/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.ir.compiler.bytecode; import gw.internal.ext.org.objectweb.asm.Type; import gw.internal.gosu.parser.*; import gw.internal.ext.org.objectweb.asm.AnnotationVisitor; import gw.lang.ir.IRAnnotation; import gw.lang.ir.IRType; import gw.lang.reflect.IAnnotationInfo; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.IJavaClassInfo; import gw.lang.reflect.java.IJavaClassMethod; import gw.lang.reflect.java.IJavaType; import gw.lang.reflect.java.JavaTypes; import gw.util.GosuExceptionUtil; import gw.internal.gosu.ir.transform.AbstractElementTransformer; import java.lang.reflect.Array; public class IRAnnotationCompiler { private AnnotationVisitor _visitor; private IRAnnotation _annotation; public IRAnnotationCompiler( AnnotationVisitor annotationVisitor, IRAnnotation annotation ) { _visitor = annotationVisitor; _annotation = annotation; } public void compile() { IAnnotationInfo annotationValue = _annotation.getValue(); compileAnnotationInfo( (GosuAnnotationInfo)annotationValue ); } private void compileAnnotationInfo( GosuAnnotationInfo gai ) { IJavaClassInfo classInfo = ((IJavaType) gai.getType()).getBackingClassInfo(); IJavaClassMethod[] methods = classInfo.getDeclaredMethods(); for( IJavaClassMethod method : methods ) { if( method.getParameterTypes().length == 0 ) { String fieldName = method.getName(); if( !fieldName.equals( "hashCode" ) && !fieldName.equals( "toString" ) && !fieldName.equals( "annotationType" ) ) { IRType returnIRType = AbstractElementTransformer.getDescriptor( method.getReturnType() ); Object value = gai.getFieldValue( fieldName ); visitAnnotationField( _visitor, method.getReturnClassInfo(), fieldName, returnIRType, value ); } } } _visitor.visitEnd(); } private void visitAnnotationField( AnnotationVisitor visitor, IJavaClassInfo returnClassInfo, String fieldName, IRType returnIRType, Object value ) { if( value == null ) { visitor.visit( fieldName, null ); return; } try { if( returnClassInfo.isAnnotation() ) { AnnotationVisitor annotationVisitor = visitor.visitAnnotation( fieldName, returnIRType.getDescriptor() ); new IRAnnotationCompiler( annotationVisitor, new IRAnnotation( returnIRType, true, (IAnnotationInfo)value ) ).compile(); } else if( JavaTypes.CLASS().getBackingClassInfo().isAssignableFrom( returnClassInfo ) ) { if( value instanceof Class ) { visitor.visit( fieldName, Type.getType( AbstractElementTransformer.getDescriptor( (Class)value ).getDescriptor() ) ); } else if( value instanceof String ) { value = TypeLord.getPureGenericType( TypeSystem.getByFullName( (String)value) ); visitor.visit( fieldName, Type.getType( AbstractElementTransformer.getDescriptor( (IType)value ).getDescriptor() ) ); } else { value = TypeLord.getPureGenericType( (IType)value ); visitor.visit( fieldName, Type.getType( AbstractElementTransformer.getDescriptor( (IType)value ).getDescriptor() ) ); } } else if( returnClassInfo.isArray() ) { visitArray( returnClassInfo, returnIRType, fieldName, value ); } else if( returnClassInfo.isEnum() ) { visitor.visitEnum( fieldName, returnIRType.getDescriptor(), (String)value ); } else { visitor.visit( fieldName, value ); } } catch( Exception e ) { throw GosuExceptionUtil.forceThrow( e ); } } private void visitArray( IJavaClassInfo returnClassInfo, IRType returnIRType, String name, Object value ) { AnnotationVisitor arrVisitor = _visitor.visitArray( name ); if( returnClassInfo.getComponentType().isPrimitive() ) { if( value.getClass().isArray() ) { for( int i = 0; i < Array.getLength( value ); i++ ) { arrVisitor.visit( name, Array.get( value, i ) ); } } else { arrVisitor.visit( name, value ); } } else { if( value.getClass().isArray() ) { Object[] valArr = (Object[])value; for( Object o : valArr ) { visitAnnotationField( arrVisitor, returnClassInfo.getComponentType(), name, returnIRType.getComponentType(), o ); } } else { visitAnnotationField( arrVisitor, returnClassInfo.getComponentType(), name, returnIRType.getComponentType(), value ); } } arrVisitor.visitEnd(); } }