001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.runtime.impl;
032:
033: import java.lang.annotation.*;
034: import java.lang.reflect.*;
035: import java.util.*;
036: import net.sf.retrotranslator.runtime.asm.*;
037: import net.sf.retrotranslator.runtime.asm.Type;
038:
039: /**
040: * @author Taras Puchko
041: */
042: public abstract class AnnotatedElementDescriptor extends EmptyVisitor {
043:
044: private static final Annotation[] EMPTY = new Annotation[0];
045: protected static final EmptyVisitor EMPTY_VISITOR = new EmptyVisitor();
046:
047: protected int access;
048:
049: private LazyList<AnnotationValue, Annotation> declaredAnnotations = new LazyList<AnnotationValue, Annotation>() {
050: protected Annotation resolve(AnnotationValue input) {
051: return createAnnotation(input);
052: }
053:
054: protected Annotation[] newArray(int size) {
055: return new Annotation[size];
056: }
057: };
058:
059: private LazyValue<LazyList<AnnotationValue, Annotation>, Annotation[]> annotations = new LazyValue<LazyList<AnnotationValue, Annotation>, Annotation[]>(
060: declaredAnnotations) {
061: protected Annotation[] resolve(
062: LazyList<AnnotationValue, Annotation> input) {
063: return createAnnotations(input.getLive());
064: }
065: };
066:
067: public boolean isAccess(int mask) {
068: return (access & mask) != 0;
069: }
070:
071: public boolean isAnnotationPresent(Class annotationType) {
072: for (Annotation annotation : annotations.get()) {
073: if (annotationType.isInstance(annotation))
074: return true;
075: }
076: return false;
077: }
078:
079: public Annotation getAnnotation(Class annotationType) {
080: for (Annotation annotation : annotations.get()) {
081: if (annotationType.isInstance(annotation))
082: return annotation;
083: }
084: return null;
085: }
086:
087: public Annotation[] getAnnotations() {
088: Annotation[] result = annotations.get();
089: return result.length == 0 ? result : result.clone();
090: }
091:
092: public Annotation[] getDeclaredAnnotations() {
093: return declaredAnnotations.getClone();
094: }
095:
096: public abstract String getName();
097:
098: public abstract String getDesc();
099:
100: public abstract ClassDescriptor getClassDescriptor();
101:
102: public abstract String getInfo();
103:
104: protected abstract TypeVariable findTypeVariable(String name);
105:
106: protected abstract Annotation[] createAnnotations(
107: Annotation[] declaredAnnotations);
108:
109: protected Annotation[] createAnnotations(
110: List<AnnotationValue> values) {
111: if (values == null)
112: return EMPTY;
113: Annotation[] result = new Annotation[values.size()];
114: for (int i = 0; i < result.length; i++) {
115: result[i] = createAnnotation(values.get(i));
116: }
117: return result;
118: }
119:
120: public AnnotationVisitor visitAnnotation(String desc,
121: boolean visible) {
122: if (!visible)
123: return EMPTY_VISITOR;
124: AnnotationValue value = new AnnotationValue(desc);
125: declaredAnnotations.add(value);
126: return value;
127: }
128:
129: private ClassLoader getClassLoader() {
130: return getClassDescriptor().getTarget().getClassLoader();
131: }
132:
133: protected Class getClassByInternalName(String name) {
134: name = RuntimeTools.getDisplayClassName(name);
135: try {
136: return Class.forName(name, false, getClassLoader());
137: } catch (ClassNotFoundException e) {
138: throw new TypeNotPresentException(name, e);
139: }
140: }
141:
142: protected Class getClassByType(
143: net.sf.retrotranslator.runtime.asm.Type type) {
144: Class baseClass = RuntimeTools.getBaseClass(type);
145: if (baseClass != null)
146: return baseClass;
147: return getClassByInternalName(type.getSort() == Type.ARRAY ? type
148: .getDescriptor()
149: : type.getInternalName());
150: }
151:
152: private Class getClassByDesc(String desc) {
153: return getClassByType(net.sf.retrotranslator.runtime.asm.Type
154: .getType(desc));
155: }
156:
157: public java.lang.reflect.Type[] createTypes(
158: List<TypeDescriptor> descriptors) {
159: if (descriptors == null)
160: return null;
161: java.lang.reflect.Type[] result = new java.lang.reflect.Type[descriptors
162: .size()];
163: Iterator<TypeDescriptor> iterator = descriptors.iterator();
164: for (int i = 0; i < result.length; i++) {
165: result[i] = createType(iterator.next());
166: }
167: return result;
168: }
169:
170: public java.lang.reflect.Type createType(TypeDescriptor descriptor) {
171: if (descriptor == null)
172: return null;
173: if (descriptor.arrayType != null) {
174: return new GenericArrayTypeImpl(
175: createType(descriptor.arrayType));
176: }
177: if (descriptor.typeVariable != null) {
178: return findTypeVariable(descriptor.typeVariable);
179: }
180: LinkedList<ClassTypeElement> elements = descriptor.elements;
181: if (elements != null) {
182: return createClassType(elements
183: .toArray(new ClassTypeElement[elements.size()]));
184: }
185: return RuntimeTools.getBaseClass(descriptor.baseType);
186: }
187:
188: private java.lang.reflect.Type createClassType(
189: ClassTypeElement[] typeElements) {
190: class Element {
191: Class rawType;
192: List<TypeArgument> arguments;
193:
194: public Element(Class rawType, List<TypeArgument> arguments) {
195: this .rawType = rawType;
196: this .arguments = arguments;
197: }
198: }
199: String className = null;
200: for (ClassTypeElement typeElement : typeElements) {
201: className = (className == null ? "" : className + "$")
202: + typeElement.getName();
203: }
204: LinkedList<Element> elements = new LinkedList<Element>();
205: Class currentClass = getClassByInternalName(className);
206: for (int i = typeElements.length - 1; i >= 0; i--) {
207: elements.addFirst(new Element(currentClass, typeElements[i]
208: .getArguments()));
209: currentClass = currentClass.getDeclaringClass();
210: if (currentClass == null)
211: break;
212: }
213: java.lang.reflect.Type result = elements.getFirst().arguments
214: .isEmpty() ? null : currentClass;
215: for (Element element : elements) {
216: result = (result == null && element.arguments.isEmpty()) ? element.rawType
217: : new ParameterizedTypeImpl(
218: createArguments(element.arguments),
219: element.rawType, result);
220: }
221: return result;
222: }
223:
224: private java.lang.reflect.Type[] createArguments(
225: List<TypeArgument> arguments) {
226: java.lang.reflect.Type[] result = new java.lang.reflect.Type[arguments
227: .size()];
228: Iterator<TypeArgument> iterator = arguments.iterator();
229: for (int i = 0; i < result.length; i++) {
230: TypeArgument argument = iterator.next();
231: result[i] = argument.wildcard == INSTANCEOF ? createType(argument.descriptor)
232: : new WildcardTypeImpl(
233: argument.wildcard == EXTENDS,
234: getLazyType(argument.descriptor));
235: }
236: return result;
237: }
238:
239: private Annotation createAnnotation(AnnotationValue annotationValue) {
240: Class annotationType = getClassByDesc(annotationValue.getDesc());
241: StringBuffer buffer = new StringBuffer("@").append(
242: annotationType.getName()).append('(');
243: Map<String, Object> values = new HashMap<String, Object>();
244: boolean isFirst = true;
245: for (MethodDescriptor descriptor : ClassDescriptor.getInstance(
246: annotationType).getMethodDescriptors()) {
247: if (isFirst) {
248: isFirst = false;
249: } else {
250: buffer.append(", ");
251: }
252: String elementName = descriptor.getName();
253: Object elementValue = annotationValue
254: .getElement(elementName);
255: Object resolvedValue = elementValue == null ? descriptor
256: .getDefaultValue() : resolveValue(elementValue,
257: descriptor.getReturnType(), descriptor);
258: if (resolvedValue == null)
259: throw new IncompleteAnnotationException(annotationType,
260: elementName);
261: values.put(elementName, resolvedValue);
262: buffer.append(elementName).append('=');
263: append(buffer, resolvedValue);
264: }
265: buffer.append(")");
266: ClassLoader classLoader;
267: Class[] interfaces;
268: if (Annotation.class.isAssignableFrom(annotationType)) {
269: classLoader = getClassLoader();
270: interfaces = new Class[] { annotationType };
271: } else {
272: classLoader = getProxyClassLoader(annotationType);
273: interfaces = new Class[] { annotationType, Annotation.class };
274: }
275: return (Annotation) Proxy.newProxyInstance(classLoader,
276: interfaces, new AnnotationHandler(annotationType,
277: buffer.toString(), values));
278: }
279:
280: private ClassLoader getProxyClassLoader(Class annotationType) {
281: try {
282: if (Annotation.class == Class.forName(Annotation.class
283: .getName(), false, getClassLoader())) {
284: return getClassLoader();
285: }
286: } catch (ClassNotFoundException e) {
287: // ignore
288: }
289: try {
290: if (annotationType == Class.forName(annotationType
291: .getName(), false, Annotation.class
292: .getClassLoader())) {
293: return Annotation.class.getClassLoader();
294: }
295: } catch (ClassNotFoundException e) {
296: // ignore
297: }
298: return getClassLoader();
299: }
300:
301: protected Object resolveValue(Object value, Class type,
302: MethodDescriptor descriptor) {
303: if (value == null)
304: return null;
305: if (value instanceof net.sf.retrotranslator.runtime.asm.Type) {
306: value = getClassByType((net.sf.retrotranslator.runtime.asm.Type) value);
307: } else if (value instanceof EnumValue) {
308: EnumValue enumValue = (EnumValue) value;
309: value = getEnumValue(getClassByDesc(enumValue
310: .getDescriptor()), enumValue.getValue());
311: } else if (value instanceof AnnotationValue) {
312: value = createAnnotation((AnnotationValue) value);
313: } else if (value instanceof AnnotationArray) {
314: AnnotationArray array = (AnnotationArray) value;
315: Class componentType = type.getComponentType();
316: List<Object> values = array.getValues();
317: value = Array.newInstance(componentType, values.size());
318: for (int i = Array.getLength(value) - 1; i >= 0; i--) {
319: Array.set(value, i, resolveValue(values.get(i),
320: componentType, descriptor));
321: }
322: }
323: if (!type.isPrimitive() && !type.isInstance(value)) {
324: throw new AnnotationTypeMismatchException(descriptor
325: .getMethod(), type.getName());
326: }
327: return value;
328: }
329:
330: private Object getEnumValue(Class enumType, String name) {
331: try {
332: return Enum.valueOf(enumType, name);
333: } catch (IllegalArgumentException e) {
334: try {
335: return enumType.getMethod("valueOf", String.class)
336: .invoke(null, name);
337: } catch (Exception ex) {
338: throw e;
339: }
340: }
341: }
342:
343: private static void append(StringBuffer buffer, Object value) {
344: if (value.getClass().isArray()) {
345: buffer.append('[');
346: int length = Array.getLength(value);
347: for (int i = 0; i < length; i++) {
348: if (i > 0)
349: buffer.append(", ");
350: append(buffer, Array.get(value, i));
351: }
352: buffer.append(']');
353: } else {
354: buffer.append(value);
355: }
356: }
357:
358: protected LazyValue<TypeDescriptor, java.lang.reflect.Type> getLazyType(
359: TypeDescriptor descriptor) {
360: if (descriptor == null)
361: return null;
362: return new LazyValue<TypeDescriptor, java.lang.reflect.Type>(
363: descriptor) {
364: protected java.lang.reflect.Type resolve(
365: TypeDescriptor input) {
366: return createType(input);
367: }
368: };
369: }
370:
371: protected LazyList<TypeDescriptor, java.lang.reflect.Type> getLazyList() {
372: return new LazyList<TypeDescriptor, java.lang.reflect.Type>() {
373:
374: protected java.lang.reflect.Type resolve(
375: TypeDescriptor descriptor) {
376: return createType(descriptor);
377: }
378:
379: protected java.lang.reflect.Type[] newArray(int size) {
380: return new java.lang.reflect.Type[size];
381: }
382: };
383: }
384:
385: }
|