/* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package signature.converter.dex; import static signature.converter.dex.DexUtil.convertAnyWay; import static signature.converter.dex.DexUtil.declaresExceptions; import static signature.converter.dex.DexUtil.declaresMemberClasses; import static signature.converter.dex.DexUtil.findPackageInfo; import static signature.converter.dex.DexUtil.getClassModifiers; import static signature.converter.dex.DexUtil.getClassName; import static signature.converter.dex.DexUtil.getDefaultMappingsAnnotation; import static signature.converter.dex.DexUtil.getDexName; import static signature.converter.dex.DexUtil.getEnclosingClassName; import static signature.converter.dex.DexUtil.getExceptionSignature; import static signature.converter.dex.DexUtil.getGenericSignature; import static signature.converter.dex.DexUtil.getKind; import static signature.converter.dex.DexUtil.getMemberClassNames; import static signature.converter.dex.DexUtil.getModifier; import static signature.converter.dex.DexUtil.getPackageName; import static signature.converter.dex.DexUtil.getQualifiedName; import static signature.converter.dex.DexUtil.hasAnnotationDefaultSignature; import static signature.converter.dex.DexUtil.hasGenericSignature; import static signature.converter.dex.DexUtil.isAnnotation; import static signature.converter.dex.DexUtil.isConstructor; import static signature.converter.dex.DexUtil.isEnclosingClass; import static signature.converter.dex.DexUtil.isEnum; import static signature.converter.dex.DexUtil.isInternalAnnotation; import static signature.converter.dex.DexUtil.isJavaLangObject; import static signature.converter.dex.DexUtil.isMethod; import static signature.converter.dex.DexUtil.isVisible; import static signature.converter.dex.DexUtil.splitTypeList; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import signature.converter.Visibility; import signature.model.IAnnotation; import signature.model.IAnnotationElement; import signature.model.IAnnotationField; import signature.model.IClassDefinition; import signature.model.IClassReference; import signature.model.IConstructor; import signature.model.IEnumConstant; import signature.model.IField; import signature.model.IMethod; import signature.model.IPackage; import signature.model.IParameter; import signature.model.ITypeReference; import signature.model.ITypeVariableDefinition; import signature.model.Kind; import signature.model.Modifier; import signature.model.impl.SigAnnotation; import signature.model.impl.SigAnnotationElement; import signature.model.impl.SigAnnotationField; import signature.model.impl.SigApi; import signature.model.impl.SigClassDefinition; import signature.model.impl.SigClassReference; import signature.model.impl.SigConstructor; import signature.model.impl.SigEnumConstant; import signature.model.impl.SigExecutableMember; import signature.model.impl.SigField; import signature.model.impl.SigMethod; import signature.model.impl.SigPackage; import signature.model.impl.SigParameter; import signature.model.impl.Uninitialized; import signature.model.util.TypePool; import dex.structure.DexAnnotation; import dex.structure.DexAnnotationAttribute; import dex.structure.DexClass; import dex.structure.DexEncodedAnnotation; import dex.structure.DexEncodedValue; import dex.structure.DexField; import dex.structure.DexFile; import dex.structure.DexMethod; import dex.structure.DexParameter; /** * Converts a set of dex files to the signature compare api. */ public final class DexToSigConverter implements IClassInitializer { private final FieldPool elementPool; private final TypePool factory; private static final Set EMPTY_FIELDS = Collections.emptySet(); private static final Set EMPTY_ENUM_CONSTANTS = Collections .emptySet(); private static final Set EMPTY_ANNOTATION_FIELDS = Collections.emptySet(); private static final List EMPTY_TYPE_VARIABLES = Collections.emptyList(); private static final Set EMPTY_INNER_CLASSES = Collections.emptySet(); private static final Set EMPTY_EXCEPTIONS = Collections .emptySet(); private Visibility visibility; private Map dexNameToDexClass; /** * Creates a new instance of {@link DexToSigConverter}. */ public DexToSigConverter() { factory = new TypePool(); elementPool = new FieldPool(); } public SigApi convertApi(String apiName, Set dexFiles, Visibility visibility) { this.visibility = visibility; SigApi api = new SigApi(apiName, visibility); api.setPackages(convertPackages(dexFiles)); factory.replaceAllUninitialiezWithNull(); return api; } /** * Converts the given {@link DexFile}s into the corresponding (packages * including their (classes and their members, etc.))E * * @param parsedFiles * the dex files to convert * @return the converted packages */ /* package */Set convertPackages(Set parsedFiles) { Map packageNameToPackage = new HashMap(); Map> packageToDexClasses = new HashMap>(); dexNameToDexClass = new HashMap(); for (DexFile dexFile : parsedFiles) { List definedClasses = dexFile.getDefinedClasses(); for (DexClass dexClass : definedClasses) { dexNameToDexClass.put(dexClass.getName(), dexClass); String dexName = dexClass.getName(); String packageName = getPackageName(dexName); SigPackage aPackage = packageNameToPackage.get(packageName); if (aPackage == null) { aPackage = convertPackage(packageName); packageNameToPackage.put(packageName, aPackage); Set classes = new HashSet(); packageToDexClasses.put(aPackage, classes); } Set classes = packageToDexClasses.get(aPackage); classes.add(dexClass); } } Set allClasses = new HashSet(); for (SigPackage aPackage : packageToDexClasses.keySet()) { Set classes = convertClasses(packageToDexClasses .get(aPackage)); allClasses.addAll(classes); aPackage.setClasses(new HashSet(classes)); } // remove package info for (SigPackage aPackage : packageToDexClasses.keySet()) { IClassDefinition packageInfo = findPackageInfo(aPackage); if (packageInfo != null) { aPackage.setAnnotations(packageInfo.getAnnotations()); aPackage.getClasses().remove(packageInfo); } } // link enclosed classes only if they are part of visible api for (SigClassDefinition sigClass : allClasses) { String dexName = getDexName(sigClass); DexClass dexClass = dexNameToDexClass.get(dexName); if (declaresMemberClasses(dexClass)) { Set enclosedClassesNames = getMemberClassNames(dexClass); Set memberClasses = new HashSet(); for (String enclosedClassName : enclosedClassesNames) { SigClassDefinition memberClass = factory.getClass( getPackageName(enclosedClassName), getClassName(enclosedClassName)); // add inner class only if parsed if (allClasses.contains(memberClass)) { memberClasses.add(memberClass); } } sigClass.setInnerClasses(memberClasses); } else { sigClass.setInnerClasses(EMPTY_INNER_CLASSES); } } // remove inner classes, is outer class is not visible for (SigClassDefinition sigClass : allClasses) { if (hasInvisibleParent(sigClass, dexNameToDexClass)) { SigPackage sigPackage = packageNameToPackage.get(sigClass .getPackageName()); sigPackage.getClasses().remove(sigClass); } } return new HashSet(packageToDexClasses.keySet()); } private boolean hasInvisibleParent(IClassDefinition sigClass, Map dexNameToDexClass) { do { String dexName = getDexName(sigClass); DexClass dexClass = dexNameToDexClass.get(dexName); if (isEnclosingClass(dexClass)) { IClassDefinition declaringClass = sigClass.getDeclaringClass(); DexClass declaringDexClass = dexNameToDexClass .get(getDexName(declaringClass)); if (!isVisible(declaringDexClass, visibility)) { return true; } } } while ((sigClass = sigClass.getDeclaringClass()) != null); return false; } /** * Converts a simple string to the corresponding {@link SigPackage}.
* Format: "a.b.c" * * @param packageName * the name of the package * @return the package */ protected SigPackage convertPackage(String packageName) { SigPackage sigPackage = new SigPackage(packageName); return sigPackage; } /** * Converts a set of {@link DexClass} objects to a set of the corresponding * {@link SigClassDefinition} objects. * * @param dexClasses * the {@link DexClass} objects * @return a set of {@link DexClass} objects */ protected Set convertClasses(Set dexClasses) { Set classes = new HashSet(); for (DexClass dexClass : dexClasses) { // convert all classes but synthetic, return only initialized if (convertAnyWay(dexClass)) { SigClassDefinition sigCLass = convertClass(dexClass); if (isVisible(dexClass, visibility)) { classes.add(sigCLass); } } } return classes; } /** * Converts a {@link DexClass} to the corresponding * {@link SigClassDefinition}. * * @param dexClass * the {@link DexClass} to convert * @return the corresponding {@link SigClassDefinition} */ protected SigClassDefinition convertClass(DexClass dexClass) { assert dexClass != null; String packageName = getPackageName(dexClass.getName()); String className = getClassName(dexClass.getName()); SigClassDefinition sigClass = factory.getClass(packageName, className); // Kind sigClass.setKind(getKind(dexClass)); // modifiers Set modifiers = getModifier(getClassModifiers(dexClass)); sigClass.setModifiers(modifiers); if (isEnclosingClass(dexClass)) { String declaringClassDexName = getEnclosingClassName(dexClass); declaringClassDexName = getClassName(declaringClassDexName); // declaring class is in same package sigClass.setDeclaringClass(factory.getClass(sigClass .getPackageName(), declaringClassDexName)); } else { sigClass.setDeclaringClass(null); } if (hasGenericSignature(dexClass)) { GenericSignatureParser parser = new GenericSignatureParser(factory, this); parser.parseForClass(sigClass, getGenericSignature(dexClass)); sigClass.setTypeParameters(parser.formalTypeParameters); if (Kind.INTERFACE.equals(sigClass.getKind())) { sigClass.setSuperClass(null); } else { sigClass.setSuperClass(parser.superclassType); } sigClass.setInterfaces(new HashSet( parser.interfaceTypes)); } else { // Type parameters sigClass.setTypeParameters(EMPTY_TYPE_VARIABLES); // java.lang.Object has no super class if (isJavaLangObject(dexClass)) { sigClass.setSuperClass(null); } else { if (Kind.INTERFACE.equals(sigClass.getKind()) || Kind.ANNOTATION.equals(sigClass.getKind())) { sigClass.setSuperClass(null); } else { String superClassPackageName = getPackageName(dexClass .getSuperClass()); String superClassName = getClassName(dexClass .getSuperClass()); sigClass.setSuperClass(factory.getClassReference( superClassPackageName, superClassName)); } } List interfaceDexNames = dexClass.getInterfaces(); Set interfaces = new HashSet(); for (String interfaceDexName : interfaceDexNames) { String interfacePackageName = getPackageName(interfaceDexName); String interfaceName = getClassName(interfaceDexName); SigClassDefinition interfaze = factory.getClass( interfacePackageName, interfaceName); interfaze.setKind(Kind.INTERFACE); interfaces.add(new SigClassReference(interfaze)); } sigClass.setInterfaces(interfaces); } // constructors Set constructors = convertConstructors(dexClass .getMethods()); for (SigConstructor constructor : constructors) { constructor.setDeclaringClass(sigClass); } sigClass.setConstructors(new HashSet(constructors)); // methods Set methods = Collections.emptySet(); if (isAnnotation(dexClass)) { Map mappings = getDefaultValueMapping(dexClass); Set annotationFields = convertAnnotationFields( dexClass.getMethods(), mappings); sigClass.setAnnotationFields(new HashSet( annotationFields)); addAnnotationsToAnnotationFields(dexClass.getMethods(), annotationFields); sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS); sigClass.setFields(EMPTY_FIELDS); // sigClass.setAnnotationFields(new // HashSet(convertAnnotationFields(dexClass))); } else if (isEnum(dexClass)) { Set fields = new HashSet(); Set enumConstants = new HashSet(); for (DexField dexField : dexClass.getFields()) { if (isVisible(dexField, visibility)) { if (dexField.isEnumConstant()) { enumConstants.add(convertEnumConstant(dexField)); } else { fields.add(convertField(dexField)); } } } sigClass.setFields(fields); sigClass.setEnumConstants(enumConstants); sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS); methods = convertMethods(dexClass.getMethods()); } else { // fields sigClass.setFields(new HashSet(convertFields(dexClass .getFields()))); sigClass.setEnumConstants(EMPTY_ENUM_CONSTANTS); sigClass.setAnnotationFields(EMPTY_ANNOTATION_FIELDS); methods = convertMethods(dexClass.getMethods()); } for (SigMethod method : methods) { method.setDeclaringClass(sigClass); } sigClass.setMethods(new HashSet(methods)); // Annotations sigClass.setAnnotations(convertAnnotations(dexClass.getAnnotations())); return sigClass; } @SuppressWarnings("unchecked") private Map getDefaultValueMapping(DexClass dexClass) { HashMap mappings = new HashMap(); if (hasAnnotationDefaultSignature(dexClass)) { // read mapping to defaults from annotation DexAnnotation annotation = getDefaultMappingsAnnotation(dexClass); DexAnnotationAttribute dexAnnotationAttribute = annotation .getAttributes().get(0); if ("value".equals(dexAnnotationAttribute.getName())) { DexEncodedValue encodedValue = dexAnnotationAttribute .getEncodedValue(); DexEncodedValue value = (DexEncodedValue) encodedValue .getValue(); List defaults = (List) value.getValue(); for (DexAnnotationAttribute defaultAttribute : defaults) { mappings.put(defaultAttribute.getName(), convertEncodedValue(defaultAttribute .getEncodedValue())); } } } return mappings; } private void addAnnotationsToAnnotationFields(List methods, Set annotationFields) { Map nameToAnnotationField = new HashMap(); for (SigAnnotationField annotationField : annotationFields) { nameToAnnotationField.put(annotationField.getName(), annotationField); } for (DexMethod method : methods) { SigAnnotationField annotationField = nameToAnnotationField .get(method.getName()); annotationField.setAnnotations(convertAnnotations(method .getAnnotations())); } } private Set convertAnnotationFields( List list, Map mappings) { Set annotationfields = new HashSet(); for (DexMethod dexMethod : list) { if (isVisible(dexMethod, visibility)) { annotationfields.add(convertAnnotationField(dexMethod, mappings .get(dexMethod.getName()))); } } return annotationfields; } private SigAnnotationField convertAnnotationField(DexMethod dexMethod, Object defaultValue) { SigAnnotationField annotationField = new SigAnnotationField(dexMethod .getName()); annotationField.setDefaultValue(defaultValue); annotationField.setModifiers(getModifier(dexMethod.getModifiers())); GenericSignatureParser parser = new GenericSignatureParser(factory, this); annotationField.setType(parser.parseNonGenericType(dexMethod .getReturnType())); return annotationField; } private IEnumConstant convertEnumConstant(DexField dexField) { String qualifiedTypeName = getQualifiedName(dexField .getDeclaringClass().getName()); SigEnumConstant enumConstant = elementPool.getEnumConstant( qualifiedTypeName, dexField.getName()); Set modifiers = getModifier(dexField.getModifiers()); modifiers.add(Modifier.STATIC); enumConstant.setModifiers(modifiers); String typePackageName = getPackageName(dexField.getType()); String typeName = getClassName(dexField.getType()); enumConstant.setType(factory.getClassReference(typePackageName, typeName)); enumConstant.setAnnotations(convertAnnotations(dexField .getAnnotations())); return enumConstant; } private Set convertFields(List dexFields) { Set fields = new HashSet(); for (DexField dexField : dexFields) { if (isVisible(dexField, visibility)) { fields.add(convertField(dexField)); } } return fields; } private SigField convertField(DexField dexField) { String qualTypeName = getQualifiedName(dexField.getDeclaringClass() .getName()); SigField field = elementPool.getField(qualTypeName, dexField.getName()); field.setModifiers(getModifier(dexField.getModifiers())); field.setAnnotations(convertAnnotations(dexField.getAnnotations())); if (hasGenericSignature(dexField)) { GenericSignatureParser parser = new GenericSignatureParser(factory, this); String declaringClassPackageName = getPackageName(dexField .getDeclaringClass().getName()); String declaringClassName = getClassName(dexField .getDeclaringClass().getName()); parser.parseForField(factory.getClass(declaringClassPackageName, declaringClassName), getGenericSignature(dexField)); field.setType(parser.fieldType); } else { GenericSignatureParser parser = new GenericSignatureParser(factory, this); field.setType(parser.parseNonGenericType(dexField.getType())); } return field; } /** * Converts a set of {@link DexMethod} to a set of corresponding * {@link IConstructor}. This method ignores methods which are not * constructors. * * @param methods * the {@link DexMethod}s to convert * @return the corresponding {@link IConstructor}s */ private Set convertConstructors(List methods) { Set constructors = new HashSet(); for (DexMethod method : methods) { if (isConstructor(method) && isVisible(method, visibility)) { constructors.add(convertConstructor(method)); } } return constructors; } /** * Converts a set of {@link DexMethod} to a set of corresponding * {@link DexMethod}. This method ignores methods which are constructors. * * @param methods * the {@link DexMethod}s to convert * @return the corresponding {@link IConstructor}s */ private Set convertMethods(List methods) { Set sigMethods = new HashSet(); for (DexMethod method : methods) { if (isMethod(method) && isVisible(method, visibility)) { sigMethods.add(convertMethod(method)); } } return sigMethods; } /** * Converts a dexMethod which must be a constructor to the corresponding * {@link SigConstructor} instance. * * @param dexMethod * the dex constructor to convert * @return the corresponding {@link SigConstructor} */ public SigConstructor convertConstructor(DexMethod dexMethod) { String declaringClassName = getClassName(dexMethod.getDeclaringClass() .getName()); SigConstructor constructor = new SigConstructor(declaringClassName); constructor.setModifiers(getModifier(dexMethod.getModifiers())); String declaringClassPackageName = getPackageName(dexMethod .getDeclaringClass().getName()); SigClassDefinition declaringClass = factory.getClass( declaringClassPackageName, declaringClassName); constructor.setDeclaringClass(declaringClass); // Annotations constructor.setAnnotations(convertAnnotations(dexMethod .getAnnotations())); if (hasGenericSignature(dexMethod)) { GenericSignatureParser parser = new GenericSignatureParser(factory, this); parser.parseForConstructor(constructor, getGenericSignature(dexMethod)); // type parameters constructor.setTypeParameters(parser.formalTypeParameters); // parameters // generic parameter types parameters List dexParameters = dexMethod.getParameters(); List parameters = new ArrayList( parser.parameterTypes.size()); Iterator iterator = dexParameters.iterator(); for (ITypeReference parameterType : parser.parameterTypes) { SigParameter parameter = new SigParameter(parameterType); iterator.hasNext(); DexParameter dexParam = iterator.next(); parameter.setAnnotations(convertAnnotations(dexParam .getAnnotations())); parameters.add(parameter); } constructor.setParameters(parameters); // exceptions constructor.setExceptions(new HashSet( parser.exceptionTypes)); } else { convertNonGenericExecutableMember(constructor, dexMethod); // remove first parameter of non static inner class constructors // implicit outer.this reference if (declaringClass.getDeclaringClass() != null) { if (!declaringClass.getModifiers().contains(Modifier.STATIC)) { if (constructor.getParameters().isEmpty()) { throw new IllegalStateException( "Expected at least one parameter!"); } IParameter first = constructor.getParameters().remove(0); String enclosingName = declaringClass.getDeclaringClass() .getName(); String firstParameterTypeName = ((IClassReference) first .getType()).getClassDefinition().getName(); if (!enclosingName.equals(firstParameterTypeName)) throw new IllegalStateException( "Expected first constructor parameter of type " + enclosingName); } } } addExceptions(constructor, dexMethod); return constructor; } public SigMethod convertMethod(DexMethod dexMethod) { SigMethod method = new SigMethod(dexMethod.getName()); method.setModifiers(getModifier(dexMethod.getModifiers())); String declaringClassPackageName = getPackageName(dexMethod .getDeclaringClass().getName()); String declaringClassName = getClassName(dexMethod.getDeclaringClass() .getName()); method.setDeclaringClass(factory.getClass(declaringClassPackageName, declaringClassName)); // Annotations method.setAnnotations(convertAnnotations(dexMethod.getAnnotations())); if (hasGenericSignature(dexMethod)) { GenericSignatureParser parser = new GenericSignatureParser(factory, this); parser.parseForMethod(method, getGenericSignature(dexMethod)); // type parameters method.setTypeParameters(parser.formalTypeParameters); // generic parameter types parameters List dexParameters = dexMethod.getParameters(); List parameters = new ArrayList( parser.parameterTypes.size()); Iterator iterator = dexParameters.iterator(); for (ITypeReference parameterType : parser.parameterTypes) { SigParameter parameter = new SigParameter(parameterType); iterator.hasNext(); DexParameter dexParam = iterator.next(); parameter.setAnnotations(convertAnnotations(dexParam .getAnnotations())); parameters.add(parameter); } method.setParameters(parameters); // exceptions method.setExceptions(new HashSet( parser.exceptionTypes)); method.setReturnType(parser.returnType); } else { convertNonGenericExecutableMember(method, dexMethod); GenericSignatureParser parser = new GenericSignatureParser(factory, this); ITypeReference type = parser.parseNonGenericReturnType(dexMethod .getReturnType()); method.setReturnType(type); } addExceptions(method, dexMethod); return method; } private void addExceptions(SigExecutableMember member, DexMethod dexMethod) { if (declaresExceptions(dexMethod)) { String exceptionSignature = getExceptionSignature(dexMethod); Set exceptionTypeNames = splitTypeList(exceptionSignature); Set exceptions = new HashSet(); for (String exTypeName : exceptionTypeNames) { String packageName = getPackageName(exTypeName); String className = getClassName(exTypeName); exceptions.add(factory .getClassReference(packageName, className)); } member.setExceptions(exceptions); } else { member.setExceptions(EMPTY_EXCEPTIONS); } } private void convertNonGenericExecutableMember(SigExecutableMember member, DexMethod dexMethod) { List dexParameters = dexMethod.getParameters(); List parameters = new ArrayList(dexParameters .size()); for (DexParameter dexParameter : dexParameters) { GenericSignatureParser parser = new GenericSignatureParser(factory, this); ITypeReference type = parser.parseNonGenericType(dexParameter .getTypeName()); SigParameter parameter = new SigParameter(type); parameters.add(parameter); // Annotations parameter.setAnnotations(convertAnnotations(dexParameter .getAnnotations())); } member.setParameters(parameters); member.setTypeParameters(EMPTY_TYPE_VARIABLES); // if (declaresExceptions(dexMethod)) { // String exceptionSignature = getExceptionSignature(dexMethod); // Set exceptionTypeNames = splitTypeList(exceptionSignature); // Set exceptions = new HashSet(); // // for (String exTypeName : exceptionTypeNames) { // String packageName = getPackageName(exTypeName); // String className = getClassName(exTypeName); // exceptions.add(factory.getClass(packageName, className)); // } // member.setExceptions(exceptions); // } else { // member.setExceptions(EMPTY_EXCEPTIONS); // } } /** * Converts a set of {@link DexAnnotation} to a set of corresponding * {@link SigAnnotation}. * * @param dexAnnotations * the {@link DexAnnotation}s to convert * @return the corresponding {@link SigAnnotation}s */ private Set convertAnnotations( Set dexAnnotations) { Set annotations = new HashSet(); for (DexAnnotation dexAnnotation : dexAnnotations) { if (!isInternalAnnotation(dexAnnotation)) { annotations.add(convertAnnotation(dexAnnotation)); } } return annotations; } /** * Converts a {@link DexAnnotation} to the corresponding * {@link SigAnnotation}. * * @param dexAnnotation * the {@link DexAnnotation} to convert * @return the corresponding {@link SigAnnotation} */ protected SigAnnotation convertAnnotation(DexAnnotation dexAnnotation) { SigAnnotation sigAnnotation = new SigAnnotation(); String packageName = getPackageName(dexAnnotation.getTypeName()); String className = getClassName(dexAnnotation.getTypeName()); sigAnnotation .setType(factory.getClassReference(packageName, className)); sigAnnotation.setElements(convertAnnotationElements(dexAnnotation .getAttributes())); return sigAnnotation; } private Set convertAnnotationElements( List attributes) { Set annotationAttributes = new HashSet(); for (DexAnnotationAttribute dexAnnotationAttribute : attributes) { annotationAttributes .add(convertAnnotationAttribute(dexAnnotationAttribute)); } return annotationAttributes; } private IAnnotationElement convertAnnotationAttribute( DexAnnotationAttribute dexAnnotationAttribute) { SigAnnotationElement sigElement = new SigAnnotationElement(); String nameOfField = dexAnnotationAttribute.getName(); String typeName = dexAnnotationAttribute.getAnnotation().getTypeName(); SigClassDefinition annotationClass = factory.getClass( getPackageName(typeName), getClassName(typeName)); if (!Uninitialized.isInitialized( annotationClass.getAnnotationFields())) { initializeClass(getPackageName(typeName), getClassName(typeName)); } for (IAnnotationField field : annotationClass.getAnnotationFields()) { if (nameOfField.equals(field.getName())) { sigElement.setDeclaringField(field); } } sigElement.setValue(convertEncodedValue(dexAnnotationAttribute .getEncodedValue())); return sigElement; } @SuppressWarnings("unchecked") private Object convertEncodedValue(DexEncodedValue dexEnodedValue) { Object value = null; switch (dexEnodedValue.getType()) { case VALUE_INT: case VALUE_BOOLEAN: case VALUE_BYTE: case VALUE_CHAR: case VALUE_DOUBLE: case VALUE_FLOAT: case VALUE_LONG: case VALUE_NULL: case VALUE_STRING: case VALUE_SHORT: value = dexEnodedValue.getValue(); break; case VALUE_ARRAY: { List dexValues = (List) dexEnodedValue.getValue(); Object[] arrayValues = new Object[dexValues.size()]; int i = 0; for (DexEncodedValue dexValue : dexValues) { arrayValues[i++] = convertEncodedValue(dexValue); } value = arrayValues; break; } case VALUE_ANNOTATION: { DexEncodedAnnotation annotation = (DexEncodedAnnotation) dexEnodedValue.getValue(); SigAnnotation sigAnnotation = new SigAnnotation(); String packageName = getPackageName(annotation.getTypeName()); String className = getClassName(annotation.getTypeName()); sigAnnotation.setType(factory.getClassReference(packageName, className)); sigAnnotation.setElements(convertAnnotationElements(annotation .getValue())); value = sigAnnotation; break; } case VALUE_FIELD: { String fieldDesc = (String) dexEnodedValue.getValue(); // FORMAT La/b/E;!CONSTANT String[] typeAndFieldName = fieldDesc.split("!"); String typeName = typeAndFieldName[0]; String fieldName = typeAndFieldName[1]; value = elementPool.getField(getQualifiedName(typeName), fieldName); break; } case VALUE_ENUM: { String fieldDesc = (String) dexEnodedValue.getValue(); // FORMAT La/b/E;!CONSTANT String[] typeAndFieldName = fieldDesc.split("!"); String typeName = typeAndFieldName[0]; String fieldName = typeAndFieldName[1]; value = elementPool.getEnumConstant(getQualifiedName(typeName), fieldName); break; } case VALUE_TYPE: { String typeName = (String) dexEnodedValue.getValue(); GenericSignatureParser parser = new GenericSignatureParser(factory, this); value = parser.parseNonGenericReturnType(typeName); break; } default: throw new IllegalStateException(); } return value; } public IClassDefinition initializeClass(String packageName, String className) { String dexName = getDexName(packageName, className); DexClass dexClass = dexNameToDexClass.get(dexName); return convertClass(dexClass); } }