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 is, in fact, a JDK proxy, returns
111 * the interfaceClass (because JDK proxies do not work with Javassist).
112 *
113 * @param instance
114 * the object instance to obtain a class from
115 * @param interfaceClass
116 * the interface class to return if the instance is a JDK proxy.
117 */
118 public static Class getInstanceClass(Object instance, Class interfaceClass)
119 {
120 Class instanceClass = instance.getClass();
121
122 if (Proxy.isProxyClass(instanceClass))
123 return interfaceClass;
124
125 return instanceClass;
126 }
127
128 /**
129 * Adds a method that does nothing. If the method returns a value, it will return null, 0 or
130 * false (depending on the type).
131 *
132 * @since 1.1
133 */
134
135 public static void addNoOpMethod(ClassFab cf, MethodSignature m)
136 {
137 StringBuffer body = new StringBuffer("{ ");
138
139 Class returnType = m.getReturnType();
140
141 if (returnType != void.class)
142 {
143 body.append("return");
144
145 if (returnType.isPrimitive())
146 {
147 if (returnType == boolean.class)
148 body.append(" false");
149 else if (returnType == long.class)
150 body.append(" 0L");
151 else if (returnType == float.class)
152 body.append(" 0.0f");
153 else if (returnType == double.class)
154 body.append(" 0.0d");
155 else
156 body.append(" 0");
157 }
158 else
159 {
160 body.append(" null");
161 }
162
163 body.append(";");
164 }
165
166 body.append(" }");
167
168 cf.addMethod(Modifier.PUBLIC, m, body.toString());
169 }
170 }