View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.reflect.impl.asm;
9   
10  import org.codehaus.aspectwerkz.reflect.ClassInfo;
11  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
12  import org.codehaus.aspectwerkz.reflect.MethodInfo;
13  import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
14  import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotationHelper;
15  import org.codehaus.aspectwerkz.proxy.ProxyCompiler;
16  import org.objectweb.asm.Type;
17  import org.objectweb.asm.ClassReader;
18  import org.objectweb.asm.attrs.Attributes;
19  
20  import java.util.List;
21  import java.util.ArrayList;
22  import java.io.IOException;
23  import java.io.InputStream;
24  
25  /***
26   * ASM implementation of the ConstructorInfo interface.
27   *
28   * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
29   */
30  public class AsmConstructorInfo extends AsmMemberInfo implements ConstructorInfo {
31  
32      /***
33       * A list with the parameter type names.
34       */
35      private String[] m_parameterTypeNames = null;
36  
37      /***
38       * A list with the exception type names.
39       */
40      private String[] m_exceptionTypeNames = null;
41  
42      /***
43       * A list with the parameter types.
44       */
45      private ClassInfo[] m_parameterTypes = null;
46  
47      /***
48       * A list with the exception types.
49       */
50      private ClassInfo[] m_exceptionTypes = null;
51  
52      /***
53       * Creates a new method meta data instance.
54       *
55       * @param method
56       * @param declaringType
57       * @param loader
58       */
59      AsmConstructorInfo(final MethodStruct method, final String declaringType, final ClassLoader loader) {
60          super(method, declaringType, loader);
61          Type[] argTypes = Type.getArgumentTypes(method.desc);
62          m_parameterTypeNames = new String[argTypes.length];
63          for (int i = 0; i < argTypes.length; i++) {
64              m_parameterTypeNames[i] = argTypes[i].getClassName();
65          }
66          // FIXME: how to do exceptions?
67          m_exceptionTypeNames = new String[]{};
68      }
69  
70      /***
71       * Returns the constructor info for the constructor specified.
72       *
73       * @param constructorDesc
74       * @param bytecode
75       * @param loader
76       * @return the constructor info
77       */
78      public static ConstructorInfo getConstructorInfo(final String constructorDesc,
79                                                       final byte[] bytecode,
80                                                       final ClassLoader loader) {
81          String className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode);
82          AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
83          ClassInfo classInfo = repository.getClassInfo(className);
84          if (classInfo == null) {
85              classInfo = AsmClassInfo.getClassInfo(bytecode, loader);
86          }
87          return classInfo.getConstructor(AsmHelper.calculateConstructorHash(constructorDesc));
88      }
89  
90      /***
91       * Returns the signature for the element.
92       *
93       * @return the signature for the element
94       */
95      public String getSignature() {
96          return AsmHelper.getConstructorDescriptor(this);
97      }
98  
99      /***
100      * Returns the parameter types.
101      *
102      * @return the parameter types
103      */
104     public ClassInfo[] getParameterTypes() {
105         if (m_parameterTypes == null) {
106             m_parameterTypes = new ClassInfo[m_parameterTypeNames.length];
107             for (int i = 0; i < m_parameterTypeNames.length; i++) {
108                 m_parameterTypes[i] = AsmClassInfo.getClassInfo(
109                         m_parameterTypeNames[i],
110                         (ClassLoader) m_loaderRef.get()
111                 );
112             }
113         }
114         return m_parameterTypes;
115     }
116 
117     /***
118      * Returns the exception types.
119      *
120      * @return the exception types
121      */
122     public ClassInfo[] getExceptionTypes() {
123         if (m_exceptionTypes == null) {
124             m_exceptionTypes = new ClassInfo[m_exceptionTypeNames.length];
125             for (int i = 0; i < m_exceptionTypeNames.length; i++) {
126                 m_exceptionTypes[i] = AsmClassInfo.getClassInfo(
127                         m_exceptionTypeNames[i],
128                         (ClassLoader) m_loaderRef.get()
129                 );
130             }
131         }
132         return m_exceptionTypes;
133     }
134 
135     /***
136      * Returns the annotations.
137      *
138      * @return the annotations
139      */
140     public List getAnnotations() {
141         if (m_annotations == null) {
142             try {
143                 InputStream in = null;
144                 ClassReader cr = null;
145                 try {
146                     if ((ClassLoader) m_loaderRef.get() != null) {
147                         in = ((ClassLoader) m_loaderRef.get()).getResourceAsStream(
148                                 m_declaringTypeName.replace('.', '/') + ".class"
149                         );
150                     } else {
151                         in = ClassLoader.getSystemClassLoader().getResourceAsStream(
152                                 m_declaringTypeName.replace('.', '/') + ".class"
153                         );
154                     }
155                     if (in == null) {
156                         in = ProxyCompiler.getProxyResourceAsStream((ClassLoader) m_loaderRef.get(), m_declaringTypeName);
157                     }
158                     cr = new ClassReader(in);
159                 } finally {
160                     try {
161                         in.close();
162                     } catch (Exception e) {
163                         ;
164                     }
165                 }
166                 List annotations = new ArrayList();
167                 cr.accept(
168                         new AsmAnnotationHelper.ConstructorAnnotationExtractor(
169                                 annotations, m_member.desc, (ClassLoader) m_loaderRef.get()
170                         ),
171                         Attributes.getDefaultAttributes(),
172                         true
173                 );
174                 m_annotations = annotations;
175             } catch (IOException e) {
176                 // unlikely to occur since ClassInfo relies on getResourceAsStream
177                 System.err.println(
178                         "WARN - could not load " + m_declaringTypeName + " as a resource to retrieve annotations"
179                 );
180                 m_annotations = AsmClassInfo.EMPTY_LIST;
181             }
182         }
183         return m_annotations;
184     }
185 
186     public boolean equals(Object o) {
187         if (this == o) {
188             return true;
189         }
190         if (!(o instanceof ConstructorInfo)) {
191             return false;
192         }
193         ConstructorInfo constructorInfo = (ConstructorInfo) o;
194         if (!m_declaringTypeName.equals(constructorInfo.getDeclaringType().getName())) {
195             return false;
196         }
197         if (!m_member.name.equals(constructorInfo.getName())) {
198             return false;
199         }
200         ClassInfo[] parameterTypes = constructorInfo.getParameterTypes();
201         if (m_parameterTypeNames.length != parameterTypes.length) {//check on names length for lazyness optim
202             return false;
203         }
204         for (int i = 0; i < m_parameterTypeNames.length; i++) {
205             if (!m_parameterTypeNames[i].equals(parameterTypes[i].getName())) {
206                 return false;
207             }
208         }
209         return true;
210     }
211 
212     public int hashCode() {
213         int result = 29;
214         result = (29 * result) + m_declaringTypeName.hashCode();
215         result = (29 * result) + m_member.name.hashCode();
216         for (int i = 0; i < m_parameterTypeNames.length; i++) {
217             result = (29 * result) + m_parameterTypeNames[i].hashCode();
218         }
219         return result;
220     }
221 
222     public String toString() {
223         StringBuffer sb = new StringBuffer(m_declaringTypeName);
224         sb.append('.').append(m_member.name);
225         sb.append(m_member.desc);
226         return sb.toString();
227     }
228 }