Skip to content

Commit

Permalink
Jigsaw support: As we already load the class from Jigsaw as Class<?> …
Browse files Browse the repository at this point in the history
…instance, we don't need InputStream of bytecode. Just use reflective analysis to get methods and fields!
  • Loading branch information
uschindler committed May 22, 2016
1 parent a9c6e9b commit 95d9d55
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 19 deletions.
27 changes: 8 additions & 19 deletions src/main/java/de/thetaphi/forbiddenapis/Checker.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public static enum Option {
final Logger logger;

final ClassLoader loader;
final java.lang.reflect.Method method_Class_getModule, method_Module_getResourceAsStream, method_Module_getName;
final java.lang.reflect.Method method_Class_getModule, method_Module_getName;
final EnumSet<Option> options;

// key is the binary name (dotted):
Expand Down Expand Up @@ -131,19 +131,16 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {

// first try Java 9 module system (Jigsaw)
// Please note: This code is not guaranteed to work with final Java 9 version. This is just for testing!
java.lang.reflect.Method method_Class_getModule, method_Module_getResourceAsStream, method_Module_getName;
java.lang.reflect.Method method_Class_getModule, method_Module_getName;
try {
method_Class_getModule = Class.class.getMethod("getModule");
method_Module_getResourceAsStream = method_Class_getModule
.getReturnType().getMethod("getResourceAsStream", String.class);
method_Module_getName = method_Class_getModule
.getReturnType().getMethod("getName");
isSupportedJDK = true;
} catch (NoSuchMethodException e) {
method_Class_getModule = method_Module_getResourceAsStream = method_Module_getName = null;
method_Class_getModule = method_Module_getName = null;
}
this.method_Class_getModule = method_Class_getModule;
this.method_Module_getResourceAsStream = method_Module_getResourceAsStream;
this.method_Module_getName = method_Module_getName;

final NavigableSet<String> runtimePaths = new TreeSet<String>();
Expand Down Expand Up @@ -208,7 +205,7 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {
logger.warn("Bundled version of ASM cannot parse bytecode of java.lang.Object class; marking runtime as not suppported.");
isSupportedJDK = false;
} catch (ClassNotFoundException cnfe) {
logger.warn("Bytecode of java.lang.Object not found; marking runtime as not suppported.");
logger.warn("Bytecode or Class<?> instance of java.lang.Object not found; marking runtime as not suppported.");
isSupportedJDK = false;
} catch (IOException ioe) {
logger.warn("IOException while loading java.lang.Object class from classloader; marking runtime as not suppported: " + ioe);
Expand All @@ -226,29 +223,21 @@ public Checker(Logger logger, ClassLoader loader, EnumSet<Option> options) {
* This is just for testing!
**/
private ClassSignature loadClassFromJigsaw(String classname) throws IOException {
if (method_Class_getModule == null || method_Module_getResourceAsStream == null || method_Module_getName == null) {
if (method_Class_getModule == null || method_Module_getName == null) {
return null; // not Java 9 JIGSAW
}

final InputStream in;
final Class<?> clazz;
final String moduleName;
try {
final Class<?> clazz = Class.forName(classname, false, loader);
clazz = Class.forName(classname, false, loader);
final Object module = method_Class_getModule.invoke(clazz);
moduleName = (String) method_Module_getName.invoke(module);
in = (InputStream) method_Module_getResourceAsStream.invoke(module, AsmUtils.getClassResourceName(classname));
if (in == null) {
return null;
}
} catch (Exception e) {
return null; // not found
}

try {
return new ClassSignature(AsmUtils.readAndPatchClass(in), AsmUtils.isRuntimeModule(moduleName), false);
} finally {
in.close();
}
return new ClassSignature(clazz, AsmUtils.isRuntimeModule(moduleName));
}

private boolean isRuntimePath(URL url) throws IOException {
Expand Down
28 changes: 28 additions & 0 deletions src/main/java/de/thetaphi/forbiddenapis/ClassSignature.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ final class ClassSignature {
public final String className, superName;
public final String[] interfaces;

/** Builds the information from an ASM ClassReader */
public ClassSignature(final ClassReader classReader, boolean isRuntimeClass, boolean withReader) {
this.reader = withReader ? classReader : null;
this.isRuntimeClass = isRuntimeClass;
Expand All @@ -67,6 +68,33 @@ public FieldVisitor visitField(int access, String name, String desc, String sign
this.fields = Collections.unmodifiableSet(fields);
}

/** Alternative ctor that can be used to build the information via reflection from an already loaded class. Useful for Java 9 Jigsaw. */
public ClassSignature(final Class<?> clazz, boolean isRuntimeClass) {
this.reader = null; // no reader available!
this.isRuntimeClass = isRuntimeClass;
this.className = Type.getType(clazz).getInternalName();
final Class<?> superclazz = clazz.getSuperclass();
this.superName = superclazz == null ? null : Type.getType(superclazz).getInternalName();
final Class<?>[] interfClasses = clazz.getInterfaces();
this.interfaces = new String[interfClasses.length];
for (int i = 0; i < interfClasses.length; i++) {
this.interfaces[i] = Type.getType(interfClasses[i]).getInternalName();
}
final Set<Method> methods = new HashSet<Method>();
final Set<String> fields = new HashSet<String>();
for (final java.lang.reflect.Method m : clazz.getDeclaredMethods()) {
methods.add(Method.getMethod(m));
}
for (final java.lang.reflect.Constructor<?> m : clazz.getDeclaredConstructors()) {
methods.add(Method.getMethod(m));
}
for (final java.lang.reflect.Field f : clazz.getDeclaredFields()) {
fields.add(f.getName());
}
this.methods = Collections.unmodifiableSet(methods);
this.fields = Collections.unmodifiableSet(fields);
}

public ClassReader getReader() {
if (reader == null)
throw new IllegalStateException("'" + Type.getObjectType(className).getClassName() + "' has no ClassReader, because it was already checked or is only loaded as related class.");
Expand Down

0 comments on commit 95d9d55

Please sign in to comment.