diff options
Diffstat (limited to 'build/annotationProcessors/classloader/JarClassIterator.java')
-rw-r--r-- | build/annotationProcessors/classloader/JarClassIterator.java | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/build/annotationProcessors/classloader/JarClassIterator.java b/build/annotationProcessors/classloader/JarClassIterator.java new file mode 100644 index 000000000..452de8131 --- /dev/null +++ b/build/annotationProcessors/classloader/JarClassIterator.java @@ -0,0 +1,84 @@ +/* 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.classloader; + +import java.util.Iterator; + +/** + * Class for iterating over an IterableJarLoadingURLClassLoader's classes. + * + * This class is not thread safe: use it only from a single thread. + */ +public class JarClassIterator implements Iterator<ClassWithOptions> { + private IterableJarLoadingURLClassLoader mTarget; + private Iterator<String> mTargetClassListIterator; + + private ClassWithOptions lookAhead; + + public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) { + mTarget = aTarget; + mTargetClassListIterator = aTarget.classNames.iterator(); + } + + @Override + public boolean hasNext() { + return fillLookAheadIfPossible(); + } + + @Override + public ClassWithOptions next() { + if (!fillLookAheadIfPossible()) { + throw new IllegalStateException("Failed to look ahead in next()!"); + } + ClassWithOptions next = lookAhead; + lookAhead = null; + return next; + } + + private boolean fillLookAheadIfPossible() { + if (lookAhead != null) { + return true; + } + + if (!mTargetClassListIterator.hasNext()) { + return false; + } + + String className = mTargetClassListIterator.next(); + try { + Class<?> ret = mTarget.loadClass(className); + + // Incremental builds can leave stale classfiles in the jar. Such classfiles will cause + // an exception at this point. We can safely ignore these classes - they cannot possibly + // ever be loaded as they conflict with their parent class and will be killed by + // Proguard later on anyway. + final Class<?> enclosingClass; + try { + enclosingClass = ret.getEnclosingClass(); + } catch (IncompatibleClassChangeError e) { + return fillLookAheadIfPossible(); + } + + if (enclosingClass != null) { + // Anonymous inner class - unsupported. + // Or named inner class, which will be processed when we process the outer class. + return fillLookAheadIfPossible(); + } + + lookAhead = new ClassWithOptions(ret, ret.getSimpleName()); + return true; + } catch (ClassNotFoundException e) { + System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?"); + e.printStackTrace(); + System.exit(2); + } + return false; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("Removal of classes from iterator not supported."); + } +} |