001    /*
002     * Licensed under the Apache License, Version 2.0 (the "License");
003     * you may not use this file except in compliance with the License.
004     * You may obtain a copy of the License at
005     *
006     *      http://www.apache.org/licenses/LICENSE-2.0
007     *
008     * Unless required by applicable law or agreed to in writing, software
009     * distributed under the License is distributed on an "AS IS" BASIS,
010     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
011     * See the License for the specific language governing permissions and
012     * limitations under the License.
013     */
014    package org.apache.commons.classscan.bcel;
015    
016    import org.apache.bcel.classfile.AnnotationElementValue;
017    import org.apache.bcel.classfile.AnnotationEntry;
018    import org.apache.bcel.classfile.ArrayElementValue;
019    import org.apache.bcel.classfile.ClassElementValue;
020    import org.apache.bcel.classfile.ElementValue;
021    import org.apache.bcel.classfile.ElementValuePair;
022    import org.apache.bcel.classfile.EnumElementValue;
023    import org.apache.bcel.classfile.SimpleElementValue;
024    import org.apache.commons.classscan.builtin.ClassNameHelper;
025    import org.apache.commons.classscan.model.MetaClass;
026    import org.apache.commons.classscan.spi.model.SpiMetaAnnotation.SpiProperty;
027    import org.apache.commons.classscan.spi.model.SpiMetaClassLoader;
028    import org.slf4j.Logger;
029    import org.slf4j.LoggerFactory;
030    
031    public class BcelProperty implements SpiProperty {
032    
033        private static final Logger logger = LoggerFactory.getLogger(BcelProperty.class);
034    
035        private final String propertyName;
036        private Object value;
037    
038        public BcelProperty(ElementValuePair evPair) {
039            propertyName = evPair.getNameString();
040            value = evPair.getValue();
041        }
042    
043            @Override
044            public boolean resolve(SpiMetaClassLoader classLoader) {
045                    value = createObject(classLoader, value);
046                    return value!=null;
047            }
048    
049        @Override
050        public String getName() {
051            return propertyName;
052        }
053    
054        @Override
055        public Object getValue() {
056            return value;
057        }
058    
059        private Object createObject(SpiMetaClassLoader classLoader, Object ev) {
060            if (ev instanceof SimpleElementValue) {
061                return createWrapper((SimpleElementValue) ev);
062            }
063            if (ev instanceof EnumElementValue) {
064                return createEnum(classLoader, (EnumElementValue) ev);
065            }
066            if (ev instanceof ClassElementValue) {
067                return createMetaClass(classLoader, (ClassElementValue) ev);
068            }
069            if (ev instanceof ArrayElementValue) {
070                return createArray(classLoader, (ArrayElementValue) ev);
071            }
072            if (ev instanceof AnnotationElementValue) {
073                return createAnnotation((AnnotationElementValue) ev);
074            }
075            logger.info("unknown annotation value type "+ev.getClass().getCanonicalName()+" for annotation property "+propertyName);
076            return null;
077        }
078    
079        private Object createWrapper(SimpleElementValue sev) {
080            char primitiveTypeCode = (char) sev.getElementValueType();
081    
082            switch (primitiveTypeCode) {
083            case 'B':
084                return sev.getValueByte();
085            case 'C':
086                return sev.getValueChar();
087            case 'D':
088                return sev.getValueDouble();
089            case 'F':
090                return sev.getValueFloat();
091            case 'I':
092                return sev.getValueInt();
093            case 'J':
094                return sev.getValueLong();
095            case 'S':
096                return sev.getValueShort();
097            case 'Z':
098                return sev.getValueBoolean();
099            case 's':
100                return sev.getValueString();
101            default:
102                return null;
103            }
104        }
105    
106        private MetaClass createMetaClass(SpiMetaClassLoader classLoader, ClassElementValue ev) {
107            String internalClassName = ev.getClassString();
108            String canonicalName = ClassNameHelper.internalToCanonicalName(internalClassName);
109            return classLoader.resolveMetaClass(canonicalName);
110        }
111    
112        private Object createAnnotation(AnnotationElementValue aev) {
113            AnnotationEntry ae = ((AnnotationElementValue) aev).getAnnotationEntry();
114            return new BcelAnnotation(ae);
115        }
116    
117        private Object createEnum(SpiMetaClassLoader classLoader, EnumElementValue eev) {
118            String enumTypeString = ClassNameHelper.internalToCanonicalName(eev.getEnumTypeString());
119            MetaClass dmc = classLoader.resolveMetaClass(enumTypeString);
120            if(dmc==null) {
121                logger.info("unknown enum type "+enumTypeString+" for annotation property "+propertyName);
122                return null;
123            }
124            String enumInstanceName = eev.getEnumValueString();
125            return new BcelEnumProperty(dmc, enumInstanceName);
126        }
127    
128        private Object[] createArray(SpiMetaClassLoader classLoader, ArrayElementValue ev) {
129            ArrayElementValue aev = (ArrayElementValue) ev;
130            ElementValue[] elementValues = aev.getElementValuesArray();
131            Object[] returnValues = new Object[elementValues.length];
132            int i = 0;
133            for (ElementValue elementValue : elementValues) {
134                Object obj = createObject(classLoader, elementValue);
135                if(obj==null) {
136                    return null;
137                }
138                            returnValues[i++] = obj;
139            }
140            return returnValues;
141        }
142    }