Currently, when we generate JNI wrapper for an inner class, the resulting C++ class will not actually be a nested class of the enclosing class. As a result, the class can be confusing to use. For example, wrapping Java class GeckoThread.State results in two unrelated C++ classes, GeckoThread and State, and it'd be confusing to use State by itself. This patch adds support for inner classes. We start by scanning only for top-level classes, and when processing each top-level class, we recursively scan for inner classes through JarClassIterator.getInnerClasses() and CodeGenerator.generateClasses(). For each Java inner classes, the resulting C++ class will be a nested class. For example, wrapping GeckoThread.State will produce widget::GeckoThread and widget::GeckoThread::State.
63 lines
2.2 KiB
Java
63 lines
2.2 KiB
Java
/* 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.
|
|
*/
|
|
public class JarClassIterator implements Iterator<ClassWithOptions> {
|
|
private IterableJarLoadingURLClassLoader mTarget;
|
|
private Iterator<String> mTargetClassListIterator;
|
|
|
|
public JarClassIterator(IterableJarLoadingURLClassLoader aTarget) {
|
|
mTarget = aTarget;
|
|
mTargetClassListIterator = aTarget.classNames.iterator();
|
|
}
|
|
|
|
@Override
|
|
public boolean hasNext() {
|
|
return mTargetClassListIterator.hasNext();
|
|
}
|
|
|
|
@Override
|
|
public ClassWithOptions next() {
|
|
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 next();
|
|
}
|
|
|
|
if (enclosingClass != null) {
|
|
// Anonymous inner class - unsupported.
|
|
// Or named inner class, which will be processed when we process the outer class.
|
|
return next();
|
|
}
|
|
|
|
return new ClassWithOptions(ret, ret.getSimpleName());
|
|
} catch (ClassNotFoundException e) {
|
|
System.err.println("Unable to enumerate class: " + className + ". Corrupted jar file?");
|
|
e.printStackTrace();
|
|
System.exit(2);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void remove() {
|
|
throw new UnsupportedOperationException("Removal of classes from iterator not supported.");
|
|
}
|
|
}
|