build/annotationProcessors/utils/GeneratableElementIterator.java

changeset 0
6474c204b198
     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 +}

mercurial