001 // Copyright 2006, 2007, 2008, 2010, 2011 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.tapestry5.ioc.services; 016 017 import java.io.File; 018 import java.lang.reflect.Method; 019 import java.net.URISyntaxException; 020 import java.net.URL; 021 import java.util.Map; 022 import java.util.concurrent.atomic.AtomicLong; 023 024 import org.apache.tapestry5.ioc.internal.util.CollectionFactory; 025 026 /** 027 * Handy method useful when creating new classes using {@link org.apache.tapestry5.ioc.services.ClassFab}. 028 * 029 * @deprecated Deprecated in Tapestry 5.3, to be removed in 5.4 with no replacement 030 */ 031 @SuppressWarnings("all") 032 public final class ClassFabUtils 033 { 034 private static final AtomicLong UID_GENERATOR = new AtomicLong(System.currentTimeMillis()); 035 036 public static String nextUID() 037 { 038 return Long.toHexString(UID_GENERATOR.getAndIncrement()); 039 } 040 041 /** 042 * Generates a unique class name, which will be in the default package. 043 */ 044 public static synchronized String generateClassName(String baseName) 045 { 046 return "$" + baseName + "_" + nextUID(); 047 } 048 049 /** 050 * Returns a class name derived from the provided interfaceClass. The package part of the interface name is stripped 051 * out, and the result passed to {@link #generateClassName(String)}. 052 */ 053 public static String generateClassName(Class interfaceClass) 054 { 055 return generateClassName(interfaceClass.getSimpleName()); 056 } 057 058 /** 059 * Javassist needs the class name to be as it appears in source code, even for arrays. Invoking getName() on a Class 060 * instance representing an array returns the internal format (i.e, "[...;" or something). This returns it as it 061 * would appear in Java code. 062 */ 063 public static String toJavaClassName(Class inputClass) 064 { 065 if (inputClass.isArray()) 066 return toJavaClassName(inputClass.getComponentType()) + "[]"; 067 068 return inputClass.getName(); 069 } 070 071 /** 072 * Returns true if the method is the standard toString() method. Very few interfaces will ever include this method 073 * as part of the interface, but we have to be sure. 074 */ 075 public static boolean isToString(Method method) 076 { 077 if (!method.getName().equals("toString")) 078 return false; 079 080 if (method.getParameterTypes().length > 0) 081 return false; 082 083 return method.getReturnType().equals(String.class); 084 } 085 086 public static Class getPrimitiveType(String primitiveTypeName) 087 { 088 return PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(primitiveTypeName).primitiveType; 089 } 090 091 private static class PrimitiveInfo 092 { 093 private final Class primitiveType; 094 095 private final String typeCode; 096 097 private final Class wrapperType; 098 099 private final String unwrapMethod; 100 101 public PrimitiveInfo(Class primitiveType, String typeCode, Class wrapperType, String unwrapMethod) 102 { 103 this.primitiveType = primitiveType; 104 this.typeCode = typeCode; 105 this.wrapperType = wrapperType; 106 this.unwrapMethod = unwrapMethod; 107 } 108 } 109 110 private static final Map<String, PrimitiveInfo> PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO = CollectionFactory.newMap(); 111 private static final Map<Class, PrimitiveInfo> WRAPPER_TYPE_TO_PRIMITIVE_INFO = CollectionFactory.newMap(); 112 113 static 114 { 115 add(boolean.class, "Z", Boolean.class, "booleanValue"); 116 add(short.class, "S", Short.class, "shortValue"); 117 add(int.class, "I", Integer.class, "intValue"); 118 add(long.class, "J", Long.class, "longValue"); 119 add(float.class, "F", Float.class, "floatValue"); 120 add(double.class, "D", Double.class, "doubleValue"); 121 add(char.class, "C", Character.class, "charValue"); 122 add(byte.class, "B", Byte.class, "byteValue"); 123 } 124 125 private static void add(Class primitiveType, String typeCode, Class wrapperType, String unwrapMethod) 126 { 127 PrimitiveInfo info = new PrimitiveInfo(primitiveType, typeCode, wrapperType, unwrapMethod); 128 129 PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.put(primitiveType.getName(), info); 130 131 WRAPPER_TYPE_TO_PRIMITIVE_INFO.put(wrapperType, info); 132 } 133 134 /** 135 * Translates types from standard Java format to Java VM format. For example, java.util.Locale remains 136 * java.util.Locale, but int[][] is translated to [[I and java.lang.Object[] to [Ljava.lang.Object; 137 */ 138 public static String toJVMBinaryName(String type) 139 { 140 // if it is not an array, just return the type itself 141 if (!type.endsWith("[]")) 142 return type; 143 144 // if it is an array, convert it to JavaVM-style format 145 StringBuilder buffer = new StringBuilder(); 146 147 while (type.endsWith("[]")) 148 { 149 buffer.append("["); 150 type = type.substring(0, type.length() - 2); 151 } 152 153 PrimitiveInfo pi = PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(type); 154 155 if (pi != null) 156 { 157 buffer.append(pi.typeCode); 158 } 159 else 160 { 161 buffer.append("L"); 162 buffer.append(type); 163 buffer.append(";"); 164 } 165 166 return buffer.toString(); 167 } 168 169 /** 170 * Given a wrapper type, determines the corresponding primitive type. 171 */ 172 public static Class getPrimitiveType(Class wrapperType) 173 { 174 return WRAPPER_TYPE_TO_PRIMITIVE_INFO.get(wrapperType).primitiveType; 175 } 176 177 /** 178 * Returns the wrapper type for an input type; for most types, this is the type. For primitive types, it is the 179 * corresponding wrapper type. 180 * 181 * @param type 182 * type to check 183 * @return type or corresponding wrapper type 184 */ 185 public static Class getWrapperType(Class type) 186 { 187 PrimitiveInfo info = PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(type.getName()); 188 189 return info == null ? type : info.wrapperType; 190 } 191 192 /** 193 * Takes a reference and casts it to the desired type. If the desired type is a primitive type, then the reference 194 * is cast to the correct wrapper type and a call to the correct unwrapper method is added. The end result is code 195 * that can be assigned to a field or parameter of the desired type (even if desired type is a primitive). 196 * 197 * @param reference 198 * to be cast 199 * @param desiredType 200 * desired object or primitive type 201 * @return Javassist code to peform the cast 202 */ 203 public static String castReference(String reference, String desiredType) 204 { 205 if (isPrimitiveType(desiredType)) 206 { 207 PrimitiveInfo info = PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(desiredType); 208 209 return String.format("((%s)%s).%s()", info.wrapperType.getName(), reference, info.unwrapMethod); 210 } 211 212 return String.format("(%s)%s", desiredType, reference); 213 } 214 215 /** 216 * Given a primitive type, finds the unwrap method of the corresponding wrapper type. 217 * 218 * @param primitiveType 219 * @return method name 220 */ 221 public static String getUnwrapMethodName(Class primitiveType) 222 { 223 return PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(primitiveType.getName()).unwrapMethod; 224 } 225 226 /** 227 * Given a type name, determines if that is the name of a primitive type. 228 */ 229 public static boolean isPrimitiveType(String typeName) 230 { 231 return PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.containsKey(typeName); 232 } 233 234 /** 235 * Converts a Class to a JVM type code (the way class information is expressed in a class file). 236 */ 237 public static String getTypeCode(Class type) 238 { 239 if (type.equals(void.class)) 240 return "V"; 241 242 if (type.isPrimitive()) 243 return PRIMITIVE_TYPE_NAME_TO_PRIMITIVE_INFO.get(type.getName()).typeCode; 244 245 if (type.isArray()) 246 return "[" + getTypeCode(type.getComponentType()); 247 248 return "L" + type.getName().replace('.', '/') + ";"; 249 } 250 251 /** 252 * Given a Class instance, convert the name into a path that can be used to locate 253 * the underlying class file on the classpath. 254 * 255 * @since 5.2.0 256 */ 257 public static String getPathForClass(Class clazz) 258 { 259 assert clazz != null; 260 261 return getPathForClassNamed(clazz.getName()); 262 } 263 264 /** 265 * Given a fully qualified class name, converts to a path on the classpath. 266 * 267 * @since 5.2.0 268 */ 269 public static String getPathForClassNamed(String className) 270 { 271 return className.replace('.', '/') + ".class"; 272 } 273 274 /** 275 * Converts a URL with protocol "file" to a File instance. 276 * 277 * @since 5.2.0 278 */ 279 public static File toFileFromFileProtocolURL(URL url) 280 { 281 assert url != null; 282 283 if (!url.getProtocol().equals("file")) 284 throw new IllegalArgumentException(String.format("URL %s does not use the 'file' protocol.", url)); 285 286 // http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html 287 288 try 289 { 290 return new File(url.toURI()); 291 } 292 catch (URISyntaxException ex) 293 { 294 return new File(url.getPath()); 295 } 296 } 297 }