| /******************************************************************************* |
| * Copyright (c) 2005, 2007 BEA Systems, Inc. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * tyeung@bea.com - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.apt.core.internal.util; |
| |
| import com.sun.mirror.declaration.AnnotationMirror; |
| import com.sun.mirror.declaration.AnnotationValue; |
| import com.sun.mirror.declaration.ParameterDeclaration; |
| import com.sun.mirror.type.AnnotationType; |
| import com.sun.mirror.type.ArrayType; |
| import com.sun.mirror.type.ClassType; |
| import com.sun.mirror.type.InterfaceType; |
| import com.sun.mirror.type.PrimitiveType; |
| import com.sun.mirror.type.TypeMirror; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.jdt.apt.core.internal.declaration.*; |
| import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv; |
| import org.eclipse.jdt.apt.core.internal.type.ArrayTypeImpl; |
| import org.eclipse.jdt.apt.core.internal.type.ErrorType; |
| import org.eclipse.jdt.apt.core.internal.type.WildcardTypeImpl; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; |
| import org.eclipse.jdt.core.dom.IAnnotationBinding; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.SingleVariableDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| |
| public class Factory |
| { |
| private static final String NULL_BINDING_NAME = "[NullBinding]"; //$NON-NLS-1$ |
| // using auto-boxing to take advantage of caching, if any. |
| // the dummy value picked here falls within the caching range. |
| public static final Byte DUMMY_BYTE = 0; |
| public static final Character DUMMY_CHAR = '0'; |
| public static final Double DUMMY_DOUBLE = 0d; |
| public static final Float DUMMY_FLOAT = 0f; |
| public static final Integer DUMMY_INTEGER = 0; |
| public static final Long DUMMY_LONG = 0l; |
| public static final Short DUMMY_SHORT = 0; |
| public static TypeDeclarationImpl createReferenceType(ITypeBinding binding, BaseProcessorEnv env) |
| { |
| if(binding == null || binding.isNullType()) return null; |
| TypeDeclarationImpl mirror = null; |
| // must test for annotation type before interface since annotation |
| // is an interface |
| if( binding.isAnnotation() ) |
| mirror = new AnnotationDeclarationImpl(binding, env); |
| else if (binding.isInterface() ) |
| mirror = new InterfaceDeclarationImpl(binding, env); |
| // must test for enum first since enum is also a class. |
| else if( binding.isEnum() ) |
| mirror = new EnumDeclarationImpl(binding, env); |
| else if( binding.isClass() ) |
| mirror = new ClassDeclarationImpl(binding, env); |
| else |
| throw new IllegalStateException("cannot create type declaration from " + binding); //$NON-NLS-1$ |
| |
| return mirror; |
| } |
| |
| public static EclipseDeclarationImpl createDeclaration(IBinding binding, BaseProcessorEnv env) |
| { |
| if(binding == null) return null; |
| |
| switch(binding.getKind()) |
| { |
| case IBinding.TYPE: |
| final ITypeBinding typeBinding = (ITypeBinding)binding; |
| if( typeBinding.isAnonymous() || typeBinding.isArray() || |
| typeBinding.isWildcardType() || typeBinding.isPrimitive() ) |
| throw new IllegalStateException("failed to create declaration from " + binding); //$NON-NLS-1$ |
| if( typeBinding.isTypeVariable() ) |
| return new TypeParameterDeclarationImpl(typeBinding, env); |
| else |
| return createReferenceType(typeBinding, env); |
| case IBinding.VARIABLE: |
| final IVariableBinding varBinding = (IVariableBinding)binding; |
| if(varBinding.isEnumConstant()) |
| return new EnumConstantDeclarationImpl(varBinding, env); |
| else |
| return new FieldDeclarationImpl(varBinding, env); |
| case IBinding.METHOD: |
| final IMethodBinding method = (IMethodBinding)binding; |
| if( method.isConstructor() ) |
| return new ConstructorDeclarationImpl(method, env); |
| final ITypeBinding declaringType = method.getDeclaringClass(); |
| if( declaringType != null && declaringType.isAnnotation() ) |
| return new AnnotationElementDeclarationImpl(method, env); |
| else |
| return new MethodDeclarationImpl(method, env); |
| default: |
| throw new IllegalStateException("failed to create declaration from " + binding); //$NON-NLS-1$ |
| } |
| } |
| |
| public static EclipseDeclarationImpl createDeclaration( |
| ASTNode node, |
| IFile file, |
| BaseProcessorEnv env) |
| { |
| if( node == null ) |
| return null; |
| switch( node.getNodeType() ) |
| { |
| case ASTNode.SINGLE_VARIABLE_DECLARATION: |
| return new SourceParameterDeclarationImpl((SingleVariableDeclaration)node, file, env); |
| case ASTNode.VARIABLE_DECLARATION_FRAGMENT: |
| return new ASTBasedFieldDeclarationImpl( (VariableDeclarationFragment)node, file, env ); |
| case ASTNode.METHOD_DECLARATION : |
| final org.eclipse.jdt.core.dom.MethodDeclaration methodDecl = |
| (org.eclipse.jdt.core.dom.MethodDeclaration)node; |
| if( methodDecl.isConstructor() ) |
| return new ASTBasedConstructorDeclarationImpl(methodDecl, file, env); |
| else |
| return new ASTBasedMethodDeclarationImpl(methodDecl, file, env ); |
| case ASTNode.ANNOTATION_TYPE_MEMBER_DECLARATION: |
| return new ASTBasedMethodDeclarationImpl((AnnotationTypeMemberDeclaration)node, file, env); |
| default : |
| throw new UnsupportedOperationException( |
| "cannot create mirror type from " + //$NON-NLS-1$ |
| node.getClass().getName() ); |
| } |
| } |
| |
| public static EclipseMirrorType createTypeMirror(ITypeBinding binding, BaseProcessorEnv env) |
| { |
| if( binding == null ) return null; |
| |
| if( binding.isPrimitive() ){ |
| if( "int".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getIntType(); |
| else if( "byte".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getByteType(); |
| else if( "short".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getShortType(); |
| else if( "char".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getCharType(); |
| else if( "long".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getLongType(); |
| else if( "float".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getFloatType(); |
| else if( "double".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getDoubleType(); |
| else if( "boolean".equals(binding.getName())) //$NON-NLS-1$ |
| return env.getBooleanType(); |
| else if( "void".equals(binding.getName()) ) //$NON-NLS-1$ |
| return env.getVoidType(); |
| else |
| throw new IllegalStateException("unrecognized primitive type: " + binding); //$NON-NLS-1$ |
| } |
| else if( binding.isArray() ) |
| return new ArrayTypeImpl(binding, env); |
| else if( binding.isWildcardType() ){ |
| return new WildcardTypeImpl(binding, env); |
| } |
| else if( binding.isTypeVariable() ) |
| return new TypeParameterDeclarationImpl(binding, env); |
| else |
| return createReferenceType(binding, env); |
| } |
| |
| public static ParameterDeclaration createParameterDeclaration( |
| final SingleVariableDeclaration param, |
| final IFile file, |
| final BaseProcessorEnv env) |
| { |
| return new SourceParameterDeclarationImpl(param, file, env); |
| } |
| |
| |
| public static ParameterDeclaration createParameterDeclaration( |
| final ExecutableDeclarationImpl exec, |
| final int paramIndex, |
| final ITypeBinding type, |
| final BaseProcessorEnv env ) |
| { |
| return new BinaryParameterDeclarationImpl(exec, type, paramIndex, env); |
| } |
| |
| |
| /** |
| * @param annotation the ast node. |
| * @param annotated the declaration that <code>annotation</code> annotated |
| * @param env |
| * @return a newly created {@link AnnotationMirror} object |
| */ |
| public static AnnotationMirror createAnnotationMirror(final IAnnotationBinding annotation, |
| final EclipseDeclarationImpl annotated, |
| final BaseProcessorEnv env) |
| { |
| return new AnnotationMirrorImpl(annotation, annotated, env); |
| } |
| |
| public static AnnotationValue createDefaultValue( |
| Object domValue, |
| AnnotationElementDeclarationImpl decl, |
| BaseProcessorEnv env) |
| { |
| if( domValue == null ) return null; |
| final Object converted = convertDOMValueToMirrorValue( |
| domValue, null, decl, decl, env, decl.getReturnType()); |
| |
| return createAnnotationValueFromDOMValue(converted, null, -1, decl, env); |
| } |
| |
| /** |
| * Build an {@link AnnotationValue} object based on the given dom value. |
| * @param domValue default value according to the DOM API. |
| * @param decl the element declaration whose default value is <code>domValue</code> |
| * if domValue is an annotation, then this is the declaration it annotated. |
| * In all other case, this parameter is ignored. |
| * @param env |
| * @return an annotation value |
| */ |
| public static AnnotationValue createDefaultValue(Object domValue, |
| ASTBasedAnnotationElementDeclarationImpl decl, |
| BaseProcessorEnv env) |
| { |
| if( domValue == null ) return null; |
| final Object converted = convertDOMValueToMirrorValue( |
| domValue, null, decl, decl, env, decl.getReturnType()); |
| |
| return createAnnotationValueFromDOMValue(converted, null, -1, decl, env); |
| } |
| |
| /** |
| * Build an {@link AnnotationValue} object based on the given dom value. |
| * @param domValue annotation member value according to the DOM API. |
| * @param elementName the name of the member value |
| * @param anno the annotation that directly contains <code>domValue</code> |
| * @param env |
| * @return an annotation value |
| */ |
| public static AnnotationValue createAnnotationMemberValue(Object domValue, |
| String elementName, |
| AnnotationMirrorImpl anno, |
| BaseProcessorEnv env, |
| TypeMirror expectedType) |
| { |
| if( domValue == null ) return null; |
| final Object converted = convertDOMValueToMirrorValue( |
| domValue, elementName, anno, |
| anno.getAnnotatedDeclaration(), env, expectedType); |
| return createAnnotationValueFromDOMValue(converted, elementName, -1, anno, env); |
| } |
| |
| /** |
| * @param convertedValue value in mirror form. |
| * @param name the name of the annotation member or null for default value |
| * @param index the number indicate the source order of the annotation member value |
| * in the annotation instance. |
| * @param mirror either {@link AnnotationMirrorImpl } or {@link AnnotationElementDeclarationImpl} |
| * @param env |
| */ |
| public static AnnotationValue createAnnotationValueFromDOMValue(Object convertedValue, |
| String name, |
| int index, |
| EclipseMirrorObject mirror, |
| BaseProcessorEnv env) |
| { |
| if( convertedValue == null ) return null; |
| if( mirror instanceof AnnotationMirrorImpl ) |
| return new AnnotationValueImpl(convertedValue, name, index, (AnnotationMirrorImpl)mirror, env); |
| else |
| return new AnnotationValueImpl(convertedValue, index, (AnnotationElementDeclarationImpl)mirror, env); |
| } |
| |
| |
| /** |
| * Building an annotation value object based on the dom value. |
| * |
| * @param dom the dom value to convert to the mirror specification. |
| * @see com.sun.mirror.declaration.AnnotationValue#getObject() |
| * @param name the name of the element if <code>domValue</code> is an |
| * element member value of an annotation |
| * @param parent the parent of this annotation value. |
| * @param decl if <code>domValue</code> is a default value, then this is the |
| * annotation element declaration where the default value originates |
| * if <code>domValue</code> is an annotation, then <code>decl</code> |
| * is the declaration that it annotates. |
| * @param expectedType the declared type of the member value. |
| * @param needBoxing <code>true</code> indicate an array should be returned. |
| * @return the converted annotation value or null if the conversion failed |
| */ |
| private static Object convertDOMValueToMirrorValue(Object domValue, |
| String name, |
| EclipseMirrorObject parent, |
| EclipseDeclarationImpl decl, |
| BaseProcessorEnv env, |
| TypeMirror expectedType) |
| { |
| if( domValue == null ) return null; |
| |
| final Object returnValue; |
| if( domValue instanceof Boolean || |
| domValue instanceof Byte || |
| domValue instanceof Character || |
| domValue instanceof Double || |
| domValue instanceof Float || |
| domValue instanceof Integer || |
| domValue instanceof Long || |
| domValue instanceof Short || |
| domValue instanceof String ) |
| returnValue = domValue; |
| |
| else if( domValue instanceof IVariableBinding ) |
| { |
| returnValue = Factory.createDeclaration((IVariableBinding)domValue, env); |
| } |
| else if (domValue instanceof Object[]) |
| { |
| final Object[] elements = (Object[])domValue; |
| final int len = elements.length; |
| final List<AnnotationValue> annoValues = new ArrayList<AnnotationValue>(len); |
| final TypeMirror leaf; |
| if( expectedType instanceof ArrayType ) |
| leaf = ((ArrayType)expectedType).getComponentType(); |
| else |
| leaf = expectedType; // doing our best here. |
| for( int i=0; i<len; i++ ){ |
| if( elements[i] == null ) continue; |
| // can't have multi-dimensional array. |
| // there should be already a java compile time error |
| else if( elements[i] instanceof Object[] ) |
| return null; |
| |
| Object o = convertDOMValueToMirrorValue( elements[i], name, parent, decl, env, leaf ); |
| if( o == null ) |
| return null; |
| assert( !( o instanceof IAnnotationBinding ) ) : |
| "Unexpected return value from convertDomValueToMirrorValue! o.getClass().getName() = " //$NON-NLS-1$ |
| + o.getClass().getName(); |
| |
| final AnnotationValue annoValue = createAnnotationValueFromDOMValue(o, name, i, parent, env); |
| if( annoValue != null ) |
| annoValues.add(annoValue); |
| } |
| return annoValues; |
| } |
| // caller should have caught this case. |
| else if( domValue instanceof ITypeBinding ) |
| returnValue = Factory.createTypeMirror((ITypeBinding)domValue, env); |
| |
| else if( domValue instanceof IAnnotationBinding ) |
| { |
| returnValue = Factory.createAnnotationMirror((IAnnotationBinding)domValue, decl, env); |
| } |
| else |
| // should never reach this point |
| throw new IllegalStateException("cannot build annotation value object from " + domValue); //$NON-NLS-1$ |
| |
| return performNecessaryTypeConversion(expectedType, returnValue, name, parent, env); |
| } |
| |
| public static Object getMatchingDummyValue(final Class<?> expectedType){ |
| if( expectedType.isPrimitive() ){ |
| if(expectedType == boolean.class) |
| return Boolean.FALSE; |
| else if( expectedType == byte.class ) |
| return DUMMY_BYTE; |
| else if( expectedType == char.class ) |
| return DUMMY_CHAR; |
| else if( expectedType == double.class) |
| return DUMMY_DOUBLE; |
| else if( expectedType == float.class ) |
| return DUMMY_FLOAT; |
| else if( expectedType == int.class ) |
| return DUMMY_INTEGER; |
| else if( expectedType == long.class ) |
| return DUMMY_LONG; |
| else if(expectedType == short.class) |
| return DUMMY_SHORT; |
| else // expectedType == void.class. can this happen? |
| return DUMMY_INTEGER; // anything would work |
| } |
| else |
| return null; |
| } |
| |
| /** |
| * This method is designed to be invoke by the invocation handler and anywhere that requires |
| * a AnnotationValue (AnnotationMirror member values and default values from anonotation member). |
| * |
| * Regardless of the path, there are common primitive type conversion that needs to take place. |
| * The type conversions are respects the type widening and narrowing rules from JLS 5.1.2 and 5.1.2. |
| * |
| * The only question remains is what is the type of the return value when the type conversion fails? * |
| * When <code>avoidReflectException</code> is set to <code>true</code> |
| * Return <code>false</code> if the expected type is <code>boolean</code> |
| * Return numeric 0 for all numeric primitive types and '0' for <code>char</code> |
| * |
| * Otherwise: |
| * Return the value unchanged. |
| * |
| * In the invocation handler case: |
| * The value returned by {@link java.lang.reflect.InvocationHandler#invoke} |
| * will be converted into the expected type by the {@link java.lang.reflect.Proxy}. |
| * If the value and the expected type does not agree, and the value is not null, |
| * a ClassCastException will be thrown. A NullPointerException will be resulted if the |
| * expected type is a primitive type and the value is null. |
| * This behavior is currently causing annotation processor a lot of pain and the decision is |
| * to not throw such unchecked exception. In the case where a ClassCastException or |
| * NullPointerException will be thrown return some dummy value. Otherwise, return |
| * the original value. |
| * Chosen dummy values: |
| * Return <code>false</code> if the expected type is <code>boolean</code> |
| * Return numeric 0 for all numeric primitive types and '0' for <code>char</code> |
| * |
| * This behavior is triggered by setting <code>avoidReflectException</code> to <code>true</code> |
| * |
| * Note: the new behavior deviates from what's documented in |
| * {@link java.lang.reflect.InvocationHandler#invoke} and also deviates from |
| * Sun's implementation. |
| * |
| * see CR260743 and 260563. |
| * @param value the current value from the annotation instance. |
| * @param expectedType the expected type of the value. |
| * |
| */ |
| public static Object performNecessaryPrimitiveTypeConversion( |
| final Class<?> expectedType, |
| final Object value, |
| final boolean avoidReflectException) |
| { |
| assert expectedType.isPrimitive() : "expectedType is not a primitive type: " + expectedType.getName(); //$NON-NLS-1$ |
| if( value == null) |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : null; |
| // apply widening conversion based on JLS 5.1.2 and 5.1.3 |
| final String typeName = expectedType.getName(); |
| final char expectedTypeChar = typeName.charAt(0); |
| final int nameLen = typeName.length(); |
| // widening byte -> short, int, long, float or double |
| // narrowing byte -> char |
| if( value instanceof Byte ) |
| { |
| final byte b = ((Byte)value).byteValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': |
| if(nameLen == 4) // byte |
| return value; // exact match. |
| else |
| return avoidReflectException ? Boolean.FALSE : value; |
| case 'c': |
| return new Character((char)b); // narrowing. |
| case 'd': |
| return new Double(b); // widening. |
| case 'f': |
| return new Float(b); // widening. |
| case 'i': |
| return new Integer(b); // widening. |
| case 'l': |
| return new Long(b); // widening. |
| case 's': |
| return new Short(b); // widening. |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| // widening short -> int, long, float, or double |
| // narrowing short -> byte or char |
| else if( value instanceof Short ) |
| { |
| final short s = ((Short)value).shortValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': |
| if(nameLen == 4) // byte |
| return new Byte((byte)s); // narrowing. |
| else |
| return avoidReflectException ? Boolean.FALSE : value; // completely wrong. |
| case 'c': |
| return new Character((char)s); // narrowing. |
| case 'd': |
| return new Double(s); // widening. |
| case 'f': |
| return new Float(s); // widening. |
| case 'i': |
| return new Integer(s); // widening. |
| case 'l': |
| return new Long(s); // widening. |
| case 's': |
| return value; // exact match |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| // widening char -> int, long, float, or double |
| // narrowing char -> byte or short |
| else if( value instanceof Character ) |
| { |
| final char c = ((Character)value).charValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': |
| if(nameLen == 4) // byte |
| return new Byte((byte)c); // narrowing. |
| else |
| return avoidReflectException ? Boolean.FALSE : value; // completely wrong. |
| case 'c': |
| return value; // exact match |
| case 'd': |
| return new Double(c); // widening. |
| case 'f': |
| return new Float(c); // widening. |
| case 'i': |
| return new Integer(c); // widening. |
| case 'l': |
| return new Long(c); // widening. |
| case 's': |
| return new Short((short)c); // narrowing. |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| |
| // widening int -> long, float, or double |
| // narrowing int -> byte, short, or char |
| else if( value instanceof Integer ) |
| { |
| final int i = ((Integer)value).intValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': |
| if(nameLen == 4) // byte |
| return new Byte((byte)i); // narrowing. |
| else |
| return avoidReflectException ? Boolean.FALSE : value; // completely wrong. |
| case 'c': |
| return new Character((char)i); // narrowing |
| case 'd': |
| return new Double(i); // widening. |
| case 'f': |
| return new Float(i); // widening. |
| case 'i': |
| return value; // exact match |
| case 'l': |
| return new Long(i); // widening. |
| case 's': |
| return new Short((short)i); // narrowing. |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| // widening long -> float or double |
| else if( value instanceof Long ) |
| { |
| final long l = ((Long)value).longValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': // both byte and boolean |
| case 'c': |
| case 'i': |
| case 's': |
| // completely wrong. |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : value; |
| case 'd': |
| return new Double(l); // widening. |
| case 'f': |
| return new Float(l); // widening. |
| case 'l': |
| return value; // exact match. |
| |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| |
| // widening float -> double |
| else if( value instanceof Float ) |
| { |
| final float f = ((Float)value).floatValue(); |
| switch( expectedTypeChar ) |
| { |
| case 'b': // both byte and boolean |
| case 'c': |
| case 'i': |
| case 's': |
| case 'l': |
| // completely wrong. |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : value; |
| case 'd': |
| return new Double(f); // widening. |
| case 'f': |
| return value; // exact match. |
| default: |
| throw new IllegalStateException("unknown type " + expectedTypeChar); //$NON-NLS-1$ |
| } |
| } |
| else if( value instanceof Double ){ |
| if(expectedTypeChar == 'd' ) |
| return value; // exact match |
| else{ |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong. |
| } |
| } |
| else if( value instanceof Boolean ){ |
| if( expectedTypeChar == 'b' && nameLen == 7) // "boolean".length() == 7 |
| return value; |
| else |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : value; // completely wrong. |
| } |
| else // can't convert |
| return avoidReflectException ? getMatchingDummyValue(expectedType) : value; |
| } |
| |
| private static Class<?> getJavaLangClass_Primitive(final PrimitiveType primitiveType){ |
| switch( primitiveType.getKind() ){ |
| case BOOLEAN: return boolean.class; |
| case BYTE: return byte.class; |
| case CHAR: return char.class; |
| case DOUBLE: return double.class; |
| case FLOAT: return float.class; |
| case INT: return int.class; |
| case LONG: return long.class; |
| case SHORT: return short.class; |
| default: |
| throw new IllegalStateException("unknow primitive type " + primitiveType ); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Apply type conversion according to JLS 5.1.2 and 5.1.3 and / or auto-boxing. |
| * @param expectedType the expected type |
| * @param value the value where conversion may be applied to |
| * @param name name of the member value |
| * @param parent the of the annotation of the member value |
| * @param env |
| * @return the value matching the expected type or itself if no conversion can be applied. |
| */ |
| private static Object performNecessaryTypeConversion(final TypeMirror expectedType, |
| final Object value, |
| final String name, |
| final EclipseMirrorObject parent, |
| final BaseProcessorEnv env) |
| { |
| if( expectedType == null )return value; |
| if( expectedType instanceof PrimitiveType ) |
| { |
| final Class<?> primitiveClass = getJavaLangClass_Primitive( (PrimitiveType)expectedType ); |
| return performNecessaryPrimitiveTypeConversion(primitiveClass, value, false); |
| } |
| // handle auto-boxing |
| else if( expectedType instanceof ArrayType) |
| { |
| final TypeMirror componentType = ((ArrayType)expectedType).getComponentType(); |
| Object converted = value; |
| // if it is an error case, will just leave it as is. |
| if( !(componentType instanceof ArrayType ) ) |
| converted = performNecessaryTypeConversion(componentType, value, name, parent, env); |
| |
| final AnnotationValue annoValue = createAnnotationValueFromDOMValue(converted, name, 0, parent, env); |
| return Collections.singletonList(annoValue); |
| } |
| else // no change |
| return value; |
| } |
| |
| public static InterfaceType createErrorInterfaceType(final ITypeBinding binding) |
| { |
| String name = null == binding ? NULL_BINDING_NAME : binding.getName(); |
| return new ErrorType.ErrorInterface(name); |
| } |
| |
| public static ClassType createErrorClassType(final ITypeBinding binding) |
| { |
| String name = null == binding ? NULL_BINDING_NAME : binding.getName(); |
| return createErrorClassType(name); |
| } |
| |
| public static ClassType createErrorClassType(final String name) |
| { |
| return new ErrorType.ErrorClass(name); |
| } |
| |
| public static AnnotationType createErrorAnnotationType(final ITypeBinding binding) |
| { |
| String name = null == binding ? NULL_BINDING_NAME : binding.getName(); |
| return createErrorAnnotationType(name); |
| } |
| |
| public static AnnotationType createErrorAnnotationType(String name) |
| { |
| return new ErrorType.ErrorAnnotation(name); |
| } |
| |
| public static ArrayType createErrorArrayType(final String name, final int dimension) |
| { |
| return new ErrorType.ErrorArrayType(name, dimension); |
| } |
| } |