package xapi.bytecode.impl;
import java.lang.reflect.Array;
import java.util.Arrays;
import xapi.bytecode.annotation.Annotation;
import xapi.bytecode.annotation.AnnotationMemberValue;
import xapi.bytecode.annotation.AnnotationsAttribute;
import xapi.bytecode.annotation.ArrayMemberValue;
import xapi.bytecode.annotation.BooleanMemberValue;
import xapi.bytecode.annotation.ByteMemberValue;
import xapi.bytecode.annotation.CharMemberValue;
import xapi.bytecode.annotation.ClassMemberValue;
import xapi.bytecode.annotation.DoubleMemberValue;
import xapi.bytecode.annotation.EnumMemberValue;
import xapi.bytecode.annotation.FloatMemberValue;
import xapi.bytecode.annotation.IntegerMemberValue;
import xapi.bytecode.annotation.LongMemberValue;
import xapi.bytecode.annotation.MemberValue;
import xapi.bytecode.annotation.MemberValueVisitor;
import xapi.bytecode.annotation.ShortMemberValue;
import xapi.bytecode.annotation.StringMemberValue;
import xapi.collect.impl.ToStringFifo;
import xapi.log.X_Log;
import xapi.source.X_Modifier;
import xapi.source.api.IsAnnotationValue;
import xapi.source.api.IsClass;
import xapi.source.api.IsType;
import xapi.source.impl.ImmutableAnnotationValue;
import xapi.util.X_Debug;
import xapi.util.api.ConvertsValue;
public class BytecodeUtil {
public static Annotation[] extractAnnotations(AnnotationsAttribute visible, AnnotationsAttribute invisible) {
Annotation[]
vis = visible == null ? null : visible.getAnnotations()
, invis = invisible == null ? null : invisible.getAnnotations();
if (vis == null) {
return invis == null ? new Annotation[0] : invis;
}
if (invis == null)
return vis;
vis = Arrays.copyOf(vis, vis.length+invis.length);
System.arraycopy(invis, 0, vis, vis.length - invis.length, invis.length);
return vis;
}
public static IsAnnotationValue extractValue(MemberValue value, BytecodeAdapterService service, IsType type) {
return new ValueExtractor().extract(value, service, type);
}
private static final class ArrayTypeExtractor implements MemberValueVisitor {
String type;
int modifier;
@Override
public void visitAnnotationMemberValue(AnnotationMemberValue node) {
type = node.getValue().getTypeName();
modifier = X_Modifier.ANNOTATION;
}
@Override
public void visitArrayMemberValue(ArrayMemberValue node) {
throw new IllegalStateException("Array types cannot have array members");
}
@Override
public void visitBooleanMemberValue(BooleanMemberValue node) {
type = "boolean";
modifier = -1;
}
@Override
public void visitByteMemberValue(ByteMemberValue node) {
type = "byte";
modifier = -1;
}
@Override
public void visitCharMemberValue(CharMemberValue node) {
type = "char";
modifier = -1;
}
@Override
public void visitDoubleMemberValue(DoubleMemberValue node) {
type = "double";
modifier = -1;
}
@Override
public void visitEnumMemberValue(EnumMemberValue node) {
type = node.getType();
modifier = X_Modifier.ENUM;
}
@Override
public void visitFloatMemberValue(FloatMemberValue node) {
type = "float";
modifier = -1;
}
@Override
public void visitIntegerMemberValue(IntegerMemberValue node) {
type = "int";
modifier = -1;
}
@Override
public void visitLongMemberValue(LongMemberValue node) {
type = "long";
modifier = -1;
}
@Override
public void visitShortMemberValue(ShortMemberValue node) {
type = "short";
modifier = -1;
}
@Override
public void visitStringMemberValue(StringMemberValue node) {
type = "java.lang.String";
}
@Override
public void visitClassMemberValue(ClassMemberValue node) {
type = "java.lang.Class";
}
}
private static final class ValueExtractor implements MemberValueVisitor {
IsAnnotationValue value;
private BytecodeAdapterService service;
private IsType knownType;
public IsAnnotationValue extract(MemberValue member, BytecodeAdapterService service, IsType type) {
this.service = service;
this.knownType = type;
member.accept(this);
return value;
}
@Override
public void visitAnnotationMemberValue(AnnotationMemberValue node) {
final Annotation val = node.getValue();
value = new ImmutableAnnotationValue(val.getTypeName(), service.toAnnotation(val), new ConvertsValue<Object, String>() {
@Override
public String convert(Object from) {
return val.toString();
}
}, X_Modifier.ANNOTATION);
}
@Override
public void visitArrayMemberValue(ArrayMemberValue node) {
MemberValue[] val = node.getValue();
ToStringFifo<IsAnnotationValue> toString = new ToStringFifo<IsAnnotationValue>();
ValueExtractor extract = new ValueExtractor();
MemberValue type = node.getType();
if (type == null) {
try {
node.getType(service.getClassLoader());
} catch (ClassNotFoundException e) {
if (val.length == 0 && this.knownType != null) {
// We have a zero-arg array value of a known type; we can create the necessary value
IsClass cls = service.toClass(knownType.getQualifiedName());
Object value;
ConvertsValue<Object, String> toStringer = new ConvertsValue<Object, String>() {
@Override
public String convert(Object from) {
return "{}";
}
};
int modifier = 0;
if (cls.isPrimitive()) {
modifier = -1;
switch (cls.getQualifiedName()) {
case "boolean":
value = new boolean[0];
break;
case "byte":
value = new byte[0];
break;
case "char":
value = new char[0];
break;
case "short":
value = new short[0];
break;
case "int":
value = new int[0];
break;
case "long":
value = new long[0];
break;
case "float":
value = new float[0];
break;
case "double":
value = new double[0];
break;
default:
throw new IllegalArgumentException();
}
} else {
if (X_Modifier.isEnum(cls.getModifier())) {
modifier = X_Modifier.ENUM;
try {
Class<?> clazz = cls.toClass(service.getClassLoader());
value = Array.newInstance(clazz, 0);
} catch (ClassNotFoundException e1) {
throw X_Debug.rethrow(e1);
}
} else if (X_Modifier.isAnnotation(cls.getModifier())) {
modifier = X_Modifier.ANNOTATION;
value = new Class[0];
try {
Class<?> clazz = cls.toClass(service.getClassLoader());
value = Array.newInstance(clazz, 0);
} catch (ClassNotFoundException e1) {
throw X_Debug.rethrow(e1);
}
} else if (cls.getQualifiedName().equals(String.class.getName())) {
value = new String[0];
} else {
// Must be a class array
value = new Class[0];
}
}
this.value = new ImmutableAnnotationValue(cls.getQualifiedName(), value, modifier);
} else {
X_Log.error(getClass(), "Unable to load array member value type", node,"from",this.value, e);
}
return;
}
type = node.getType();
}
for (MemberValue member : val) {
toString.give(extract.extract((type = member), service, null));
}
ArrayTypeExtractor getType = new ArrayTypeExtractor();
type.accept(getType);
value = new ImmutableAnnotationValue(getType.type, toString, getType.modifier);
}
@Override
public void visitBooleanMemberValue(BooleanMemberValue node) {
value = new ImmutableAnnotationValue("boolean", node.getValue(), -1);
}
@Override
public void visitByteMemberValue(ByteMemberValue node) {
value = new ImmutableAnnotationValue("byte", node.getValue(), -1);
}
@Override
public void visitCharMemberValue(CharMemberValue node) {
value = new ImmutableAnnotationValue("char", node.getValue(), -1);
}
@Override
public void visitDoubleMemberValue(DoubleMemberValue node) {
value = new ImmutableAnnotationValue("double", node.getValue(), -1);
}
@Override
@SuppressWarnings("unchecked")
public void visitEnumMemberValue(EnumMemberValue node) {
Object val;
try {
Class<?> enumCls = Class.forName(node.getType(), false, service.getClassLoader());
val = Enum.valueOf(Class.class.cast(enumCls), node.getValue());
} catch (Exception e) {
X_Log.error("Unable to load enum value type "+node.getType()+"."+node.getValue(),e);
val = node.getValue();
}
value = new ImmutableAnnotationValue(node.getType(), val, X_Modifier.ENUM);
}
@Override
public void visitFloatMemberValue(FloatMemberValue node) {
value = new ImmutableAnnotationValue("float", node.getValue(), -1);
}
@Override
public void visitIntegerMemberValue(IntegerMemberValue node) {
value = new ImmutableAnnotationValue("int", node.getValue(), -1);
}
@Override
public void visitLongMemberValue(LongMemberValue node) {
value = new ImmutableAnnotationValue("long", node.getValue(), -1);
}
@Override
public void visitShortMemberValue(ShortMemberValue node) {
value = new ImmutableAnnotationValue("short", node.getValue(), -1);
}
@Override
public void visitStringMemberValue(StringMemberValue node) {
value = new ImmutableAnnotationValue("java.lang.String", node.getValue(), 0);
}
@Override
public void visitClassMemberValue(ClassMemberValue node) {
Object cls;
final String name = node.getValue();
try {
cls = Class.forName(name, false, service.getClassLoader());
} catch (Exception e ) {
X_Log.error("Unable to load annotation class value ",node.getValue());
cls = node.getValue();
}
value = new ImmutableAnnotationValue("java.lang.Class", cls, new ConvertsValue<Object, String>() {
@Override
public String convert(Object from) {
return name;
}
}, 0);
}
}
}