1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/build/annotationProcessors/utils/GeneratableElementIterator.java Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,155 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +package org.mozilla.gecko.annotationProcessors.utils; 1.9 + 1.10 +import org.mozilla.gecko.annotationProcessors.AnnotationInfo; 1.11 +import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity; 1.12 + 1.13 +import java.lang.annotation.Annotation; 1.14 +import java.lang.reflect.AnnotatedElement; 1.15 +import java.lang.reflect.InvocationTargetException; 1.16 +import java.lang.reflect.Member; 1.17 +import java.lang.reflect.Method; 1.18 +import java.util.Arrays; 1.19 +import java.util.Iterator; 1.20 + 1.21 +/** 1.22 + * Iterator over the methods in a given method list which have the WrappedJNIMethod 1.23 + * annotation. Returns an object containing both the annotation (Which may contain interesting 1.24 + * parameters) and the argument. 1.25 + */ 1.26 +public class GeneratableElementIterator implements Iterator<AnnotatableEntity> { 1.27 + private final Member[] mObjects; 1.28 + private AnnotatableEntity mNextReturnValue; 1.29 + private int mElementIndex; 1.30 + 1.31 + private boolean mIterateEveryEntry; 1.32 + 1.33 + public GeneratableElementIterator(Class<?> aClass) { 1.34 + // Get all the elements of this class as AccessibleObjects. 1.35 + Member[] aMethods = aClass.getDeclaredMethods(); 1.36 + Member[] aFields = aClass.getDeclaredFields(); 1.37 + Member[] aCtors = aClass.getConstructors(); 1.38 + 1.39 + // Shove them all into one buffer. 1.40 + Member[] objs = new Member[aMethods.length + aFields.length + aCtors.length]; 1.41 + 1.42 + int offset = 0; 1.43 + System.arraycopy(aMethods, 0, objs, 0, aMethods.length); 1.44 + offset += aMethods.length; 1.45 + System.arraycopy(aFields, 0, objs, offset, aFields.length); 1.46 + offset += aFields.length; 1.47 + System.arraycopy(aCtors, 0, objs, offset, aCtors.length); 1.48 + 1.49 + // Sort the elements to ensure determinism. 1.50 + Arrays.sort(objs, new AlphabeticAnnotatableEntityComparator()); 1.51 + mObjects = objs; 1.52 + 1.53 + // Check for "Wrap ALL the things" flag. 1.54 + for (Annotation annotation : aClass.getDeclaredAnnotations()) { 1.55 + final String annotationTypeName = annotation.annotationType().getName(); 1.56 + if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapEntireClassForJNI")) { 1.57 + mIterateEveryEntry = true; 1.58 + break; 1.59 + } 1.60 + } 1.61 + 1.62 + findNextValue(); 1.63 + } 1.64 + 1.65 + /** 1.66 + * Find and cache the next appropriately annotated method, plus the annotation parameter, if 1.67 + * one exists. Otherwise cache null, so hasNext returns false. 1.68 + */ 1.69 + private void findNextValue() { 1.70 + while (mElementIndex < mObjects.length) { 1.71 + Member candidateElement = mObjects[mElementIndex]; 1.72 + mElementIndex++; 1.73 + for (Annotation annotation : ((AnnotatedElement) candidateElement).getDeclaredAnnotations()) { 1.74 + // WrappedJNIMethod has parameters. Use Reflection to obtain them. 1.75 + Class<? extends Annotation> annotationType = annotation.annotationType(); 1.76 + final String annotationTypeName = annotationType.getName(); 1.77 + if (annotationTypeName.equals("org.mozilla.gecko.mozglue.generatorannotations.WrapElementForJNI")) { 1.78 + String stubName = null; 1.79 + boolean isStaticStub = false; 1.80 + boolean isMultithreadedStub = false; 1.81 + boolean noThrow = false; 1.82 + try { 1.83 + // Determine the explicitly-given name of the stub to generate, if any. 1.84 + final Method stubNameMethod = annotationType.getDeclaredMethod("stubName"); 1.85 + stubNameMethod.setAccessible(true); 1.86 + stubName = (String) stubNameMethod.invoke(annotation); 1.87 + 1.88 + // Detemine if the generated stub should be static. 1.89 + final Method staticStubMethod = annotationType.getDeclaredMethod("generateStatic"); 1.90 + staticStubMethod.setAccessible(true); 1.91 + isStaticStub = (Boolean) staticStubMethod.invoke(annotation); 1.92 + 1.93 + // Determine if the generated stub is to allow calls from multiple threads. 1.94 + final Method multithreadedStubMethod = annotationType.getDeclaredMethod("allowMultithread"); 1.95 + multithreadedStubMethod.setAccessible(true); 1.96 + isMultithreadedStub = (Boolean) multithreadedStubMethod.invoke(annotation); 1.97 + 1.98 + // Determine if ignoring exceptions 1.99 + final Method noThrowMethod = annotationType.getDeclaredMethod("noThrow"); 1.100 + noThrowMethod.setAccessible(true); 1.101 + noThrow = (Boolean) noThrowMethod.invoke(annotation); 1.102 + 1.103 + } catch (NoSuchMethodException e) { 1.104 + System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?"); 1.105 + e.printStackTrace(System.err); 1.106 + System.exit(3); 1.107 + } catch (IllegalAccessException e) { 1.108 + System.err.println("IllegalAccessException reading fields on WrapElementForJNI annotation. Seems the semantics of Reflection have changed..."); 1.109 + e.printStackTrace(System.err); 1.110 + System.exit(4); 1.111 + } catch (InvocationTargetException e) { 1.112 + System.err.println("InvocationTargetException reading fields on WrapElementForJNI annotation. This really shouldn't happen."); 1.113 + e.printStackTrace(System.err); 1.114 + System.exit(5); 1.115 + } 1.116 + 1.117 + // If the method name was not explicitly given in the annotation generate one... 1.118 + if (stubName.isEmpty()) { 1.119 + String aMethodName = candidateElement.getName(); 1.120 + stubName = aMethodName.substring(0, 1).toUpperCase() + aMethodName.substring(1); 1.121 + } 1.122 + 1.123 + AnnotationInfo annotationInfo = new AnnotationInfo( 1.124 + stubName, isStaticStub, isMultithreadedStub, noThrow); 1.125 + mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); 1.126 + return; 1.127 + } 1.128 + } 1.129 + 1.130 + // If no annotation found, we might be expected to generate anyway using default arguments, 1.131 + // thanks to the "Generate everything" annotation. 1.132 + if (mIterateEveryEntry) { 1.133 + AnnotationInfo annotationInfo = new AnnotationInfo( 1.134 + candidateElement.getName(), false, false, false); 1.135 + mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo); 1.136 + return; 1.137 + } 1.138 + } 1.139 + mNextReturnValue = null; 1.140 + } 1.141 + 1.142 + @Override 1.143 + public boolean hasNext() { 1.144 + return mNextReturnValue != null; 1.145 + } 1.146 + 1.147 + @Override 1.148 + public AnnotatableEntity next() { 1.149 + AnnotatableEntity ret = mNextReturnValue; 1.150 + findNextValue(); 1.151 + return ret; 1.152 + } 1.153 + 1.154 + @Override 1.155 + public void remove() { 1.156 + throw new UnsupportedOperationException("Removal of methods from GeneratableElementIterator not supported."); 1.157 + } 1.158 +}