mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 1280666 - Allow class annotations to set defaults for members when generating Java bindings r=jchen
This commit is contained in:
parent
89c51f72ce
commit
718f23f9d0
@ -27,6 +27,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
private final Member[] mObjects;
|
||||
private AnnotatableEntity mNextReturnValue;
|
||||
private int mElementIndex;
|
||||
private AnnotationInfo mClassInfo;
|
||||
|
||||
private boolean mIterateEveryEntry;
|
||||
|
||||
@ -55,8 +56,8 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
|
||||
// Check for "Wrap ALL the things" flag.
|
||||
for (Annotation annotation : aClass.getDeclaredAnnotations()) {
|
||||
final String annotationTypeName = annotation.annotationType().getName();
|
||||
if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
mClassInfo = buildAnnotationInfo(aClass, annotation);
|
||||
if (mClassInfo != null) {
|
||||
mIterateEveryEntry = true;
|
||||
break;
|
||||
}
|
||||
@ -115,6 +116,73 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private AnnotationInfo buildAnnotationInfo(AnnotatedElement element, Annotation annotation) {
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final String annotationTypeName = annotationType.getName();
|
||||
if (!annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String stubName = null;
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
boolean catchException = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
stubNameMethod.setAccessible(true);
|
||||
stubName = (String) stubNameMethod.invoke(annotation);
|
||||
|
||||
if (element instanceof Class<?>) {
|
||||
// Make @WrapForJNI always allow multithread by default, individual methods can then
|
||||
// override with their own annotation
|
||||
isMultithreadedStub = true;
|
||||
} else {
|
||||
// Determine if the generated stub is to allow calls from multiple threads.
|
||||
final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
|
||||
multithreadedStubMethod.setAccessible(true);
|
||||
isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
|
||||
}
|
||||
|
||||
// Determine if ignoring exceptions
|
||||
final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
|
||||
noThrowMethod.setAccessible(true);
|
||||
noThrow = (Boolean) noThrowMethod.invoke(annotation);
|
||||
|
||||
// Determine if strings should be wide or narrow
|
||||
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
// Determine if we should catch exceptions
|
||||
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
|
||||
catchExceptionMethod.setAccessible(true);
|
||||
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(3);
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(4);
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
// If the method name was not explicitly given in the annotation generate one...
|
||||
if (stubName.isEmpty()) {
|
||||
stubName = Utils.getNativeName(element);
|
||||
}
|
||||
|
||||
return new AnnotationInfo(
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and cache the next appropriately annotated method, plus the annotation parameter, if
|
||||
* one exists. Otherwise cache null, so hasNext returns false.
|
||||
@ -124,63 +192,9 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
Member candidateElement = mObjects[mElementIndex];
|
||||
mElementIndex++;
|
||||
for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
|
||||
// WrappedJNIMethod has parameters. Use Reflection to obtain them.
|
||||
Class<? extends Annotation> annotationType = annotation.annotationType();
|
||||
final String annotationTypeName = annotationType.getName();
|
||||
if (annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
|
||||
String stubName = null;
|
||||
boolean isMultithreadedStub = false;
|
||||
boolean noThrow = false;
|
||||
boolean narrowChars = false;
|
||||
boolean catchException = false;
|
||||
try {
|
||||
// Determine the explicitly-given name of the stub to generate, if any.
|
||||
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
|
||||
stubNameMethod.setAccessible(true);
|
||||
stubName = (String) stubNameMethod.invoke(annotation);
|
||||
|
||||
// Determine if the generated stub is to allow calls from multiple threads.
|
||||
final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread");
|
||||
multithreadedStubMethod.setAccessible(true);
|
||||
isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation);
|
||||
|
||||
// Determine if ignoring exceptions
|
||||
final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow");
|
||||
noThrowMethod.setAccessible(true);
|
||||
noThrow = (Boolean) noThrowMethod.invoke(annotation);
|
||||
|
||||
// Determine if strings should be wide or narrow
|
||||
final Method narrowCharsMethod = annotationType.getDeclaredMethod("narrowChars");
|
||||
narrowCharsMethod.setAccessible(true);
|
||||
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
|
||||
|
||||
// Determine if we should catch exceptions
|
||||
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
|
||||
catchExceptionMethod.setAccessible(true);
|
||||
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
|
||||
|
||||
} catch (NoSuchMethodException e) {
|
||||
System.err.println("Unable to find expected field on WrapForJNI annotation. Did the signature change?");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(3);
|
||||
} catch (IllegalAccessException e) {
|
||||
System.err.println("IllegalAccessException reading fields on WrapForJNI annotation. Seems the semantics of Reflection have changed...");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(4);
|
||||
} catch (InvocationTargetException e) {
|
||||
System.err.println("InvocationTargetException reading fields on WrapForJNI annotation. This really shouldn't happen.");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(5);
|
||||
}
|
||||
|
||||
// If the method name was not explicitly given in the annotation generate one...
|
||||
if (stubName.isEmpty()) {
|
||||
stubName = Utils.getNativeName(candidateElement);
|
||||
}
|
||||
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
AnnotationInfo info = buildAnnotationInfo((AnnotatedElement)candidateElement, annotation);
|
||||
if (info != null) {
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -190,10 +204,10 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
|
||||
if (mIterateEveryEntry) {
|
||||
AnnotationInfo annotationInfo = new AnnotationInfo(
|
||||
Utils.getNativeName(candidateElement),
|
||||
/* multithreaded */ true,
|
||||
/* noThrow */ false,
|
||||
/* narrowChars */ false,
|
||||
/* catchException */ false);
|
||||
mClassInfo.isMultithreaded,
|
||||
mClassInfo.noThrow,
|
||||
mClassInfo.narrowChars,
|
||||
mClassInfo.catchException);
|
||||
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
|
||||
return;
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package org.mozilla.gecko.annotationProcessors.utils;
|
||||
|
||||
import org.mozilla.gecko.annotationProcessors.AnnotationInfo;
|
||||
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Member;
|
||||
@ -212,6 +213,33 @@ public class Utils {
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the C++ name for a member.
|
||||
*
|
||||
* @param member Member to get the name for.
|
||||
* @return JNI name as a string
|
||||
*/
|
||||
public static String getNativeName(Class<?> clz) {
|
||||
final String name = clz.getName();
|
||||
return name.substring(0, 1).toUpperCase() + name.substring(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the C++ name for a member.
|
||||
*
|
||||
* @param member Member to get the name for.
|
||||
* @return JNI name as a string
|
||||
*/
|
||||
public static String getNativeName(AnnotatedElement element) {
|
||||
if (element instanceof Class<?>) {
|
||||
return getNativeName((Class<?>)element);
|
||||
} else if (element instanceof Member) {
|
||||
return getNativeName((Member)element);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JNI name for a member.
|
||||
*
|
||||
|
@ -31,9 +31,8 @@ public @interface WrapForJNI {
|
||||
|
||||
/**
|
||||
* If set, the generated method stub will support being called from any thread via the use of
|
||||
* GetEnvForThread. This is rarely useful, at time of writing, as well as possibly risky.
|
||||
*
|
||||
* Did I mention use of this function is discouraged?
|
||||
* GetEnvForThread. This is forced to 'true' when the annotation is used on a class, but can
|
||||
* be overridden for individual methods.
|
||||
*/
|
||||
boolean allowMultithread() default false;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user