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.lang.reflect.Field;
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.HashSet;
22  import java.util.List;
23  import java.util.Set;
24  
25  import javassist.bytecode.AnnotationsAttribute;
26  import javassist.bytecode.FieldInfo;
27  import javassist.bytecode.annotation.Annotation;
28  
29  import org.apache.commons.lang3.builder.EqualsBuilder;
30  import org.apache.commons.lang3.builder.HashCodeBuilder;
31  import org.jadira.scanner.classpath.ClasspathResolver;
32  import org.jadira.scanner.classpath.visitor.IntrospectionVisitor;
33  import org.jadira.scanner.core.exception.ClasspathAccessException;
34  
35  public class JField extends JVariable {
36  
37      private FieldInfo fieldInfo;
38      private JClass jClass;
39  
40      protected JField(FieldInfo fieldInfo, JClass jClass, ClasspathResolver resolver) {
41          super(fieldInfo.getName(), resolver);
42          this.fieldInfo = fieldInfo;
43          this.jClass = jClass;
44      }
45  
46      public static JField getJField(FieldInfo fieldInfo, JClass jClass, ClasspathResolver resolver) {
47          return new JField(fieldInfo, jClass, resolver);
48      }
49  
50      @Override
51      public JType getEnclosingType() {
52          return jClass;
53      }
54  
55      @Override
56      public JType getType() throws ClasspathAccessException {
57  
58          final JType retVal;
59  
60          Class<?> clazz;
61          try {
62              Field field = getActualField();
63              clazz = field.getType();            
64          } catch (SecurityException e) {
65              throw new ClasspathAccessException("Problem finding enclosing type: " + e.getMessage(), e);
66          }
67          if (clazz.isInterface()) {
68              retVal = JInterface.getJInterface(clazz.getName(), getResolver());
69          } else if (clazz.isPrimitive()) {
70          	retVal = JPrimitiveClass.getJClass(clazz.getName(), getResolver());
71          } else if (clazz.isArray()) {
72          	retVal = JArrayClass.getJClass(clazz, getResolver());
73          } else {
74              retVal = JClass.getJClass(clazz.getName(), getResolver());
75          }
76          return retVal;
77      }
78      
79  	public Class<?> decodeFieldType(String componentType) throws ClassNotFoundException {
80  
81  		char type = componentType.charAt(0);
82  		String fieldContent = componentType.substring(1);
83  
84  		switch (type) {
85  		// L<classname>; reference an instance of class <classname>		
86  		case 'L': 
87  			return getResolver().loadClass(fieldContent.replace('/', '.'));
88  		// B byte signed byte
89  		case 'B': 
90  			return Byte.class;
91  		// C char Unicode character
92  		case 'C': 
93  			return Character.class;
94  		// D double double-precision floating-point value
95  		case 'D': 
96  			return Double.class;
97  		// F float single-precision floating-point value
98  		case 'F': 
99  			return Float.class;
100 		// I int integer
101 		case 'I': 
102 			return Integer.class;
103 		// J long long integer
104 		case 'J': 
105 			return Long.class;
106 		// S short signed short
107 		case 'S': 
108 			return Short.class;
109 		// Z boolean true or false
110 		case 'Z': 
111 			return Boolean.class;
112 		// [ reference one array dimension
113 		case '[': 
114 		    return getResolver().loadClass(componentType.replace('/', '.') + ";");
115 		}
116 		return null;
117 	}
118 
119     @Override
120     public Set<JAnnotation<?>> getAnnotations() {
121 
122         AnnotationsAttribute visible = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.visibleTag);
123         AnnotationsAttribute invisible = (AnnotationsAttribute) fieldInfo.getAttribute(AnnotationsAttribute.invisibleTag);
124 
125         Set<JAnnotation<?>> annotations = new HashSet<JAnnotation<?>>();
126 
127         List<Annotation> annotationsList = new ArrayList<Annotation>();
128         if (visible != null) {
129             annotationsList.addAll(Arrays.asList(visible.getAnnotations()));
130         }
131         if (invisible != null) {
132             annotationsList.addAll(Arrays.asList(invisible.getAnnotations()));
133         }
134 
135         for (Annotation nextAnnotation : annotationsList) {
136             annotations.add(JAnnotation.getJAnnotation(nextAnnotation, this, getResolver()));
137         }
138 
139         return annotations;
140     }
141 
142     @Override
143     public void acceptVisitor(IntrospectionVisitor visitor) {
144         visitor.visit(this);
145 
146         for (JAnnotation<?> next : getAnnotations()) {
147             next.acceptVisitor(visitor);
148         }
149     }
150 
151     public Field getActualField() {
152 
153         try {
154             return getEnclosingType().getActualClass().getDeclaredField(getName());
155         } catch (SecurityException e) {
156             throw new ClasspathAccessException("Problem obtaining field: " + e.getMessage(), e);
157         } catch (NoSuchFieldException e) {
158             throw new ClasspathAccessException("Problem finding field: " + this.toString(), e);
159         }
160     }
161 
162     public FieldInfo getFieldInfo() {
163         return fieldInfo;
164     }
165 
166     @Override
167     public JClass getEnclosingElement() {
168         return jClass;
169     }
170     
171     @Override
172 	public boolean equals(Object obj) {
173 		if (obj == null) {
174 			return false;
175 		}
176 		if (obj == this) {
177 			return true;
178 		}
179 		if (obj.getClass() != getClass()) {
180 			return false;
181 		}
182 		JField rhs = (JField) obj;
183 		return new EqualsBuilder()
184 			 	.appendSuper(super.equals(obj))
185 				.append(jClass, rhs.jClass).isEquals();
186 	}
187 
188     @Override
189 	public int hashCode() {
190 		return new HashCodeBuilder(11, 47).append(super.hashCode())
191 				.append(jClass.getName()).toHashCode();
192 	}
193 }