Skip to content

Instantly share code, notes, and snippets.

@johncarl81
Last active August 29, 2015 14:22
Show Gist options
  • Save johncarl81/46306590cbdde5a3003f to your computer and use it in GitHub Desktop.
Save johncarl81/46306590cbdde5a3003f to your computer and use it in GitHub Desktop.
public class AnnotationProcessorOutputAssertion {
public @interface Target {}
public interface TestTarget {
String get();
}
@Test
public void testCompileAnnotationProcessorOutput() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
final MemoryFileManager manager = new MemoryFileManager(compiler);
Set<Source> input = new HashSet<Source>();
input.add(new Source("Test", JavaFileObject.Kind.SOURCE,
"public @" + Target.class.getCanonicalName() + " class Test{}"
));
JavaCompiler.CompilationTask task = compiler.getTask(null, manager, null, null, null, input);
task.setProcessors(Collections.singleton(new TargetProcessor()));
task.call();
ClassLoader loader = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
Source mc = manager.map.remove(name);
if (mc != null) {
byte[] array = mc.toByteArray();
return defineClass(name, array, 0, array.length);
}
return super.findClass(name);
}
};
TestTarget testTarget = (TestTarget) loader.loadClass("ProcessedTest").newInstance();
assertEquals("Hello", testTarget.get());
}
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
private static class TargetProcessor extends AbstractProcessor {
private Filer filer;
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
filer = processingEnv.getFiler();
}
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
try {
for (Element typeElement : roundEnv.getRootElements()) {
if (typeElement.getAnnotation(Target.class) != null) {
JavaFileObject output = filer.createSourceFile("Processed" + typeElement.getSimpleName());
String sourceString =
"public class Processed" + typeElement.getSimpleName()
+ " implements " + TestTarget.class.getCanonicalName() + " {"
+ "public String get() { return \"Hello\"; }"
+ "}";
OutputStream outputStream = output.openOutputStream();
outputStream.write(sourceString.getBytes());
outputStream.flush();
outputStream.close();
}
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
return false;
}
}
private static class Source extends SimpleJavaFileObject {
private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Source(String name, JavaFileObject.Kind kind) {
super(URI.create("memo:///" + name.replace('.', '/') + kind.extension), kind);
}
Source(String name, Kind kind, String content) throws IOException {
this(name, kind);
outputStream.write(content.getBytes());
}
byte[] toByteArray() {
return this.outputStream.toByteArray();
}
public ByteArrayOutputStream openOutputStream() {
return this.outputStream;
}
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
return new String(toByteArray());
}
}
private static class MemoryFileManager extends ForwardingJavaFileManager<JavaFileManager> {
public final Map<String, Source> map = new HashMap<String, Source>();
MemoryFileManager(JavaCompiler compiler) {
super(compiler.getStandardFileManager(null, null, null));
}
public Source getJavaFileForOutput(JavaFileManager.Location location, String name, JavaFileObject.Kind kind, FileObject source) {
Source mc = new Source(name, kind);
map.put(name, mc);
return mc;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment