/******************************************************************************* * Copyright (c) 2005, 2014 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 * het@google.com - Bug 441790 *******************************************************************************/ package org.eclipse.jdt.apt.core.internal.declaration; import java.util.Collection; import java.util.List; import com.sun.mirror.declaration.AnnotationValue; import com.sun.mirror.declaration.EnumConstantDeclaration; import com.sun.mirror.type.TypeMirror; import com.sun.mirror.util.SourcePosition; import org.eclipse.core.resources.IFile; import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv; import org.eclipse.jdt.apt.core.internal.util.SourcePositionImpl; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.ArrayInitializer; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.internal.compiler.util.Util; public class AnnotationValueImpl implements EclipseMirrorObject, AnnotationValue { /** * Either the annotation that directly contains this annotation value * or an annotation method, which indicates that this is its default value. */ private EclipseMirrorObject _parent; private final BaseProcessorEnv _env; /** the annotation value */ private final Object _value; /** * The name of the element if this is a value from an annotation member value. * <code>null</code> otherwise */ private final String _name; /** * If this is part of an array, then the index into the array. * <code>-1</code> when this doesn't apply */ private final int _index; /** * * @param value the default value of an annotation element declaration * @param element the annotation element declaration. * @param index zero-based index into the array if the this value is an array element. * <code>-1</code> otherwise. * @param env */ public AnnotationValueImpl( final Object value, final int index, final AnnotationElementDeclarationImpl element, final BaseProcessorEnv env) { _value = value; _env = env; _parent = element; _name = null; _index = index; assert _env != null : "missing environment"; //$NON-NLS-1$ assert _parent != null : "missing element"; //$NON-NLS-1$ } /** * * @param value the annotation value * @param name the name of the element member * @param index zero-based index into the array if the this value is an array element. * <code>-1</code> otherwise. * @param annotation the annotation containing this value * @param env */ public AnnotationValueImpl( final Object value, final String name, final int index, final AnnotationMirrorImpl annotation, final BaseProcessorEnv env) { assert value != null : "value is null"; //$NON-NLS-1$ _value = value; _env = env; _parent = annotation; _name = name; _index = index; assert _env != null : "missing environment"; //$NON-NLS-1$ assert _parent != null : "missing element"; //$NON-NLS-1$ } @SuppressWarnings("rawtypes") // DOM AST API returns raw collections public SourcePosition getPosition() { final MirrorKind kind = _parent.kind(); ASTNode astNode = null; switch(kind) { case ANNOTATION_MIRROR: final AnnotationMirrorImpl anno = (AnnotationMirrorImpl)_parent; astNode = anno.getASTNodeForElement(_name); break; case ANNOTATION_ELEMENT: final AnnotationElementDeclarationImpl element = (AnnotationElementDeclarationImpl)_parent; astNode = element.getAstNodeForDefault(); break; default: throw new IllegalStateException(); // should never reach this point. } // did not come from source. if( astNode == null ) return null; if( _index >= 0 && astNode.getNodeType() == ASTNode.ARRAY_INITIALIZER ){ final ArrayInitializer arrayInit = (ArrayInitializer)astNode; final List exprs = arrayInit.expressions(); if (exprs != null && _index < exprs.size() ) astNode = (ASTNode)exprs.get(_index); } if( astNode == null ) return null; final CompilationUnit unit = getCompilationUnit(); if( unit == null ) return null; final int offset = astNode.getStartPosition(); return new SourcePositionImpl(astNode.getStartPosition(), astNode.getLength(), unit.getLineNumber(offset), unit.getColumnNumber(offset), this); } CompilationUnit getCompilationUnit() { final MirrorKind kind = _parent.kind(); switch(kind) { case ANNOTATION_MIRROR: return ((AnnotationMirrorImpl)_parent).getCompilationUnit(); case ANNOTATION_ELEMENT: if( ((EclipseDeclarationImpl)_parent).isBindingBased() ) return ((AnnotationElementDeclarationImpl)_parent).getCompilationUnit(); else return ((ASTBasedAnnotationElementDeclarationImpl)_parent).getCompilationUnit(); default: throw new IllegalStateException(); // should never reach this point. } } public boolean isFromSource() { final MirrorKind kind = _parent.kind(); switch(kind) { case ANNOTATION_MIRROR: return ((AnnotationMirrorImpl)_parent).isFromSource(); case ANNOTATION_ELEMENT: if( ((EclipseDeclarationImpl)_parent).isBindingBased() ) return ((AnnotationElementDeclarationImpl)_parent).isFromSource(); else return ((ASTBasedAnnotationElementDeclarationImpl)_parent).isFromSource(); default: throw new IllegalStateException(); // should never reach this point. } } public IFile getResource() { final MirrorKind kind = _parent.kind(); switch(kind) { case ANNOTATION_MIRROR: return ((AnnotationMirrorImpl)_parent).getResource(); case ANNOTATION_ELEMENT: if( ((EclipseDeclarationImpl)_parent).isBindingBased() ) return ((AnnotationElementDeclarationImpl)_parent).getResource(); else return ((ASTBasedAnnotationElementDeclarationImpl)_parent).getResource(); default: throw new IllegalStateException(); // should never reach this point. } } public Object getValue(){ return _value; } public MirrorKind kind(){ return MirrorKind.ANNOTATION_VALUE; } public BaseProcessorEnv getEnvironment(){ return _env; } @Override public String toString() { if (_value == null) { return "null"; //$NON-NLS-1$ } else if (_value instanceof String) { String value = (String) _value; StringBuffer sb = new StringBuffer(); sb.append('"'); for (int i = 0; i < value.length(); i++) { Util.appendEscapedChar(sb, value.charAt(i), true); } sb.append('"'); return sb.toString(); } else if (_value instanceof Character) { StringBuffer sb = new StringBuffer(); sb.append('\''); Util.appendEscapedChar(sb, ((Character) _value).charValue(), false); sb.append('\''); return sb.toString(); } else if (_value instanceof EnumConstantDeclaration) { EnumConstantDeclaration enumDecl = (EnumConstantDeclaration) _value; return enumDecl.getDeclaringType().toString() + "." + enumDecl.getSimpleName(); //$NON-NLS-1$ } else if (_value instanceof Collection) { // It must be Collection<AnnotationValue> @SuppressWarnings("unchecked") Collection<AnnotationValue> values = (Collection<AnnotationValue>) _value; StringBuilder sb = new StringBuilder(); sb.append('{'); boolean first = true; for (AnnotationValue annoValue : values) { if (!first) { sb.append(", "); //$NON-NLS-1$ } first = false; sb.append(annoValue.toString()); } sb.append('}'); return sb.toString(); } else if (_value instanceof TypeMirror) { return _value.toString() + ".class"; //$NON-NLS-1$ } else { return _value.toString(); } } }