diff options
Diffstat (limited to 'build/annotationProcessors/AnnotationProcessor.java')
-rw-r--r-- | build/annotationProcessors/AnnotationProcessor.java | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/build/annotationProcessors/AnnotationProcessor.java b/build/annotationProcessors/AnnotationProcessor.java new file mode 100644 index 000000000..4f53317cd --- /dev/null +++ b/build/annotationProcessors/AnnotationProcessor.java @@ -0,0 +1,175 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.annotationProcessors; + +import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; +import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions; +import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader; +import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; + +public class AnnotationProcessor { + public static final String GENERATED_COMMENT = + "// GENERATED CODE\n" + + "// Generated by the Java program at /build/annotationProcessors at compile time\n" + + "// from annotations on Java methods. To update, change the annotations on the\n" + + "// corresponding Java methods and rerun the build. Manually updating this file\n" + + "// will cause your build to fail.\n" + + "\n"; + + private static final StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT); + private static final StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT); + private static final StringBuilder nativesFile = new StringBuilder(GENERATED_COMMENT); + + public static void main(String[] args) { + // We expect a list of jars on the commandline. If missing, whinge about it. + if (args.length <= 2) { + System.err.println("Usage: java AnnotationProcessor outprefix jarfiles ..."); + System.exit(1); + } + + final String OUTPUT_PREFIX = args[0]; + final String SOURCE_FILE = OUTPUT_PREFIX + "JNIWrappers.cpp"; + final String HEADER_FILE = OUTPUT_PREFIX + "JNIWrappers.h"; + final String NATIVES_FILE = OUTPUT_PREFIX + "JNINatives.h"; + + System.out.println("Processing annotations..."); + + // We want to produce the same output as last time as often as possible. Ordering of + // generated statements, therefore, needs to be consistent. + final String[] jars = Arrays.copyOfRange(args, 1, args.length); + Arrays.sort(jars); + + // Start the clock! + long s = System.currentTimeMillis(); + + // Get an iterator over the classes in the jar files given... + Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(jars); + + headerFile.append( + "#ifndef " + getHeaderGuardName(HEADER_FILE) + "\n" + + "#define " + getHeaderGuardName(HEADER_FILE) + "\n" + + "\n" + + "#include \"mozilla/jni/Refs.h\"\n" + + "\n" + + "namespace mozilla {\n" + + "namespace java {\n" + + "\n"); + + implementationFile.append( + "#include \"" + HEADER_FILE + "\"\n" + + "#include \"mozilla/jni/Accessors.h\"\n" + + "\n" + + "namespace mozilla {\n" + + "namespace java {\n" + + "\n"); + + nativesFile.append( + "#ifndef " + getHeaderGuardName(NATIVES_FILE) + "\n" + + "#define " + getHeaderGuardName(NATIVES_FILE) + "\n" + + "\n" + + "#include \"" + HEADER_FILE + "\"\n" + + "#include \"mozilla/jni/Natives.h\"\n" + + "\n" + + "namespace mozilla {\n" + + "namespace java {\n" + + "\n"); + + while (jarClassIterator.hasNext()) { + generateClass(jarClassIterator.next()); + } + + implementationFile.append( + "} /* java */\n" + + "} /* mozilla */\n"); + + headerFile.append( + "} /* java */\n" + + "} /* mozilla */\n" + + "#endif // " + getHeaderGuardName(HEADER_FILE) + "\n"); + + nativesFile.append( + "} /* java */\n" + + "} /* mozilla */\n" + + "#endif // " + getHeaderGuardName(NATIVES_FILE) + "\n"); + + writeOutputFile(SOURCE_FILE, implementationFile); + writeOutputFile(HEADER_FILE, headerFile); + writeOutputFile(NATIVES_FILE, nativesFile); + + long e = System.currentTimeMillis(); + System.out.println("Annotation processing complete in " + (e - s) + "ms"); + } + + private static void generateClass(final ClassWithOptions annotatedClass) { + // Get an iterator over the appropriately generated methods of this class + final GeneratableElementIterator methodIterator + = new GeneratableElementIterator(annotatedClass); + final ClassWithOptions[] innerClasses = methodIterator.getInnerClasses(); + + if (!methodIterator.hasNext() && innerClasses.length == 0) { + return; + } + + final CodeGenerator generatorInstance = new CodeGenerator(annotatedClass); + generatorInstance.generateClasses(innerClasses); + + // Iterate all annotated members in this class.. + while (methodIterator.hasNext()) { + AnnotatableEntity aElementTuple = methodIterator.next(); + switch (aElementTuple.mEntityType) { + case METHOD: + generatorInstance.generateMethod(aElementTuple); + break; + case NATIVE: + generatorInstance.generateNative(aElementTuple); + break; + case FIELD: + generatorInstance.generateField(aElementTuple); + break; + case CONSTRUCTOR: + generatorInstance.generateConstructor(aElementTuple); + break; + } + } + + headerFile.append(generatorInstance.getHeaderFileContents()); + implementationFile.append(generatorInstance.getWrapperFileContents()); + nativesFile.append(generatorInstance.getNativesFileContents()); + + for (ClassWithOptions innerClass : innerClasses) { + generateClass(innerClass); + } + } + + private static String getHeaderGuardName(final String name) { + return name.replaceAll("\\W", "_"); + } + + private static void writeOutputFile(final String name, + final StringBuilder content) { + FileOutputStream outStream = null; + try { + outStream = new FileOutputStream(name); + outStream.write(content.toString().getBytes()); + } catch (IOException e) { + System.err.println("Unable to write " + name + ". Perhaps a permissions issue?"); + e.printStackTrace(System.err); + } finally { + if (outStream != null) { + try { + outStream.close(); + } catch (IOException e) { + System.err.println("Unable to close outStream due to "+e); + e.printStackTrace(System.err); + } + } + } + } +} |