/**
* Copyright © 2006-2016 Web Cohesion (info@webcohesion.com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.webcohesion.enunciate.javac.decorations.element;
import com.webcohesion.enunciate.javac.decorations.DecoratedProcessingEnvironment;
import com.webcohesion.enunciate.javac.decorations.ElementDecoration;
import com.webcohesion.enunciate.javac.decorations.ElementDecorator;
import com.webcohesion.enunciate.javac.decorations.TypeMirrorDecorator;
import com.webcohesion.enunciate.javac.javadoc.DefaultJavaDocTagHandler;
import com.webcohesion.enunciate.javac.javadoc.JavaDoc;
import com.webcohesion.enunciate.javac.javadoc.JavaDocTagHandler;
import javax.lang.model.element.*;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("unchecked")
public class DecoratedElement<E extends Element> implements Element {
protected final E delegate;
protected final DecoratedProcessingEnvironment env;
private final HashMap<JavaDocTagHandler, JavaDoc> javaDocs = new HashMap<JavaDocTagHandler, JavaDoc>();
private TypeMirror type;
private Element enclosingElement;
private List<? extends Element> enclosedElements;
private List<AnnotationMirror> annotationMirrors;
private Map<String, AnnotationMirror> annotations = null;
public DecoratedElement(E delegate, DecoratedProcessingEnvironment env) {
this.delegate = delegate;
this.env = env;
if (this.env.getElementDecorations() != null) {
for (ElementDecoration elementDecoration : this.env.getElementDecorations()) {
elementDecoration.applyTo(this, this.env);
}
}
}
/**
* Whether the declaration is <code>public</code>.
*
* @return Whether the declaration is <code>public</code>.
*/
public boolean isPublic() {
return getModifiers().contains(javax.lang.model.element.Modifier.PUBLIC);
}
/**
* Whether the declaration is <code>protected</code>.
*
* @return Whether the declaration is <code>protected</code>.
*/
public boolean isProtected() {
return getModifiers().contains(Modifier.PROTECTED);
}
/**
* Whether the declaration is <code>private</code>.
*
* @return Whether the declaration is <code>private</code>.
*/
public boolean isPrivate() {
return getModifiers().contains(Modifier.PRIVATE);
}
/**
* Whether the declaration is <code>abstract</code>.
*
* @return Whether the declaration is <code>abstract</code>.
*/
public boolean isAbstract() {
return getModifiers().contains(Modifier.ABSTRACT);
}
/**
* Whether the declaration is <code>static</code>.
*
* @return Whether the declaration is <code>static</code>.
*/
public boolean isStatic() {
return getModifiers().contains(Modifier.STATIC);
}
/**
* Whether the declaration is <code>final</code>.
*
* @return Whether the declaration is <code>final</code>.
*/
public boolean isFinal() {
return getModifiers().contains(Modifier.FINAL);
}
/**
* Whether the declaration is <code>transient</code>.
*
* @return Whether the declaration is <code>transient</code>.
*/
public boolean isTransient() {
return getModifiers().contains(Modifier.TRANSIENT);
}
/**
* Whether the declaration is <code>volatile</code>.
*
* @return Whether the declaration is <code>volatile</code>.
*/
public boolean isVolatile() {
return getModifiers().contains(Modifier.VOLATILE);
}
/**
* Whether the declaration is <code>synchronized</code>.
*
* @return Whether the declaration is <code>synchronized</code>.
*/
public boolean isSynchronized() {
return getModifiers().contains(Modifier.SYNCHRONIZED);
}
/**
* Whether the declaration is <code>native</code>.
*
* @return Whether the declaration is <code>native</code>.
*/
public boolean isNative() {
return getModifiers().contains(Modifier.NATIVE);
}
/**
* Whether the declaration is <code>strictfp</code>.
*
* @return Whether the declaration is <code>strictfp</code>.
*/
public boolean isStrictfp() {
return getModifiers().contains(Modifier.STRICTFP);
}
public String getDocComment() {
return this.env.getElementUtils().getDocComment(this.delegate);
}
/**
* The javadoc for this declaration with the default tag handler.
*
* @return The javadoc for this declaration with the default tag handler.
*/
public final JavaDoc getJavaDoc() {
return getJavaDoc(DefaultJavaDocTagHandler.INSTANCE);
}
/**
* Get the JavaDoc for this element for the given tag handler.
*
* @param tagHandler The tag handler.
* @return The javadoc.
*/
public final JavaDoc getJavaDoc(JavaDocTagHandler tagHandler) {
return getJavaDoc(tagHandler, true);
}
protected JavaDoc getJavaDoc(JavaDocTagHandler tagHandler, boolean useDelegate) {
if (useDelegate && this.delegate instanceof DecoratedElement) {
//if the delegate is decorated, we assume that the extension
//intends the delegate to be the comment-holder. This is
//important in order to correctly calculate inherited javadocs.
//However, it makes overriding tricky because if you override
//'getDocComment', you have to also override this method lest
//the JavaDoc be out of sync with the doc comment.
return ((DecoratedElement) this.delegate).getJavaDoc(tagHandler);
}
JavaDoc javaDoc = this.javaDocs.get(tagHandler);
if (javaDoc == null) {
javaDoc = new JavaDoc(getDocComment(), tagHandler, this, this.env);
this.javaDocs.put(tagHandler, javaDoc);
}
return javaDoc;
}
/**
* The value of the java doc, before the block tags.
*
* @return The value of the java doc, before the block tags, or null if the value is the empty string.
*/
public final String getDocValue() {
return getDocValue(DefaultJavaDocTagHandler.INSTANCE);
}
/**
* The value of the java doc, before the block tags.
*
* @param tagHandler The tag handler.
* @return The value of the java doc, before the block tags, or null if the value is the empty string.
*/
public final String getDocValue(JavaDocTagHandler tagHandler) {
String value = getJavaDoc(tagHandler).toString();
if (value != null) {
value = value.trim();
if ("".equals(value)) {
value = null;
}
}
return value;
}
/**
* A map of annotations for this declaration.
*
* @return A map of annotations for this declaration.
*/
public Map<String, AnnotationMirror> getAnnotations() {
if (this.annotations == null) {
this.annotations = new HashMap<String, AnnotationMirror>();
for (AnnotationMirror annotationMirror : getAnnotationMirrors()) {
DeclaredType annotationType = annotationMirror.getAnnotationType();
if ((annotationType != null) && (annotationType.asElement() instanceof TypeElement)) {
annotations.put(((TypeElement)annotationType.asElement()).getQualifiedName().toString(), annotationMirror);
}
}
}
return this.annotations;
}
@Override
public TypeMirror asType() {
if (this.type == null) {
this.type = TypeMirrorDecorator.decorate(delegate.asType(), env);
}
return this.type;
}
@Override
public ElementKind getKind() {
return this.delegate.getKind();
}
@Override
public Element getEnclosingElement() {
if (this.enclosingElement == null) {
this.enclosingElement = ElementDecorator.decorate(delegate.getEnclosingElement(), env);
}
return this.enclosingElement;
}
@Override
public List<? extends Element> getEnclosedElements() {
if (this.enclosedElements == null) {
this.enclosedElements = ElementDecorator.decorate(delegate.getEnclosedElements(), env);
}
return this.enclosedElements;
}
@Override
public <R, P> R accept(ElementVisitor<R, P> v, P p) {
return v.visitUnknown(this, p);
}
//Inherited.
public List<? extends AnnotationMirror> getAnnotationMirrors() {
if (this.annotationMirrors == null) {
this.annotationMirrors = ElementDecorator.decorateAnnotationMirrors(delegate.getAnnotationMirrors(), env);
}
return this.annotationMirrors;
}
public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
return this.delegate.getAnnotation(annotationType);
}
//Inherited.
public Set<Modifier> getModifiers() {
return this.delegate.getModifiers();
}
//Inherited.
public Name getSimpleName() {
return this.delegate.getSimpleName();
}
public E getDelegate() {
return this.delegate;
}
//Inherited.
public boolean equals(Object obj) {
if (obj instanceof DecoratedElement) {
return equals(((DecoratedElement) obj).delegate);
}
Element delegate = this.delegate;
while (delegate instanceof DecoratedElement) {
delegate = ((DecoratedElement) delegate).delegate;
}
return delegate.equals(obj);
}
//Inherited.
public String toString() {
return this.delegate.toString();
}
}