Bug 1280666 - Allow class annotations to set defaults for members when generating Java bindings r=jchen

This commit is contained in:
James Willcox 2016-06-29 13:42:05 -07:00 коммит произвёл Randall Barker
Родитель 89c51f72ce
Коммит 718f23f9d0
3 изменённых файлов: 107 добавлений и 66 удалений

Просмотреть файл

@ -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,19 +116,13 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
return ret;
}
/**
* Find and cache the next appropriately annotated method, plus the annotation parameter, if
* one exists. Otherwise cache null, so hasNext returns false.
*/
private void findNextValue() {
while (mElementIndex < mObjects.length) {
Member candidateElement = mObjects[mElementIndex];
mElementIndex++;
for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
// WrappedJNIMethod has parameters. Use Reflection to obtain them.
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")) {
if (!annotationTypeName.equals("org.mozilla.gecko.annotation.WrapForJNI")) {
return null;
}
String stubName = null;
boolean isMultithreadedStub = false;
boolean noThrow = false;
@ -139,10 +134,16 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
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");
@ -175,12 +176,25 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
// If the method name was not explicitly given in the annotation generate one...
if (stubName.isEmpty()) {
stubName = Utils.getNativeName(candidateElement);
stubName = Utils.getNativeName(element);
}
AnnotationInfo annotationInfo = new AnnotationInfo(
return new AnnotationInfo(
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
}
/**
* Find and cache the next appropriately annotated method, plus the annotation parameter, if
* one exists. Otherwise cache null, so hasNext returns false.
*/
private void findNextValue() {
while (mElementIndex < mObjects.length) {
Member candidateElement = mObjects[mElementIndex];
mElementIndex++;
for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) {
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;