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.ref.SoftReference;
035: import java.lang.reflect.*;
036: import java.lang.reflect.Type;
037: import java.util.*;
038: import net.sf.retrotranslator.runtime.asm.*;
039: import net.sf.retrotranslator.runtime.asm.signature.*;
040:
041: /**
042: * @author Taras Puchko
043: */
044: public class ClassDescriptor extends GenericDeclarationDescriptor {
045:
046: private static final WeakIdentityTable<Class, String> metadataTable = new WeakIdentityTable<Class, String>();
047: private static SoftReference<Map<Class, ClassDescriptor>> cache;
048: private static BytecodeTransformer bytecodeTransformer;
049:
050: private String name;
051: private Class target;
052: private String declaringClass;
053: private String enclosingClass;
054: private String enclosingMethod;
055: private LazyList<TypeDescriptor, Type> genericInterfaces;
056: private LazyValue<TypeDescriptor, Type> genericSuperclass;
057: private Map<String, FieldDescriptor> fieldDescriptors = new HashMap<String, FieldDescriptor>();
058: private Map<String, MethodDescriptor> methodDescriptors = new HashMap<String, MethodDescriptor>();
059:
060: public ClassDescriptor(Class target, byte[] bytecode) {
061: this .target = target;
062: if (bytecode != null) {
063: if (bytecodeTransformer != null) {
064: bytecode = bytecodeTransformer.transform(bytecode, 0,
065: bytecode.length);
066: }
067: new ClassReader(bytecode).accept(this , true);
068: } else {
069: visit(0, target.getModifiers(),
070: net.sf.retrotranslator.runtime.asm.Type
071: .getInternalName(target), null, null, null);
072: }
073: }
074:
075: public static void setBytecodeTransformer(
076: BytecodeTransformer transformer) {
077: bytecodeTransformer = transformer;
078: }
079:
080: public static ClassDescriptor getInstance(Class target) {
081: Map<Class, ClassDescriptor> map = getMap();
082: ClassDescriptor descriptor = map.get(target);
083: if (descriptor != null)
084: return descriptor;
085: descriptor = new ClassDescriptor(target, getBytecode(target));
086: map.put(target, descriptor);
087: return descriptor;
088: }
089:
090: private static byte[] getBytecode(Class target) {
091: byte[] bytecode = RuntimeTools.getBytecode(target);
092: if (bytecode != null) {
093: return bytecode;
094: }
095: try {
096: Class.forName(target.getName(), true, target
097: .getClassLoader());
098: } catch (ClassNotFoundException e) {
099: // ignore
100: }
101: String s = metadataTable.lookup(target);
102: return s != null ? decode(s) : null;
103: }
104:
105: private static byte[] decode(String s) {
106: byte[] bytecode = new byte[s.length()];
107: for (int i = 0; i < bytecode.length; i++) {
108: bytecode[i] = (byte) (127 - s.charAt(i));
109: }
110: return bytecode;
111: }
112:
113: public static void setEncodedMetadata(Class aClass, String metadata) {
114: if (metadataTable != null) {
115: metadataTable.putIfAbsent(aClass, metadata);
116: }
117: }
118:
119: private static synchronized Map<Class, ClassDescriptor> getMap() {
120: Map<Class, ClassDescriptor> map = cache == null ? null : cache
121: .get();
122: if (map == null) {
123: map = new Hashtable<Class, ClassDescriptor>();
124: cache = new SoftReference<Map<Class, ClassDescriptor>>(map);
125: }
126: return map;
127: }
128:
129: protected Annotation[] createAnnotations(
130: Annotation[] declaredAnnotations) {
131: Class super class = target.getSuperclass();
132: if (super class == null)
133: return declaredAnnotations;
134: Annotation[] super Annotations = getInstance(super class)
135: .getAnnotations();
136: if (super Annotations.length == 0)
137: return declaredAnnotations;
138: Map<Class, Annotation> result = new HashMap<Class, Annotation>();
139: for (Annotation annotation : super Annotations) {
140: Class annotationClass = annotation.getClass()
141: .getInterfaces()[0];
142: if (annotationClass.isAnnotationPresent(Inherited.class)) {
143: result.put(annotationClass, annotation);
144: }
145: }
146: for (Annotation annotation : declaredAnnotations) {
147: result.put(annotation.getClass().getInterfaces()[0],
148: annotation);
149: }
150: return result.values().toArray(new Annotation[result.size()]);
151: }
152:
153: public String getName() {
154: return name;
155: }
156:
157: public String getDesc() {
158: return null;
159: }
160:
161: public ClassDescriptor getClassDescriptor() {
162: return this ;
163: }
164:
165: public String getInfo() {
166: return RuntimeTools.getDisplayClassName(name);
167: }
168:
169: public MethodDescriptor getEnclosingMethodDescriptor() {
170: return enclosingMethod == null ? null : getInstance(
171: getClassByInternalName(enclosingClass))
172: .getMethodDescriptor(enclosingMethod);
173: }
174:
175: public Class getDeclaringClass() {
176: return declaringClass == null ? null
177: : getClassByInternalName(declaringClass);
178: }
179:
180: public boolean isLocalOrAnonymous() {
181: return enclosingMethod != null;
182: }
183:
184: public FieldDescriptor getFieldDescriptor(String name) {
185: return fieldDescriptors.get(name);
186: }
187:
188: public Type[] getGenericInterfaces() {
189: return genericInterfaces == null ? null : genericInterfaces
190: .getClone();
191: }
192:
193: public Type getGenericSuperclass() {
194: return genericSuperclass == null ? null : genericSuperclass
195: .get();
196: }
197:
198: public MethodDescriptor getMethodDescriptor(String key) {
199: return methodDescriptors.get(key);
200: }
201:
202: public Collection<MethodDescriptor> getMethodDescriptors() {
203: return methodDescriptors.values();
204: }
205:
206: public Collection<FieldDescriptor> getFieldDescriptors() {
207: return fieldDescriptors.values();
208: }
209:
210: public Class getTarget() {
211: return target;
212: }
213:
214: protected TypeVariable findTypeVariable(String name) {
215: TypeVariable variable = getTypeVariable(name);
216: if (variable != null) {
217: return variable;
218: }
219: MethodDescriptor methodDescriptor = getEnclosingMethodDescriptor();
220: if (methodDescriptor != null) {
221: return methodDescriptor.findTypeVariable(name);
222: }
223: Class declaringClass = target.getDeclaringClass();
224: if (declaringClass != null) {
225: return getInstance(declaringClass).findTypeVariable(name);
226: }
227: throw new MalformedParameterizedTypeException();
228: }
229:
230: public void visit(int version, int access, String name,
231: String signature, String super Name, String[] interfaces) {
232: this .access = access;
233: this .name = name;
234: if (signature == null) {
235: signature = SignatureList.getSignature(name);
236: }
237: if (signature != null) {
238: new SignatureReader(signature).accept(this );
239: }
240: }
241:
242: public void visitOuterClass(String owner, String name, String desc) {
243: if (name != null) {
244: enclosingClass = owner;
245: enclosingMethod = name + desc;
246: }
247: }
248:
249: public void visitInnerClass(String name, String outerName,
250: String innerName, int access) {
251: if (name.equals(this .name)) {
252: this .access |= access;
253: declaringClass = outerName;
254: }
255: }
256:
257: public FieldVisitor visitField(int access, String name,
258: String desc, String signature, Object value) {
259: FieldDescriptor fieldDescriptor = new FieldDescriptor(this ,
260: access, name, desc, signature);
261: fieldDescriptors.put(name, fieldDescriptor);
262: return fieldDescriptor;
263: }
264:
265: public MethodVisitor visitMethod(int access, String name,
266: String desc, String signature, String[] exceptions) {
267: MethodDescriptor methodDescriptor = new MethodDescriptor(this ,
268: access, name, desc, signature);
269: methodDescriptors.put(name + desc, methodDescriptor);
270: return methodDescriptor;
271: }
272:
273: public SignatureVisitor visitSuperclass() {
274: TypeDescriptor descriptor = new TypeDescriptor();
275: if (!isAccess(Opcodes.ACC_INTERFACE)) {
276: genericSuperclass = getLazyType(descriptor);
277: }
278: return descriptor;
279: }
280:
281: public SignatureVisitor visitInterface() {
282: TypeDescriptor descriptor = new TypeDescriptor();
283: if (genericInterfaces == null)
284: genericInterfaces = getLazyList();
285: genericInterfaces.add(descriptor);
286: return descriptor;
287: }
288:
289: }
|