| /******************************************************************************* |
| * Copyright (c) 2005, 2007 IBM Corporation and others. |
| * 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.compiler.apt.model; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| |
| import javax.lang.model.element.AnnotationMirror; |
| import javax.lang.model.element.AnnotationValue; |
| import javax.lang.model.element.AnnotationValueVisitor; |
| import javax.lang.model.element.VariableElement; |
| import javax.lang.model.type.TypeMirror; |
| |
| import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl; |
| import org.eclipse.jdt.internal.compiler.impl.Constant; |
| import org.eclipse.jdt.internal.compiler.impl.DoubleConstant; |
| import org.eclipse.jdt.internal.compiler.impl.FloatConstant; |
| import org.eclipse.jdt.internal.compiler.impl.LongConstant; |
| import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.ElementValuePair; |
| import org.eclipse.jdt.internal.compiler.lookup.FieldBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; |
| import org.eclipse.jdt.internal.compiler.lookup.TypeIds; |
| import org.eclipse.jdt.internal.compiler.problem.ShouldNotImplement; |
| |
| public class AnnotationValueImpl implements AnnotationValue, TypeIds { |
| |
| /* |
| * Additions to T_* constants in TypeIds. |
| */ |
| private static final int T_AnnotationMirror = -1; |
| private static final int T_EnumConstant = -2; |
| private static final int T_ClassObject = -3; |
| private static final int T_ArrayType = -4; |
| |
| private final BaseProcessingEnvImpl _env; |
| |
| /** |
| * The annotation value, as it would be returned by |
| * {@link #getValue()}. For instance, an Integer (for an int |
| * constant), a VariableElement (for an enum constant), or |
| * a List<AnnotationValueImpl> containing multiple such (for an array type). |
| */ |
| private final Object _value; |
| |
| /** |
| * The type stored in _value, represented as a T_* value from {@link TypeIds} |
| * or one of the additional T_* values defined in this class. |
| */ |
| private final int _kind; |
| |
| /** |
| * @param value |
| * The JDT representation of a compile-time constant. See |
| * {@link ElementValuePair#getValue()} for possible object types: |
| * <ul> |
| * <li>{@link org.eclipse.jdt.internal.compiler.impl.Constant} for member |
| * of primitive type or String</li> |
| * <li>{@link TypeBinding} for a member value of type |
| * {@link java.lang.Class}</li> |
| * <li>{@link FieldBinding} for an enum constant</li> |
| * <li>{@link AnnotationBinding} for an annotation instance</li> |
| * <li><code>Object[]</code> for a member value of array type, where the |
| * array entries are one of the above</li> |
| * </ul> |
| * @param type |
| * The JDT representation of the type of the constant, as determined |
| * by the return type of the element. This is needed because the type |
| * of the value may have been widened (e.g., byte to int) by the compiler |
| * and we need to call the proper visitor. This is used only for base types. |
| * If it is null or not a BaseTypeBinding, it is ignored and the type is |
| * determined from the type of the value. |
| */ |
| public AnnotationValueImpl(BaseProcessingEnvImpl env, Object value, TypeBinding type) { |
| _env = env; |
| int kind[] = new int[1]; |
| if (type == null) { |
| _value = convertToMirrorType(value, type, kind); |
| _kind = kind[0]; |
| } else if (type.isArrayType()) { |
| List<AnnotationValue> convertedValues = null; |
| TypeBinding valueType = ((ArrayBinding)type).elementsType(); |
| if (value instanceof Object[]) { |
| Object[] values = (Object[])value; |
| convertedValues = new ArrayList<AnnotationValue>(values.length); |
| for (Object oneValue : values) { |
| convertedValues.add(new AnnotationValueImpl(_env, oneValue, valueType)); |
| } |
| } else { |
| convertedValues = new ArrayList<AnnotationValue>(1); |
| convertedValues.add(new AnnotationValueImpl(_env, value, valueType)); |
| } |
| _value = Collections.unmodifiableList(convertedValues); |
| _kind = T_ArrayType; |
| } else { |
| _value = convertToMirrorType(value, type, kind); |
| _kind = kind[0]; |
| } |
| } |
| |
| /** |
| * Convert the JDT representation of a single constant into its javax.lang.model |
| * representation. For instance, convert a StringConstant into a String, or |
| * a FieldBinding into a VariableElement. This does not handle the case where |
| * value is an Object[]. |
| * @param value the JDT object |
| * @param type the return type of the annotation member. If null or not a |
| * BaseTypeBinding, this is ignored and the value is inspected to determine type. |
| * @param kind an int array whose first element will be set to the type of the |
| * converted object, represented with T_* values from TypeIds or from this class. |
| * @return |
| */ |
| private Object convertToMirrorType(Object value, TypeBinding type, int kind[]) { |
| if (type == null) { |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } else if (type instanceof BaseTypeBinding || type.id == TypeIds.T_JavaLangString) { |
| if (value == null) { |
| if (type instanceof BaseTypeBinding |
| || type.id == TypeIds.T_JavaLangString) { |
| // return a string with error in it to reflect a value that could not be resolved |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } else if (type.isAnnotationType()) { |
| kind[0] = T_AnnotationMirror; |
| return _env.getFactory().newAnnotationMirror(null); |
| } |
| } else if (value instanceof Constant) { |
| if (type instanceof BaseTypeBinding) { |
| kind[0] = ((BaseTypeBinding)type).id; |
| } |
| else if (type.id == TypeIds.T_JavaLangString) { |
| kind[0] = ((Constant)value).typeID(); |
| } else { |
| // error case |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } |
| switch (kind[0]) { |
| case T_boolean: |
| return ((Constant)value).booleanValue(); |
| case T_byte: |
| return ((Constant)value).byteValue(); |
| case T_char: |
| return ((Constant)value).charValue(); |
| case T_double: |
| return ((Constant)value).doubleValue(); |
| case T_float: |
| return ((Constant)value).floatValue(); |
| case T_int: |
| try { |
| if (value instanceof LongConstant |
| || value instanceof DoubleConstant |
| || value instanceof FloatConstant) { |
| // error case |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } |
| return ((Constant)value).intValue(); |
| } catch (ShouldNotImplement e) { |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } |
| case T_JavaLangString: |
| return ((Constant)value).stringValue(); |
| case T_long: |
| return ((Constant)value).longValue(); |
| case T_short: |
| return ((Constant)value).shortValue(); |
| } |
| } |
| } else if (type.isEnum()) { |
| if (value instanceof FieldBinding) { |
| kind[0] = T_EnumConstant; |
| return (VariableElement) _env.getFactory().newElement((FieldBinding) value); |
| } else { |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } |
| } else if (type.isAnnotationType()) { |
| if (value instanceof AnnotationBinding) { |
| kind[0] = T_AnnotationMirror; |
| return _env.getFactory().newAnnotationMirror((AnnotationBinding) value); |
| } |
| } else if (value instanceof TypeBinding) { |
| kind[0] = T_ClassObject; |
| return _env.getFactory().newTypeMirror((TypeBinding) value); |
| } |
| // error case |
| kind[0] = TypeIds.T_JavaLangString; |
| return "<error>"; //$NON-NLS-1$ |
| } |
| |
| @SuppressWarnings("unchecked") // Need to cast Object _value to a List<AnnotationValue> |
| @Override |
| public <R, P> R accept(AnnotationValueVisitor<R, P> v, P p) { |
| switch (_kind) { |
| case TypeIds.T_boolean: |
| return v.visitBoolean((Boolean)_value, p); |
| case TypeIds.T_byte: |
| return v.visitByte((Byte)_value, p); |
| case TypeIds.T_char: |
| return v.visitChar((Character)_value, p); |
| case TypeIds.T_double: |
| return v.visitDouble((Double)_value, p); |
| case TypeIds.T_float: |
| return v.visitFloat((Float)_value, p); |
| case TypeIds.T_int: |
| return v.visitInt((Integer)_value, p); |
| case TypeIds.T_JavaLangString: |
| return v.visitString((String)_value, p); |
| case TypeIds.T_long: |
| return v.visitLong((Long)_value, p); |
| case TypeIds.T_short: |
| return v.visitShort((Short)_value, p); |
| case T_EnumConstant: |
| return v.visitEnumConstant((VariableElement)_value, p); |
| case T_ClassObject: |
| return v.visitType((TypeMirror)_value, p); |
| case T_AnnotationMirror: |
| return v.visitAnnotation((AnnotationMirror)_value, p); |
| case T_ArrayType: |
| return v.visitArray((List<AnnotationValue>)_value, p); |
| default: |
| return null; |
| } |
| } |
| |
| @Override |
| public Object getValue() { |
| return _value; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (obj instanceof AnnotationValueImpl) { |
| return this._value.equals(((AnnotationValueImpl) obj)._value); |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| return this._value.hashCode() + this._kind; |
| } |
| |
| @Override |
| public String toString() { |
| if (null == _value) { |
| return "null"; //$NON-NLS-1$ |
| } |
| return _value.toString(); |
| } |
| } |