001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 015 package org.apache.hivemind.service; 016 017 import java.lang.reflect.Method; 018 import java.lang.reflect.Modifier; 019 import java.lang.reflect.Proxy; 020 021 /** 022 * Static class containing utility methods. 023 * 024 * @author Howard Lewis Ship 025 */ 026 public class ClassFabUtils 027 { 028 private static long _uid = System.currentTimeMillis(); 029 030 private static final char QUOTE = '"'; 031 032 private ClassFabUtils() 033 { 034 } 035 036 /** 037 * Generates a unique class name, which will be in the default package. 038 */ 039 040 public static synchronized String generateClassName(String baseName) 041 { 042 return "$" + baseName + "_" + Long.toHexString(_uid++); 043 } 044 045 /** 046 * Returns a class name derived from the provided interfaceClass. The package part of the 047 * interface name is stripped out, and the result passed to {@link #generateClassName(String)}. 048 * 049 * @since 1.1 050 */ 051 052 public static synchronized String generateClassName(Class interfaceClass) 053 { 054 String name = interfaceClass.getName(); 055 056 int dotx = name.lastIndexOf('.'); 057 058 return generateClassName(name.substring(dotx + 1)); 059 } 060 061 /** 062 * Javassist needs the class name to be as it appears in source code, even for arrays. Invoking 063 * getName() on a Class instance representing an array returns the internal format (i.e, "[...;" 064 * or something). This returns it as it would appear in Java code. 065 */ 066 public static String getJavaClassName(Class inputClass) 067 { 068 if (inputClass.isArray()) 069 return getJavaClassName(inputClass.getComponentType()) + "[]"; 070 071 return inputClass.getName(); 072 } 073 074 /** 075 * Returns true if the method is the standard toString() method. Very few interfaces will ever 076 * include this method as part of the interface, but we have to be sure. 077 */ 078 public static boolean isToString(Method method) 079 { 080 if (!method.getName().equals("toString")) 081 return false; 082 083 if (method.getParameterTypes().length > 0) 084 return false; 085 086 return method.getReturnType().equals(String.class); 087 } 088 089 /** 090 * Adds a <code>toString()</code> method to a class that returns a fixed, pre-computed value. 091 * 092 * @param classFab 093 * ClassFab used to construct the new class. 094 * @param toStringResult 095 * fixed result to be returned by the method. 096 */ 097 public static void addToStringMethod(ClassFab classFab, String toStringResult) 098 { 099 StringBuffer buffer = new StringBuffer("return "); 100 buffer.append(QUOTE); 101 buffer.append(toStringResult); 102 buffer.append(QUOTE); 103 buffer.append(";"); 104 105 classFab.addMethod(Modifier.PUBLIC, new MethodSignature(String.class, "toString", null, 106 null), buffer.toString()); 107 } 108 109 /** 110 * Returns the class of an instance. However, if the instance's class 111 * isn't compatible (externally generated, for instance), then 112 * <code>interfaceClass</code> is returned instead. 113 * 114 * @param instance 115 * the object instance to obtain a class from 116 * @param interfaceClass 117 * the interface class to return if the instance is not compatible 118 */ 119 public static Class getInstanceClass(ClassFab classFab, Object instance, Class interfaceClass) 120 { 121 Class instanceClass = instance.getClass(); 122 123 if (!classFab.canConvert(instanceClass)) 124 return interfaceClass; 125 126 return instanceClass; 127 } 128 129 /** 130 * Returns the class of an instance. However, if the instance is, in fact, a JDK proxy, returns 131 * the interfaceClass (because JDK proxies do not work with Javassist). 132 * 133 * @param instance 134 * the object instance to obtain a class from 135 * @param interfaceClass 136 * the interface class to return if the instance is a JDK proxy. 137 * @deprecated Please use version which takes a ClassFab object. 138 */ 139 public static Class getInstanceClass(Object instance, Class interfaceClass) 140 { 141 Class instanceClass = instance.getClass(); 142 143 if (Proxy.isProxyClass(instanceClass)) 144 return interfaceClass; 145 146 return instanceClass; 147 } 148 149 /** 150 * Adds a method that does nothing. If the method returns a value, it will return null, 0 or 151 * false (depending on the type). 152 * 153 * @since 1.1 154 */ 155 156 public static void addNoOpMethod(ClassFab cf, MethodSignature m) 157 { 158 StringBuffer body = new StringBuffer("{ "); 159 160 Class returnType = m.getReturnType(); 161 162 if (returnType != void.class) 163 { 164 body.append("return"); 165 166 if (returnType.isPrimitive()) 167 { 168 if (returnType == boolean.class) 169 body.append(" false"); 170 else if (returnType == long.class) 171 body.append(" 0L"); 172 else if (returnType == float.class) 173 body.append(" 0.0f"); 174 else if (returnType == double.class) 175 body.append(" 0.0d"); 176 else 177 body.append(" 0"); 178 } 179 else 180 { 181 body.append(" null"); 182 } 183 184 body.append(";"); 185 } 186 187 body.append(" }"); 188 189 cf.addMethod(Modifier.PUBLIC, m, body.toString()); 190 } 191 }