Created
January 24, 2018 18:30
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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