/* * Copyright 2013 Guidewire Software, Inc. */ package gw.internal.gosu.parser.java.classinfo; import gw.internal.gosu.parser.AsmMethodJavaClassMethod; import gw.internal.gosu.parser.MethodJavaClassMethod; import gw.internal.gosu.parser.java.IJavaASTNode; import gw.internal.gosu.parser.java.JavaASTConstants; import gw.lang.parser.IExpression; import gw.lang.reflect.IAnnotationInfo; import gw.lang.reflect.IType; import gw.lang.reflect.TypeSystem; import gw.lang.reflect.java.IJavaAnnotatedElement; import gw.lang.reflect.java.IJavaClassField; import gw.lang.reflect.java.IJavaClassInfo; import gw.lang.reflect.java.IJavaClassMethod; import gw.lang.reflect.module.IModule; import java.lang.reflect.Array; import java.util.List; public class JavaSourceAnnotationInfo implements IAnnotationInfo { private IJavaASTNode _annotationNode; private IJavaAnnotatedElement _owner; private IModule _gosuModule; private String _name; private IJavaClassInfo _type; public JavaSourceAnnotationInfo(IJavaASTNode annotationNode, IJavaAnnotatedElement owner) { _annotationNode = annotationNode; _owner = owner; _gosuModule = _owner instanceof IJavaClassInfo ? ((IJavaClassInfo) _owner).getModule() : _owner.getEnclosingClass().getModule(); } @Override public IType getType() { return TypeSystem.getByFullNameIfValid(getName(), _gosuModule); } @Override public Object getInstance() { throw new RuntimeException("Not supported for source types"); } @Override public Object getFieldValue(String fieldName) { initNameAndType(); try { IJavaClassMethod method = _type.getMethod(fieldName); return parseValue(method); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } private Object parseValue(IJavaClassMethod method) { IJavaASTNode valueNode = null; IJavaASTNode pairs = _annotationNode.getChildOfType( JavaASTConstants.elementValuePairs ); if( pairs != null ) { for( IJavaASTNode pair : pairs.getChildrenOfTypes( JavaASTConstants.elementValuePair ) ) { if( pair.getChild( 0 ).getText().equals( method.getName() ) ) { valueNode = pair.getChildOfType( JavaASTConstants.elementValue ); break; } } } else { valueNode = _annotationNode.getChildOfType( JavaASTConstants.elementValue ); } if( valueNode == null ) { Object defaultValue = method.getDefaultValue(); if (method instanceof MethodJavaClassMethod || method instanceof AsmMethodJavaClassMethod) { if (defaultValue.getClass().isArray()) { String[] value = new String[Array.getLength(defaultValue)]; for (int i = 0; i < value.length; i++) { value[i] = Array.get(defaultValue, i).toString(); } return value; } else { return defaultValue; } } else { return ((JavaSourceDefaultValue) defaultValue).evaluate(); } } return evaluate( method.getReturnClassInfo(), valueNode ); } private Object evaluate( IJavaClassInfo type, IJavaASTNode valueNode ) { IJavaASTNode annotationValue = valueNode.getChildOfType( JavaASTConstants.annotation ); if( annotationValue != null ) { return new JavaSourceAnnotationInfo(annotationValue, _owner); } IJavaASTNode arrayNode = valueNode.getChildOfType( JavaASTConstants.elementValueArrayInitializer ); if( arrayNode != null ) { List<IJavaASTNode> children = arrayNode.getChildrenOfTypes( JavaASTConstants.elementValue ); Object[] arrayResult = null; int i = 0; for( IJavaASTNode elemValue : children ) { Object value = evaluate( type.getComponentType(), elemValue ); if( arrayResult == null ) { arrayResult = (Object[])Array.newInstance( value.getClass(), children.size() ); } arrayResult[i++] = value; } return arrayResult; } String text = valueNode.getSource(); if (type.isEnum()) { return parseEnum(text, type); } else { JavaSourceType enclosingType = getEnclosingType( _owner ); IExpression pr = CompileTimeExpressionParser.parse( text, enclosingType, handleSingleElementArrayType( text, type ) ); try { return pr.evaluate(); } catch (Exception e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. return null; } } } private IType handleSingleElementArrayType( String text, IJavaClassInfo type ) { IType javaType = type.getJavaType(); if( !javaType.isArray() ) { return javaType; } if( text.startsWith( "{" ) ) { return javaType; } return javaType.getComponentType(); } private JavaSourceType getEnclosingType( IJavaAnnotatedElement owner ) { if( owner instanceof JavaSourceType ) { return (JavaSourceType)owner; } return (JavaSourceType)owner.getEnclosingClass(); } private Object parseEnum(String text, IJavaClassInfo type) { String enumConstName = text.substring(text.lastIndexOf('.') + 1); IJavaClassField[] fields = type.getDeclaredFields(); for (IJavaClassField field : fields) { if (field.isEnumConstant() && field.getName().equals(enumConstName)) { return field.getName(); } } return null; } @Override public String getName() { initNameAndType(); return _name; } private void initNameAndType() { if (_name == null) { IJavaASTNode qNameNode = _annotationNode.getChildOfType(JavaASTConstants.qualifiedName); String name = ""; for (IJavaASTNode node : qNameNode.getChildren()) { name += node.getText(); } IJavaClassInfo _containingClass = _owner instanceof IJavaClassInfo ? ((IJavaClassInfo) _owner) : _owner.getEnclosingClass(); _type = (IJavaClassInfo) JavaSourceType.createType(_containingClass, name, JavaSourceType.IGNORE_NONE); _name = _type.getName().replace('$', '.'); } } @Override public String getDescription() { return getName(); } @Override public IType getOwnersType() { return _owner.getEnclosingClass().getJavaType(); } }