Commit 81ddcccb authored by pcregut's avatar pcregut

Added corrected reading of default annotations that are not primitive values...

Added corrected reading of default annotations that are not primitive values or arrays of primitive values.
This requires also changes in the generation of the class. 
Some test cases have been added.
parent f26c96bf
#Fri May 18 23:20:29 CEST 2012
eclipse.preferences.version=1
project.repository.kind=web
project.repository.url=http\://forge.ow2.org
......@@ -48,6 +48,8 @@ public class AnnotationWriterDefaultAnnotation extends AnnotationWriter {
*/
protected ClassDefinitionItem classDefinitionItem = null;
AnnotationVisitor subAnnotationVisitor;
/**
* Constructor for the default annotations.
* @param constantPool constant pool
......@@ -63,14 +65,32 @@ public class AnnotationWriterDefaultAnnotation extends AnnotationWriter {
@Override
public void visit(String name, Object value) {
// If Default Annotation, we have to create a subAnnotation and visit it.
AnnotationVisitor subAnnotationVisitor = visitAnnotation(Constants.VALUE_STRING, currentName);
subAnnotationVisitor = super.visitAnnotation(Constants.VALUE_STRING, currentName);
subAnnotationVisitor.visit(name, value);
subAnnotationVisitor.visitEnd();
// Registering "name" and "currentName" is not needed, as they were registered before.
}
@Override
@Override
public void visitEnum(String name, String desc, String value) {
subAnnotationVisitor = super.visitAnnotation(Constants.VALUE_STRING, currentName);
subAnnotationVisitor.visitEnum(name, desc, value);
}
@Override
public AnnotationVisitor visitArray(String name) {
subAnnotationVisitor = super.visitAnnotation(Constants.VALUE_STRING, currentName);
return subAnnotationVisitor.visitArray(name);
}
@Override
public AnnotationVisitor visitAnnotation(String name,String desc) {
subAnnotationVisitor = super.visitAnnotation(Constants.VALUE_STRING, currentName);
return subAnnotationVisitor.visitAnnotation(name,desc);
}
@Override
public void visitEnd() {
subAnnotationVisitor.visitEnd();
// If DefaultAnnotation, we must not add it directly to the Method, it is not encoded this way.
// It must be given to the Class, that will encode it as ONE AnnotationElement of VALUE_ANNOTATION
// type, which will consist of the one or several DefaultAnnotations.
......
......@@ -192,6 +192,7 @@ public class ApplicationReader {
/**
* Constructs a new {@link ApplicationReader} object.
* @param api the ASMDEX api level
* @param byteCode the bytecode of the application to be read.
*/
public ApplicationReader(final int api, final byte[] byteCode) {
......@@ -200,6 +201,7 @@ public class ApplicationReader {
/**
* Constructs a new {@link ApplicationReader} object.
* @param api the ASMDEX api level
* @param byteCode the bytecode of the application to be read.
* @param startOffset the start offset of the application data.
* @param length the length of the application data.
......@@ -228,6 +230,7 @@ public class ApplicationReader {
/**
* Constructs a new {@link ApplicationReader} object.
* @param api the ASMDEX api level
* @param inputStream an input stream from which to read the application.
* @throws IOException if a problem occurs during reading.
*/
......@@ -237,6 +240,7 @@ public class ApplicationReader {
/**
* Constructs a new {@link ApplicationReader} object.
* @param api the ASMDEX api level
* @param fileName name and path of the application (DEX) to be read.
* @throws IOException if an exception occurs during reading.
*/
......@@ -247,6 +251,7 @@ public class ApplicationReader {
/**
* Constructs a new {@link ApplicationReader} object.
* @param api the ASMDEX api level
* @param file the dex file to be read.
* @throws IOException if an exception occurs during reading.
*/
......@@ -746,7 +751,8 @@ public class ApplicationReader {
// As stated in the ASM visitDefaultAnnotation(), it consists only in one
// visit(), and one visitEnd().
if (annotationVisitor != null) {
annotationVisitor.visit(methodName, defaultAnnotations.get(methodName).getValue());
Object value = defaultAnnotations.get(methodName).getValue();
visitDefaultAnnotationValue(annotationVisitor,methodName,value);
annotationVisitor.visitEnd();
}
}
......@@ -826,6 +832,41 @@ public class ApplicationReader {
}
}
private void visitDefaultAnnotationValue(AnnotationVisitor annotationVisitor, String name, Object value) {
if (value instanceof DefaultAnnotationVisitor) {
DefaultAnnotationVisitor dav = (DefaultAnnotationVisitor) value;
String desc = dav.getDesc();
if (desc == null) {
// Here we have an array
AnnotationVisitor av = annotationVisitor.visitArray(name);
if (av != null) {
for(DefaultAnnotationInformation info : dav.getDefaultAnnotationInformationList()) {
visitDefaultAnnotationValue(av, info.getName(), info.getValue());
}
av.visitEnd();
}
} else {
// Here we have an annotation with its description type
AnnotationVisitor av = annotationVisitor.visitAnnotation(name,desc);
if (av != null) {
for(DefaultAnnotationInformation info : dav.getDefaultAnnotationInformationList()) {
visitDefaultAnnotationValue(av, info.getName(), info.getValue());
}
av.visitEnd();
}
}
} else if (value instanceof DefaultAnnotationInformation.EnumInfo) {
DefaultAnnotationInformation.EnumInfo enumInfo = (DefaultAnnotationInformation.EnumInfo) value;
annotationVisitor.visitEnum(name,enumInfo.enumDesc, enumInfo.enumValue);
} else if (value instanceof DefaultAnnotationInformation.ClassInfo) {
DefaultAnnotationInformation.ClassInfo classInfo = (DefaultAnnotationInformation.ClassInfo) value;
annotationVisitor.visitClass(name,classInfo.className);
} else {
// Primitive type case.
annotationVisitor.visit(name, value);
}
}
/**
* Reads an encoded value, as described in the encoded_value format. The
* parsing may be recursive.
......@@ -1268,16 +1309,20 @@ public class ApplicationReader {
ISpecificAnnotationParser specificAnnotationParser =
new DefaultAnnotationSpecificAnnotationParser(Constants.ANNOTATION_DEFAULT_INTERNAL_NAME);
boolean foundAnnotation = parseSpecificAnnotations(new DefaultAnnotationVisitor(api), specificAnnotationParser);
boolean foundAnnotation = parseSpecificAnnotations(new DefaultAnnotationVisitor(api, Constants.ANNOTATION_DEFAULT_INTERNAL_NAME), specificAnnotationParser);
if (foundAnnotation) {
// We found a Default Annotation. However, this method was called as we were
// visiting a Class. But ASM calls the visitDefaultAnnotation for each Method
// which has a Default Annotation linked to it. So we store our result and will
// use it for each Method having a Default Annotation.
DefaultAnnotationVisitor dav = (DefaultAnnotationVisitor)((DefaultAnnotationSpecificAnnotationParser)specificAnnotationParser).getAnnotationVisitor();
for (DefaultAnnotationInformation info : dav.getDefaultAnnotationInformationList()) {
String methodName = info.getName();
defaultAnnotations.put(methodName, info);
List <DefaultAnnotationInformation> entries = dav.getDefaultAnnotationInformationList();
if (entries.size() == 1) {
dav = (DefaultAnnotationVisitor) entries.get(0).getValue();
for (DefaultAnnotationInformation info : dav.getDefaultAnnotationInformationList()) {
String methodName = info.getName();
defaultAnnotations.put(methodName, info);
}
}
} else {
defaultAnnotations.clear();
......@@ -1325,16 +1370,6 @@ public class ApplicationReader {
List<String> classes = parser.getInnerClasses();
for (String name : classes) {
// We may be reading information about a class that doesn't exist.
// This can happen when, for example, the Reader reads an application that
// has been only generated partially for, for example, the Writer.
// In that case, the only missing information is the InnerClass access flag.
Integer classIndex = classNameToIndex.get(name);
int accessFlags = 0;
if (classIndex != null && classIndex >= 0) {
ClassDefinitionItem cdi = dexFile.getClassDefinitionItem(classIndex);
accessFlags = cdi.getAccessFlags();
}
int i = name.lastIndexOf('$');
// Reconstruction of the innerName and outerName.
......
......@@ -31,6 +31,8 @@
package org.ow2.asmdex.specificAnnotationVisitors;
import java.util.ArrayList;
/**
* Tiny class to hold the name and value of an Default Annotation conveniently.
* The description (class of the Annotation it belongs to) isn't stored here.
......@@ -49,12 +51,60 @@ public class DefaultAnnotationInformation {
*/
private Object value;
/**
* Description of an enumeration item. Can be used a value if this is not a primitive object.
* @author pierre
*
*/
static public class EnumInfo {
/**
* Description of the enum type
*/
final public String enumDesc;
/**
* enumeration element.
*/
final public String enumValue;
/**
* Constructor representing a statically encoded value from an enum type.
* @param enumDesc the type description
* @param enumValue the value
*/
public EnumInfo(String enumDesc, String enumValue) {
this.enumDesc = enumDesc;
this.enumValue = enumValue;
}
}
/**
*
* Representation of a value in an annotation that is class.
*/
static public class ClassInfo {
/**
* The name of the class
*/
final public String className;
/**
* Constructor for the value
* @param className static name of the class.
*/
public ClassInfo(String className) {
this.className = className;
}
}
/**
* Constructor (record)
* @param name
* @param value
*/
public DefaultAnnotationInformation(String name, Object value) {
System.out.println(name + " -> " + value); // DEBUG
this.name = name;
this.value = value;
}
......
......@@ -47,8 +47,9 @@ public class DefaultAnnotationVisitor extends AnnotationVisitor {
* Constructor.
* @param api the API level
*/
public DefaultAnnotationVisitor(int api) {
public DefaultAnnotationVisitor(int api, String desc) {
super(api);
this.desc = desc;
}
private List<DefaultAnnotationInformation> infos = new ArrayList<DefaultAnnotationInformation>();
......@@ -78,19 +79,28 @@ public class DefaultAnnotationVisitor extends AnnotationVisitor {
@Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
// The "name" is "value", ignored here.
this.desc = desc;
return this;
DefaultAnnotationVisitor av = new DefaultAnnotationVisitor(api, desc);
infos.add(new DefaultAnnotationInformation(name, av));
return av;
}
@Override
public AnnotationVisitor visitArray(String name) {
return null;
DefaultAnnotationVisitor av = new DefaultAnnotationVisitor(api, null);
infos.add(new DefaultAnnotationInformation(name, av));
return av;
}
@Override
public void visitEnd() { }
@Override
public void visitEnum(String name, String desc, String value) { }
public void visitEnum(String name, String desc, String value) {
infos.add(new DefaultAnnotationInformation(name, new DefaultAnnotationInformation.EnumInfo(desc,value)));
}
@Override
public void visitClass(String annotationName, String className) { }
public void visitClass(String name, String className) {
infos.add(new DefaultAnnotationInformation(name, new DefaultAnnotationInformation.ClassInfo(className)));
}
}
\ No newline at end of file
......@@ -111,7 +111,7 @@ public class AnnotationElement implements Comparable<AnnotationElement> {
@Override
public int hashCode() {
// Caching the hashcode is useless here (not enough calls).
return (elementName != null ? elementName.hashCode() : 0) + encodedValue.hashCode();
return (elementName != null ? elementName.hashCode() : 0) + (encodedValue != null ? encodedValue.hashCode() : 0);
}
@Override
......@@ -142,4 +142,8 @@ public class AnnotationElement implements Comparable<AnnotationElement> {
return result;
}
@Override
public String toString() {
return elementName + ": " + encodedValue;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment