View Javadoc
1   /*
2    *  Copyright 2012 Chris Pheby
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package org.jadira.scanner.classpath.types;
17  
18  import java.util.Arrays;
19  import java.util.HashSet;
20  import java.util.Set;
21  
22  import javassist.bytecode.MethodInfo;
23  import javassist.bytecode.ParameterAnnotationsAttribute;
24  import javassist.bytecode.annotation.Annotation;
25  
26  import org.apache.commons.lang3.builder.EqualsBuilder;
27  import org.apache.commons.lang3.builder.HashCodeBuilder;
28  import org.jadira.scanner.classpath.ClasspathResolver;
29  import org.jadira.scanner.classpath.visitor.IntrospectionVisitor;
30  import org.jadira.scanner.core.exception.ClasspathAccessException;
31  import org.jadira.scanner.core.helper.JavassistMethodInfoHelper;
32  
33  public class JParameter extends JVariable {
34  
35      private JOperation enclosingOperation;
36      private int index;
37  
38      protected JParameter(int index, JOperation enclosingOperation, ClasspathResolver resolver) {
39          super(JavassistMethodInfoHelper.getMethodParamNames(enclosingOperation.getMethodInfo())[index], resolver);
40          this.enclosingOperation = enclosingOperation;
41          this.index = index;
42      }
43  
44      public static JParameter getJParameter(int index, JOperation enclosingOperation, ClasspathResolver resolver) {
45          return new JParameter(index, enclosingOperation, resolver);
46      }
47  
48      public JOperation getEnclosingMethod() {
49          return enclosingOperation;
50      }
51  
52      @Override
53      public JType getEnclosingType() {
54          return enclosingOperation.getEnclosingType();
55      }
56  
57      @Override
58      public Set<JAnnotation<?>> getAnnotations() throws ClasspathAccessException {
59  
60          ParameterAnnotationsAttribute paramsVisible = (ParameterAnnotationsAttribute) enclosingOperation.getMethodInfo().getAttribute(ParameterAnnotationsAttribute.visibleTag);
61          ParameterAnnotationsAttribute paramsInvisible = (ParameterAnnotationsAttribute) enclosingOperation.getMethodInfo().getAttribute(ParameterAnnotationsAttribute.invisibleTag);
62  
63          final Set<JAnnotation<?>> retVal = new HashSet<JAnnotation<?>>();
64          if (paramsVisible != null && paramsVisible.getAnnotations() != null) {
65              for (Annotation anns : paramsVisible.getAnnotations()[index]) {
66                  retVal.add(JAnnotation.getJAnnotation(anns, this, getResolver()));
67              }
68          }
69          if (paramsInvisible != null && paramsInvisible.getAnnotations() != null) {
70              for (Annotation anns : paramsInvisible.getAnnotations()[index]) {
71                  retVal.add(JAnnotation.getJAnnotation(anns, this, getResolver()));
72              }
73          }
74  
75          return retVal;
76      }
77  
78      @Override
79      public JType getType() throws ClasspathAccessException {
80  
81          Class<?> clazz;
82          if (enclosingOperation instanceof JConstructor || enclosingOperation instanceof JMethod) {
83              MethodInfo methodInfo = ((JOperation) enclosingOperation).getMethodInfo();
84              String[] paramTypeNames = JavassistMethodInfoHelper.getMethodParamTypeNames(methodInfo);
85              clazz = decodeFieldType(paramTypeNames[getIndex()]);
86  
87          } else {
88              throw new ClasspathAccessException("Invalid parameter index: " + index);
89          }
90  
91          if (clazz.isAnnotation()) {
92              try {
93                  return new JAnnotation<java.lang.annotation.Annotation>((java.lang.annotation.Annotation) clazz.newInstance(), this, getResolver());
94              } catch (InstantiationException e) {
95                  throw new ClasspathAccessException("Problem instantiating annotation: " + e.getMessage(), e);
96              } catch (IllegalAccessException e) {
97                  throw new ClasspathAccessException("Problem accessing annotation: " + e.getMessage(), e);
98              }
99          } else if (clazz.isInterface()) {
100             return new JInterface(clazz.getName(), getResolver());
101         } else {
102             JClass jClass = new JClass(clazz.getName(), getResolver());
103             return jClass;
104         }
105     }
106 
107     public int getIndex() {
108         return index;
109     }
110 
111     @Override
112     public void acceptVisitor(IntrospectionVisitor visitor) throws ClasspathAccessException {
113         visitor.visit(this);
114 
115         for (JAnnotation<?> next : getAnnotations()) {
116             next.acceptVisitor(visitor);
117         }
118     }
119 
120     @Override
121     public JOperation getEnclosingElement() {
122         return enclosingOperation;
123     }
124 
125     @Override
126 	public boolean equals(Object obj) {
127 		if (obj == null) {
128 			return false;
129 		}
130 		if (obj == this) {
131 			return true;
132 		}
133 		if (obj.getClass() != getClass()) {
134 			return false;
135 		}
136 		JParameter rhs = (JParameter) obj;
137 		return new EqualsBuilder()
138 			 	.appendSuper(super.equals(obj))
139 				.append(enclosingOperation, rhs.enclosingOperation).isEquals();
140 	}
141 
142     @Override
143 	public int hashCode() {
144 		return new HashCodeBuilder(11, 47).append(super.hashCode())
145 				.append(enclosingOperation).toHashCode();
146 	}
147     
148 
149     private Class<?> decodeFieldType(String componentType) {
150 
151         char type = componentType.charAt(0);
152         String fieldContent = componentType.substring(1);
153 
154         switch (type) {
155         // L<classname>; reference an instance of class <classname>
156         case 'L': 
157             return getResolver().loadClass(fieldContent.replace('/', '.'));
158         // B byte signed byte
159         case 'B': 
160             return Byte.class;
161         // C char Unicode character
162         case 'C': 
163             return Character.class;
164         // D double double-precision floating-point value
165         case 'D': 
166             return Double.class;
167         // F float single-precision floating-point value        
168         case 'F': 
169             return Float.class;
170         // I int integer
171         case 'I': 
172             return Integer.class;
173         // J long long integer
174         case 'J': 
175             return Long.class;
176         // S short signed short
177         case 'S': 
178             return Short.class;
179         // Z boolean true or false
180         case 'Z': 
181             return Boolean.class;
182         // [ reference one array dimension
183         case '[': 
184             return Arrays.class;
185         }
186         return null;
187     }
188 }