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 }