Coverage Report - org.apache.commons.classscan.bcel.BcelClass
 
Classes in this File Line Coverage Branch Coverage Complexity
BcelClass
94%
79/84
94%
47/50
2.579
 
 1  
 /*
 2  
  * Licensed under the Apache License, Version 2.0 (the "License");
 3  
  * you may not use this file except in compliance with the License.
 4  
  * You may obtain a copy of the License at
 5  
  *
 6  
  *      http://www.apache.org/licenses/LICENSE-2.0
 7  
  *
 8  
  * Unless required by applicable law or agreed to in writing, software
 9  
  * distributed under the License is distributed on an "AS IS" BASIS,
 10  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11  
  * See the License for the specific language governing permissions and
 12  
  * limitations under the License.
 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  
                         // set result to true to prevent re-resolution of classes involved in cyclic graphs
 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  
                         // this is java.lang.Object
 83  
                         // parent should remain null
 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)) { // bcel behaves
 138  
                                                     // unexpectedly, Object's
 139  
                                                     // super class is Object
 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  
 }