improve annotation processor

This commit is contained in:
Sebastian Sdorra
2014-03-28 20:38:36 +01:00
parent 812021f212
commit 93dc44b729
4 changed files with 144 additions and 19 deletions

View File

@@ -47,7 +47,7 @@ import java.lang.annotation.Target;
*/ */
@Documented @Documented
@Target({ ElementType.TYPE }) @Target({ ElementType.TYPE })
@PluginAnnotation("extension-points") @PluginAnnotation("extension-point")
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface ExtensionPoint public @interface ExtensionPoint
{ {

View File

@@ -51,6 +51,6 @@ import java.lang.annotation.Target;
*/ */
@Documented @Documented
@Target({ ElementType.TYPE }) @Target({ ElementType.TYPE })
@PluginAnnotation("extensions") @PluginAnnotation("extension")
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface Extension {} public @interface Extension {}

View File

@@ -36,6 +36,11 @@ package sonia.scm.annotation;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
//~--- JDK imports ------------------------------------------------------------
import java.util.Map;
import java.util.Map.Entry;
/** /**
* *
* @author Sebastian Sdorra * @author Sebastian Sdorra
@@ -55,7 +60,8 @@ public class ClassSetElement implements DescriptorElement
* @param elementName * @param elementName
* @param classes * @param classes
*/ */
public ClassSetElement(String elementName, Iterable<String> classes) public ClassSetElement(String elementName,
Iterable<ClassWithAttributes> classes)
{ {
this.elementName = elementName; this.elementName = elementName;
this.classes = classes; this.classes = classes;
@@ -73,23 +79,67 @@ public class ClassSetElement implements DescriptorElement
@Override @Override
public void append(Document doc, Element root) public void append(Document doc, Element root)
{ {
Element element = doc.createElement(elementName);
for (String c : classes) for (ClassWithAttributes c : classes)
{ {
Element element = doc.createElement(elementName);
Element classEl = doc.createElement(EL_CLASS); Element classEl = doc.createElement(EL_CLASS);
classEl.setTextContent(c); classEl.setTextContent(c.className);
for (Entry<String, String> e : c.attributes.entrySet())
{
Element attr = doc.createElement(e.getKey());
attr.setTextContent(e.getValue());
element.appendChild(attr);
}
element.appendChild(classEl); element.appendChild(classEl);
root.appendChild(element);
} }
root.appendChild(element);
} }
//~--- inner classes --------------------------------------------------------
/**
* Class description
*
*
* @version Enter version here..., 14/03/18
* @author Enter your name here...
*/
public static class ClassWithAttributes
{
/**
* Constructs ...
*
*
* @param className
* @param attributes
*/
public ClassWithAttributes(String className, Map<String, String> attributes)
{
this.className = className;
this.attributes = attributes;
}
//~--- fields -------------------------------------------------------------
/** Field description */
private final Map<String, String> attributes;
/** Field description */
private final String className;
}
//~--- fields --------------------------------------------------------------- //~--- fields ---------------------------------------------------------------
/** Field description */ /** Field description */
private final Iterable<String> classes; private final Iterable<ClassWithAttributes> classes;
/** Field description */ /** Field description */
private final String elementName; private final String elementName;

View File

@@ -37,12 +37,14 @@ import com.github.legman.Subscribe;
import com.google.common.base.Throwables; import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import org.kohsuke.MetaInfServices; import org.kohsuke.MetaInfServices;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import sonia.scm.annotation.ClassSetElement.ClassWithAttributes;
import sonia.scm.plugin.PluginAnnotation; import sonia.scm.plugin.PluginAnnotation;
//~--- JDK imports ------------------------------------------------------------ //~--- JDK imports ------------------------------------------------------------
@@ -58,6 +60,8 @@ import java.io.Writer;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set; import java.util.Set;
import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.AbstractProcessor;
@@ -68,6 +72,8 @@ import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element; import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind; import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.ExecutableElement;
@@ -115,8 +121,8 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
/** Field description */ /** Field description */
private static final Set<ClassAnnotation> CLASS_ANNOTATIONS = private static final Set<ClassAnnotation> CLASS_ANNOTATIONS =
ImmutableSet.of(new ClassAnnotation("jaxrs-resources", Path.class), ImmutableSet.of(new ClassAnnotation("jaxrs-resource", Path.class),
new ClassAnnotation("jaxrs-providers", Provider.class)); new ClassAnnotation("jaxrs-provider", Provider.class));
//~--- methods -------------------------------------------------------------- //~--- methods --------------------------------------------------------------
@@ -144,8 +150,7 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
if (pa != null) if (pa != null)
{ {
scanForClassAnnotations(descriptorElements, pa.value(), scanForClassAnnotations(descriptorElements, roundEnv, e, pa.value());
roundEnv.getElementsAnnotatedWith(e));
} }
if (SUBSCRIBE_ANNOTATIONS.contains(e.getQualifiedName().toString())) if (SUBSCRIBE_ANNOTATIONS.contains(e.getQualifiedName().toString()))
@@ -156,8 +161,14 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
for (ClassAnnotation ca : CLASS_ANNOTATIONS) for (ClassAnnotation ca : CLASS_ANNOTATIONS)
{ {
scanForClassAnnotations(descriptorElements, ca.elementName, TypeElement annotation = findAnnotation(annotations,
roundEnv.getElementsAnnotatedWith(ca.annotationClass)); ca.annotationClass);
if (annotation != null)
{
scanForClassAnnotations(descriptorElements, roundEnv, annotation,
ca.elementName);
}
} }
for (TypeElement annotation : subscriberAnnotations) for (TypeElement annotation : subscriberAnnotations)
@@ -193,6 +204,33 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
} }
} }
/**
* Method description
*
*
* @param annotations
* @param annotationClass
*
* @return
*/
private TypeElement findAnnotation(Set<? extends TypeElement> annotations,
Class<? extends Annotation> annotationClass)
{
TypeElement annotation = null;
for (TypeElement te : annotations)
{
if (te.getQualifiedName().toString().equals(annotationClass.getName()))
{
annotation = te;
break;
}
}
return annotation;
}
/** /**
* Method description * Method description
* *
@@ -283,24 +321,27 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
* *
* *
* @param descriptorElements * @param descriptorElements
* @param roundEnv
* @param annotation
* @param elementName * @param elementName
* @param elements * @param elements
* *
* @return * @return
*/ */
private void scanForClassAnnotations( private void scanForClassAnnotations(
Set<DescriptorElement> descriptorElements, String elementName, Set<DescriptorElement> descriptorElements, RoundEnvironment roundEnv,
Set<? extends Element> elements) TypeElement annotation, String elementName)
{ {
Set<String> classes = Sets.newHashSet(); Set<ClassWithAttributes> classes = Sets.newHashSet();
for (Element e : elements) for (Element e : roundEnv.getElementsAnnotatedWith(annotation))
{ {
if (e.getKind().isClass() || e.getKind().isInterface()) if (e.getKind().isClass() || e.getKind().isInterface())
{ {
TypeElement type = (TypeElement) e; TypeElement type = (TypeElement) e;
classes.add(type.getQualifiedName().toString()); classes.add(new ClassWithAttributes(type.getQualifiedName().toString(),
getAttributesFromAnnotation(e, annotation)));
} }
} }
@@ -405,6 +446,40 @@ public final class ScmAnnotationProcessor extends AbstractProcessor
} }
} }
//~--- get methods ----------------------------------------------------------
/**
* Method description
*
*
* @param el
* @param annotation
*
* @return
*/
private Map<String, String> getAttributesFromAnnotation(Element el,
TypeElement annotation)
{
Map<String, String> attributes = Maps.newHashMap();
for (AnnotationMirror am : el.getAnnotationMirrors())
{
String qn = am.getAnnotationType().asElement().toString();
if (qn.equals(annotation.toString()))
{
for (Entry<? extends ExecutableElement,
? extends AnnotationValue> entry : am.getElementValues().entrySet())
{
attributes.put(entry.getKey().getSimpleName().toString(),
entry.getValue().getValue().toString());
}
}
}
return attributes;
}
//~--- inner classes -------------------------------------------------------- //~--- inner classes --------------------------------------------------------
/** /**