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 }