Skip to content

Commit 2db381b

Browse files
committed
Add a Java 6-compliant annotation processor
This is loosely modeled after the way SezPoz does it, for the obvious reasons: SezPoz' goals and the goals of this here annotation indexer are almost the same. Therefore, this developer learnt a lot from inspecting the source code of SezPoz' Indexer6 class and then went on to re-implement the part that inspects the AnnotationMirror instances here. Since we are building an annotation processor here, we need to switch off annotation processing during the compilation. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
1 parent 4b03603 commit 2db381b

File tree

3 files changed

+252
-0
lines changed

3 files changed

+252
-0
lines changed

pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@
3535

3636
<build>
3737
<plugins>
38+
<plugin>
39+
<groupId>org.apache.maven.plugins</groupId>
40+
<artifactId>maven-compiler-plugin</artifactId>
41+
<configuration>
42+
<compilerArgument>-proc:none</compilerArgument>
43+
</configuration>
44+
</plugin>
3845
<plugin>
3946
<artifactId>maven-jar-plugin</artifactId>
4047
<version>2.4</version>
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
/*
2+
* #%L
3+
* Annotation index (processor and index access library).
4+
* %%
5+
* Copyright (C) 2009 - 2013 Board of Regents of the University of Wisconsin-Madison.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
*
28+
* The views and conclusions contained in the software and documentation are
29+
* those of the authors and should not be interpreted as representing official
30+
* policies, either expressed or implied, of any organization.
31+
* #L%
32+
*/
33+
34+
package org.scijava.annotations;
35+
36+
import java.io.ByteArrayOutputStream;
37+
import java.io.FileNotFoundException;
38+
import java.io.IOException;
39+
import java.io.InputStream;
40+
import java.io.OutputStream;
41+
import java.io.PrintStream;
42+
import java.util.ArrayList;
43+
import java.util.HashMap;
44+
import java.util.List;
45+
import java.util.Map;
46+
import java.util.Map.Entry;
47+
import java.util.Set;
48+
import java.util.TreeMap;
49+
50+
import javax.annotation.processing.AbstractProcessor;
51+
import javax.annotation.processing.Filer;
52+
import javax.annotation.processing.RoundEnvironment;
53+
import javax.annotation.processing.SupportedAnnotationTypes;
54+
import javax.annotation.processing.SupportedSourceVersion;
55+
import javax.lang.model.SourceVersion;
56+
import javax.lang.model.element.AnnotationMirror;
57+
import javax.lang.model.element.AnnotationValue;
58+
import javax.lang.model.element.Element;
59+
import javax.lang.model.element.ExecutableElement;
60+
import javax.lang.model.element.Name;
61+
import javax.lang.model.element.TypeElement;
62+
import javax.lang.model.element.VariableElement;
63+
import javax.lang.model.type.TypeMirror;
64+
import javax.lang.model.util.Elements;
65+
import javax.lang.model.util.Types;
66+
import javax.tools.Diagnostic.Kind;
67+
import javax.tools.StandardLocation;
68+
69+
import org.scijava.annotations.AbstractIndexWriter.StreamFactory;
70+
71+
/**
72+
* The annotation processor for use with Java 6 and above.
73+
*
74+
* @author Johannes Schindelin
75+
*/
76+
@SupportedSourceVersion(SourceVersion.RELEASE_6)
77+
@SupportedAnnotationTypes("*")
78+
@SuppressWarnings("restriction")
79+
public class AnnotationProcessor extends AbstractProcessor {
80+
81+
private RoundEnvironment roundEnv;
82+
83+
@Override
84+
public boolean process(final Set<? extends TypeElement> elements,
85+
final RoundEnvironment env)
86+
{
87+
roundEnv = env;
88+
89+
final Writer writer = new Writer();
90+
for (final TypeElement element : elements) {
91+
writer.add(element);
92+
}
93+
try {
94+
writer.write(writer);
95+
}
96+
catch (IOException e) {
97+
final ByteArrayOutputStream out = new ByteArrayOutputStream();
98+
e.printStackTrace(new PrintStream(out));
99+
try {
100+
out.close();
101+
processingEnv.getMessager().printMessage(Kind.ERROR, out.toString());
102+
}
103+
catch (IOException e2) {
104+
processingEnv.getMessager().printMessage(Kind.ERROR,
105+
e2.getMessage() + " while printing " + e.getMessage());
106+
}
107+
}
108+
return false;
109+
}
110+
111+
private class Writer extends AbstractIndexWriter implements StreamFactory {
112+
113+
private final Map<String, List<Element>> originatingElements =
114+
new HashMap<String, List<Element>>();
115+
private final Filer filer = processingEnv.getFiler();
116+
private final Elements utils = processingEnv.getElementUtils();
117+
private final Types typeUtils = processingEnv.getTypeUtils();
118+
119+
public void add(final TypeElement element) {
120+
final AnnotationMirror mirror = getMirror(element);
121+
if (mirror != null) {
122+
final String annotationName = utils.getBinaryName(element).toString();
123+
124+
// remember originating elements
125+
List<Element> originating = originatingElements.get(annotationName);
126+
if (originating == null) {
127+
originating = new ArrayList<Element>();
128+
originatingElements.put(annotationName, originating);
129+
}
130+
131+
for (final Element annotated : roundEnv
132+
.getElementsAnnotatedWith(element))
133+
{
134+
switch (annotated.getKind()) {
135+
case ANNOTATION_TYPE:
136+
case CLASS:
137+
case ENUM:
138+
case INTERFACE:
139+
final String className =
140+
utils.getBinaryName((TypeElement) annotated).toString();
141+
final Map<String, Object> values =
142+
adapt(annotated.getAnnotationMirrors(), element.asType());
143+
super.add(values, annotationName, className);
144+
originating.add(annotated);
145+
break;
146+
default:
147+
processingEnv.getMessager().printMessage(
148+
Kind.ERROR,
149+
"Cannot handle annotated element of kind " +
150+
annotated.getKind());
151+
}
152+
}
153+
}
154+
//
155+
}
156+
157+
@SuppressWarnings("unchecked")
158+
private Map<String, Object> adapt(List<? extends AnnotationMirror> mirrors,
159+
TypeMirror annotationType)
160+
{
161+
final Map<String, Object> result = new TreeMap<String, Object>();
162+
for (final AnnotationMirror mirror : mirrors) {
163+
if (typeUtils.isSameType(mirror.getAnnotationType(), annotationType)) {
164+
return (Map<String, Object>) adapt(mirror);
165+
}
166+
}
167+
return result;
168+
}
169+
170+
protected Object adapt(final Object o) {
171+
if (o instanceof AnnotationMirror) {
172+
final AnnotationMirror mirror = (AnnotationMirror) o;
173+
final Map<String, Object> result = new TreeMap<String, Object>();
174+
for (final Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : mirror
175+
.getElementValues().entrySet())
176+
{
177+
final String key = entry.getKey().getSimpleName().toString();
178+
final Object value = adapt(entry.getValue().getValue());
179+
result.put(key, value);
180+
}
181+
return result;
182+
}
183+
else if (o instanceof List) {
184+
final List<?> list = (List<?>) o;
185+
final List<Object> result = new ArrayList<Object>(list.size());
186+
for (final Object item : list) {
187+
result.add(adapt(item));
188+
}
189+
return result;
190+
}
191+
else if (o instanceof TypeMirror) {
192+
final TypeMirror mirror = (TypeMirror) o;
193+
return utils.getBinaryName((TypeElement) typeUtils.asElement(mirror))
194+
.toString();
195+
}
196+
else if (o instanceof VariableElement) {
197+
final VariableElement element = (VariableElement) o;
198+
final Map<String, Object> result = new TreeMap<String, Object>();
199+
final String enumName =
200+
utils.getBinaryName((TypeElement) element.getEnclosingElement())
201+
.toString();
202+
final String valueName = element.getSimpleName().toString();
203+
result.put("enum", enumName);
204+
result.put("value", valueName);
205+
return result;
206+
}
207+
else {
208+
return super.adapt(o);
209+
}
210+
}
211+
212+
private AnnotationMirror getMirror(final TypeElement element) {
213+
for (AnnotationMirror candidate : utils.getAllAnnotationMirrors(element))
214+
{
215+
final Name binaryName =
216+
utils.getBinaryName((TypeElement) candidate.getAnnotationType()
217+
.asElement());
218+
if (binaryName.contentEquals(Indexable.class.getName())) {
219+
return candidate;
220+
}
221+
}
222+
return null;
223+
}
224+
225+
public InputStream openInput(String annotationName) throws IOException {
226+
try {
227+
return filer.getResource(StandardLocation.CLASS_OUTPUT, "",
228+
Index.INDEX_PREFIX + annotationName).openInputStream();
229+
}
230+
catch (final FileNotFoundException e) {
231+
return null;
232+
}
233+
}
234+
235+
public OutputStream openOutput(String annotationName) throws IOException {
236+
final List<Element> originating = originatingElements.get(annotationName);
237+
return filer.createResource(StandardLocation.CLASS_OUTPUT, "",
238+
Index.INDEX_PREFIX + annotationName,
239+
originating.toArray(new Element[originating.size()]))
240+
.openOutputStream();
241+
}
242+
243+
}
244+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.scijava.annotations.AnnotationProcessor

0 commit comments

Comments
 (0)