1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
|
12 | |
|
13 | |
|
14 | |
package org.apache.commons.classscan.bcel; |
15 | |
|
16 | |
import java.io.IOException; |
17 | |
import java.util.Set; |
18 | |
|
19 | |
import org.apache.bcel.classfile.ClassFormatException; |
20 | |
import org.apache.bcel.classfile.ClassParser; |
21 | |
import org.apache.bcel.classfile.Field; |
22 | |
import org.apache.bcel.classfile.JavaClass; |
23 | |
import org.apache.bcel.classfile.Method; |
24 | |
import org.apache.commons.classscan.MetaClassPathElement; |
25 | |
import org.apache.commons.classscan.model.MetaAnnotation; |
26 | |
import org.apache.commons.classscan.model.MetaClass; |
27 | |
import org.apache.commons.classscan.model.MetaField; |
28 | |
import org.apache.commons.classscan.model.MetaMethod; |
29 | |
import org.apache.commons.classscan.spi.model.SpiMetaClass; |
30 | |
import org.apache.commons.classscan.spi.model.SpiMetaClassLoader; |
31 | |
import org.apache.commons.classscan.spi.model.SpiMetaField; |
32 | |
import org.apache.commons.classscan.spi.model.SpiMetaMethod; |
33 | |
import org.apache.commons.classscan.util.NameSet; |
34 | |
import org.apache.commons.classscan.util.ReadOnlySet; |
35 | |
import org.apache.commons.classscan.util.ResolveSet; |
36 | |
import org.slf4j.Logger; |
37 | |
import org.slf4j.LoggerFactory; |
38 | |
|
39 | |
public class BcelClass implements SpiMetaClass { |
40 | |
|
41 | 11 | private static final Logger logger = LoggerFactory.getLogger(BcelClass.class); |
42 | |
|
43 | |
private final MetaClassPathElement location; |
44 | |
private final String canonicalName; |
45 | |
private String parentName; |
46 | |
private MetaClass parent; |
47 | |
private String[] interfaceNames; |
48 | |
private Set<MetaClass> interfaces; |
49 | |
private final AnnotationMap annotations; |
50 | |
private final ResolveSet<SpiMetaMethod> methods; |
51 | |
private final ResolveSet<SpiMetaField> fields; |
52 | |
private Boolean resolutionResult; |
53 | |
|
54 | 227997 | public BcelClass(MetaClassPathElement location, ClassParser parser) throws ClassFormatException, IOException { |
55 | 227997 | this.location = location; |
56 | 227997 | JavaClass bcelClass = parser.parse(); |
57 | 227986 | canonicalName = bcelClass.getClassName(); |
58 | 227986 | parentName = getParentName(bcelClass); |
59 | 227986 | interfaceNames = bcelClass.getInterfaceNames(); |
60 | 227986 | annotations = AnnotationMap.createAnnotations(bcelClass.getAnnotationEntries()); |
61 | 227986 | methods = createMethods(bcelClass); |
62 | 227986 | fields = createFields(bcelClass); |
63 | 227986 | } |
64 | |
|
65 | |
@Override |
66 | |
public boolean resolve(SpiMetaClassLoader classLoader) { |
67 | 2916364 | if(resolutionResult == null) { |
68 | |
|
69 | 227986 | resolutionResult = Boolean.TRUE; |
70 | 227986 | resolutionResult= Boolean.valueOf(resolveParent(classLoader) |
71 | |
&& resolveInterfaces(classLoader) |
72 | |
&& annotations.resolve(classLoader) |
73 | |
&& methods.resolve(classLoader) |
74 | |
&& fields.resolve(classLoader)); |
75 | |
} |
76 | 2916364 | return resolutionResult; |
77 | |
} |
78 | |
|
79 | |
private boolean resolveParent(SpiMetaClassLoader classLoader) { |
80 | 227986 | boolean success = true; |
81 | 227986 | if(parentName == null) { |
82 | |
|
83 | |
|
84 | |
} |
85 | |
else { |
86 | 227975 | parent = classLoader.resolveMetaClass(parentName); |
87 | 227975 | if(parent == null) { |
88 | 154 | logger.info("Cannot find parent "+parentName+" for class "+canonicalName); |
89 | 154 | success= false; |
90 | |
} |
91 | 227975 | parentName = null; |
92 | |
} |
93 | 227986 | return success; |
94 | |
} |
95 | |
|
96 | 11 | private static final ReadOnlySet<MetaClass> EMPTY_INTERFACES = new ReadOnlySet<MetaClass>(new MetaClass[0]); |
97 | |
|
98 | |
private boolean resolveInterfaces(final SpiMetaClassLoader classLoader) { |
99 | 227832 | boolean success= true; |
100 | 227832 | if (interfaceNames==null || interfaceNames.length == 0) { |
101 | 146971 | interfaces= EMPTY_INTERFACES; |
102 | |
} |
103 | |
else { |
104 | 80861 | MetaClass[] metaClasses = new MetaClass[interfaceNames.length]; |
105 | 80861 | int i= 0; |
106 | 182215 | for(String interfaceName : interfaceNames) { |
107 | 101354 | MetaClass mc = classLoader.resolveMetaClass(interfaceName); |
108 | 101354 | if(mc == null) { |
109 | 44 | logger.info("Cannot find interface "+interfaceName+" for class "+canonicalName); |
110 | 44 | success= false; |
111 | |
} |
112 | 101354 | metaClasses[i++] = mc; |
113 | |
} |
114 | 80861 | interfaces= new ReadOnlySet<MetaClass>(metaClasses); |
115 | |
} |
116 | 227832 | interfaceNames= null; |
117 | 227832 | return success; |
118 | |
} |
119 | |
|
120 | |
@Override |
121 | |
public MetaClassPathElement getClassLocation() { |
122 | 121 | return location; |
123 | |
} |
124 | |
|
125 | |
@Override |
126 | |
public String getName() { |
127 | 21962215 | return canonicalName; |
128 | |
} |
129 | |
|
130 | |
@Override |
131 | |
public MetaClass getParent() { |
132 | 678480 | return parent; |
133 | |
} |
134 | |
|
135 | |
private String getParentName(JavaClass bcelClass) { |
136 | 227986 | String superclassName = bcelClass.getSuperclassName(); |
137 | 227986 | if (superclassName.equals(canonicalName)) { |
138 | |
|
139 | |
|
140 | 11 | return null; |
141 | |
} |
142 | 227975 | return superclassName; |
143 | |
} |
144 | |
|
145 | |
@Override |
146 | |
public Set<MetaClass> getInterfaces() { |
147 | 1024639 | return interfaces; |
148 | |
} |
149 | |
|
150 | |
@Override |
151 | |
public Set<? extends MetaAnnotation> getAnnotations() { |
152 | 11 | return annotations; |
153 | |
} |
154 | |
|
155 | |
@Override |
156 | |
public MetaAnnotation getAnnotation(String annotationName) { |
157 | 11 | return annotations.getValue(annotationName); |
158 | |
} |
159 | |
|
160 | |
@Override |
161 | |
public Set<? extends MetaMethod> getMethods() { |
162 | 11 | return methods; |
163 | |
} |
164 | |
|
165 | |
private NameSet<SpiMetaMethod> createMethods(JavaClass bcelClass) { |
166 | 227986 | Method[] methods = bcelClass.getMethods(); |
167 | 227986 | if (methods.length == 0) { |
168 | 6380 | return NameSet.emptyNameSet(); |
169 | |
} |
170 | |
|
171 | 221606 | SpiMetaMethod[] metaMethods = new SpiMetaMethod[methods.length]; |
172 | 2181982 | for(int i = 0; i<methods.length; ++i) { |
173 | 1960376 | metaMethods[i]= new BcelMethod(methods[i]); |
174 | |
} |
175 | |
|
176 | 221606 | return new NameSet<SpiMetaMethod>(metaMethods); |
177 | |
} |
178 | |
|
179 | |
@Override |
180 | |
public Set<? extends MetaField> getFields() { |
181 | 11 | return fields; |
182 | |
} |
183 | |
|
184 | |
private ResolveSet<SpiMetaField> createFields(JavaClass bcelClass) { |
185 | 227986 | Field[] fields = bcelClass.getFields(); |
186 | 227986 | if (fields.length == 0) { |
187 | 72974 | return NameSet.emptyNameSet(); |
188 | |
} |
189 | |
|
190 | 155012 | SpiMetaField[] metaFields = new SpiMetaField[fields.length]; |
191 | 1063403 | for(int i = 0; i<fields.length; ++i) { |
192 | 908391 | metaFields[i]= new BcelField(fields[i]); |
193 | |
} |
194 | |
|
195 | 155012 | return new ResolveSet<SpiMetaField>(metaFields); |
196 | |
} |
197 | |
|
198 | |
@Override |
199 | |
public boolean isAssignableFrom(MetaClass assignor) { |
200 | |
do { |
201 | 678557 | if (isAssignableFromAnyInterface(assignor)) { |
202 | 11 | return true; |
203 | |
} |
204 | 678546 | assignor = assignor.getParent(); |
205 | |
} |
206 | 678546 | while (assignor != null); |
207 | 227667 | return false; |
208 | |
} |
209 | |
|
210 | |
private boolean isAssignableFromAnyInterface(MetaClass assignor) { |
211 | 1024727 | if (equals(assignor)) { |
212 | 11 | return true; |
213 | |
} |
214 | 1024716 | for (MetaClass derived : assignor.getInterfaces()) { |
215 | 346170 | if (isAssignableFromAnyInterface(derived)) { |
216 | 11 | return true; |
217 | |
} |
218 | |
} |
219 | 1024705 | return false; |
220 | |
} |
221 | |
|
222 | |
@Override |
223 | |
public boolean equals(Object obj) { |
224 | 1275714 | if (!(obj instanceof MetaClass)) { |
225 | 22 | return false; |
226 | |
} |
227 | 1275692 | MetaClass other = (MetaClass) obj; |
228 | 1275692 | return canonicalName.equals(other.getName()) && location.equals(other.getClassLocation()); |
229 | |
} |
230 | |
|
231 | |
@Override |
232 | |
public int hashCode() { |
233 | 0 | final int prime = 33; |
234 | 0 | int result = 1; |
235 | 0 | result = prime * result + canonicalName.hashCode(); |
236 | 0 | result = prime * result + location.hashCode(); |
237 | 0 | return result; |
238 | |
} |
239 | |
} |