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 }