Skip to content

Instantly share code, notes, and snippets.

@forax
Created January 24, 2018 18:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forax/38935d18aaedc08a32610a7cbc68885e to your computer and use it in GitHub Desktop.
Save forax/38935d18aaedc08a32610a7cbc68885e to your computer and use it in GitHub Desktop.
Find all possible candidates to be a value based class in the JDK
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Optional;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
public class ValueBasedClassFinder {
private static Optional<InputStream> open(ModuleReader reader, String name) {
try {
return reader.open(name);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
private static boolean isValueBasedClassCandidate(InputStream input) {
ClassReader reader;
try(input) {
reader = new ClassReader(input);
} catch(IOException e) {
throw new UncheckedIOException(e);
}
var visitor = new ClassVisitor(Opcodes.ASM7) {
private boolean isAValueBasedClass = true;
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
if ((access & Opcodes.ACC_FINAL) == 0 || !"java/lang/Object".equals(superName)) {
isAValueBasedClass = false;
}
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
if ((access & Opcodes.ACC_FINAL) == 0) {
isAValueBasedClass = false;
}
return null;
}
};
reader.accept(visitor, ClassReader.SKIP_CODE);
return visitor.isAValueBasedClass;
}
public static void main(String[] args) throws IOException {
var finder = Optional.of(args)
.filter(array -> array.length != 0)
.map(array -> Arrays.stream(array).map(Paths::get).toArray(Path[]::new))
.map(ModuleFinder::of)
.orElseGet(ModuleFinder::ofSystem);
var candidates = new ArrayList<String>();
for(var module: finder.findAll()) {
try(var reader = module.open()) {
reader.list().filter(name -> name.endsWith(".class"))
.flatMap(name -> open(reader, name)
.filter(input -> isValueBasedClassCandidate(input))
.map(__ -> name + " in " + module.descriptor().name())
.stream())
.forEach(candidates::add);
}
}
candidates.forEach(System.out::println);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment