diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb5f97de..d047b933 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ jobs: strategy: matrix: os: [ubuntu-latest, windows-latest] - # Always test on the latest version and LTS. - java: [8, 11, 17, 21, 25] + # Requires Java 25 for the Class-File API (java.lang.classfile) + java: [25] runs-on: ${{ matrix.os }} steps: - name: Checkout diff --git a/pom.xml b/pom.xml index 7834774e..6290c83d 100644 --- a/pom.xml +++ b/pom.xml @@ -7,13 +7,12 @@ UTF-8 UTF-8 - 8 - 8 - 8 + 25 + 25 + 25 3.9.6 ${project.build.directory}/test-working-directory - 9.9.1 4.0.0 org.vafer @@ -79,31 +78,6 @@ commons-io 2.21.0 - - org.ow2.asm - asm - ${asm.version} - - - org.ow2.asm - asm-analysis - ${asm.version} - - - org.ow2.asm - asm-commons - ${asm.version} - - - org.ow2.asm - asm-util - ${asm.version} - - - org.ow2.asm - asm-tree - ${asm.version} - @@ -250,7 +224,7 @@ shade - true + false *:* @@ -264,11 +238,6 @@ commons-io:commons-io - org.ow2.asm:asm - org.ow2.asm:asm-analysis - org.ow2.asm:asm-commons - org.ow2.asm:asm-util - org.ow2.asm:asm-tree @@ -276,15 +245,6 @@ org.apache.commons org.vafer.jdeb.shaded.commons - - org.ow2.asm - org.vafer.jdeb.shaded.ow2.asm - - - org.objectweb.asm - org.vafer.jdeb.shaded.objectweb.asm - diff --git a/src/main/java/org/vafer/jdependency/Clazzpath.java b/src/main/java/org/vafer/jdependency/Clazzpath.java index 29310f1b..b09db71c 100644 --- a/src/main/java/org/vafer/jdependency/Clazzpath.java +++ b/src/main/java/org/vafer/jdependency/Clazzpath.java @@ -31,8 +31,6 @@ import java.util.stream.Stream; import java.util.zip.ZipEntry; -import org.apache.commons.io.input.MessageDigestInputStream; -import org.objectweb.asm.ClassReader; import static org.apache.commons.io.FilenameUtils.normalize; import static org.apache.commons.io.FilenameUtils.separatorsToUnix; @@ -165,16 +163,15 @@ private ClazzpathUnit addClazzpathUnit( final Iterable resources, fina // extract dependencies of clazz InputStream inputStream = resource.getInputStream(); try { - final MessageDigest digest = MessageDigest.getInstance("SHA-256"); - final MessageDigestInputStream calculatingInputStream = - MessageDigestInputStream.builder().setInputStream(inputStream).setMessageDigest(digest).get(); + final byte[] classBytes = inputStream.readAllBytes(); + final MessageDigest digest = MessageDigest.getInstance("SHA-256"); if (versions) { - inputStream = calculatingInputStream; + digest.update(classBytes); } final DependenciesClassAdapter v = new DependenciesClassAdapter(); - new ClassReader(inputStream).accept(v, ClassReader.EXPAND_FRAMES | ClassReader.SKIP_DEBUG); + v.accept(classBytes); // get or create clazz final String clazzName = resource.name; diff --git a/src/main/java/org/vafer/jdependency/asm/DependenciesClassAdapter.java b/src/main/java/org/vafer/jdependency/asm/DependenciesClassAdapter.java index 4085716f..ce1b29cd 100644 --- a/src/main/java/org/vafer/jdependency/asm/DependenciesClassAdapter.java +++ b/src/main/java/org/vafer/jdependency/asm/DependenciesClassAdapter.java @@ -15,166 +15,51 @@ */ package org.vafer.jdependency.asm; +import java.lang.classfile.ClassFile; +import java.lang.classfile.ClassModel; +import java.lang.classfile.constantpool.ClassEntry; +import java.lang.classfile.constantpool.PoolEntry; +import java.lang.classfile.constantpool.Utf8Entry; import java.util.HashSet; import java.util.Set; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.ModuleVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.RecordComponentVisitor; -import org.objectweb.asm.TypePath; -import org.objectweb.asm.commons.ClassRemapper; -import org.objectweb.asm.commons.Remapper; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * internal - do not use */ - -public final class DependenciesClassAdapter extends ClassRemapper { - - private static final int OPCODES = Opcodes.ASM9; - - private static final EmptyVisitor ev = new EmptyVisitor(); - - public DependenciesClassAdapter() { - super(ev, new CollectingRemapper()); - } - - public Set getDependencies() { - return ((CollectingRemapper) super.remapper).classes; - } - - private static class CollectingRemapper extends Remapper { - - final Set classes = new HashSet(); - - public String map(String pClassName) { - classes.add(pClassName.replace('/', '.')); - return pClassName; - } - } - - static class EmptyVisitor extends ClassVisitor { - - private static final AnnotationVisitor av = new AnnotationVisitor(OPCODES) { - @Override - public AnnotationVisitor visitAnnotation(String name, String desc) { - return this; - } - - @Override - public AnnotationVisitor visitArray(String name) { - return this; - } - }; - - private static final MethodVisitor mv = new MethodVisitor(OPCODES) { - @Override - public AnnotationVisitor visitAnnotationDefault() { - return av; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return av; - } - - @Override - public AnnotationVisitor visitParameterAnnotation( - int parameter, String desc, boolean visible) { - return av; - } - - @Override - public AnnotationVisitor visitInsnAnnotation( int typeRef, TypePath typePath, String descriptor, - boolean visible ) { - return av; - } - - @Override - public AnnotationVisitor visitLocalVariableAnnotation( int typeRef, TypePath typePath, Label[] start, - Label[] end, int[] index, String descriptor, - boolean visible ) { - return av; - } - - @Override - public AnnotationVisitor visitTryCatchAnnotation( int typeRef, TypePath typePath, String descriptor, - boolean visible ) { - return av; - } - - @Override - public AnnotationVisitor visitTypeAnnotation( int typeRef, TypePath typePath, String descriptor, - boolean visible ) { - return av; - } - }; - - private static final FieldVisitor fieldVisitor = new FieldVisitor(OPCODES) { - @Override - public AnnotationVisitor visitAnnotation( String desc, boolean visible ) { - return av; +public final class DependenciesClassAdapter { + + private static final Pattern DESCRIPTOR_PATTERN = Pattern.compile("L([a-zA-Z0-9_/\\$]+);"); + + private final Set classes = new HashSet<>(); + + public void accept(byte[] classBytes) { + ClassModel cm = ClassFile.of().parse(classBytes); + for (PoolEntry pe : cm.constantPool()) { + if (pe instanceof ClassEntry ce) { + String name = ce.asInternalName(); + if (name.startsWith("[")) { + Matcher m = DESCRIPTOR_PATTERN.matcher(name); + while (m.find()) { + classes.add(m.group(1).replace('/', '.')); + } + } else { + classes.add(name.replace('/', '.')); + } + } else if (pe instanceof Utf8Entry ue) { + String str = ue.stringValue(); + if (str.indexOf('L') != -1 && str.indexOf(';') != -1) { + Matcher m = DESCRIPTOR_PATTERN.matcher(str); + while (m.find()) { + classes.add(m.group(1).replace('/', '.')); + } + } } - @Override - public AnnotationVisitor visitTypeAnnotation( int typeRef, TypePath typePath, String descriptor, - boolean visible ) { - return av; - } - }; - - private static final ModuleVisitor moduleVisitor = new ModuleVisitor(OPCODES) { - }; - - private static final RecordComponentVisitor recordComponentVisitor = new RecordComponentVisitor(OPCODES) { - @Override - public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { - return av; - } - - @Override - public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String descriptor, boolean visible) { - return av; - } - }; - - public EmptyVisitor() { - super(OPCODES); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return av; - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { - return fieldVisitor; - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return mv; - } - - @Override - public AnnotationVisitor visitTypeAnnotation( int typeRef, TypePath typePath, String descriptor, - boolean visible ) { - return av; - } - - @Override - public ModuleVisitor visitModule(String name, int access, String version) { - return moduleVisitor; } + } - @Override - public RecordComponentVisitor visitRecordComponent(String name, String descriptor, String signature) { - return recordComponentVisitor; - } + public Set getDependencies() { + return classes; } } diff --git a/src/main/java/org/vafer/jdependency/utils/DependencyUtils.java b/src/main/java/org/vafer/jdependency/utils/DependencyUtils.java index efc7b912..97bf8784 100644 --- a/src/main/java/org/vafer/jdependency/utils/DependencyUtils.java +++ b/src/main/java/org/vafer/jdependency/utils/DependencyUtils.java @@ -19,7 +19,6 @@ import java.io.InputStream; import java.util.Set; -import org.objectweb.asm.ClassReader; import org.vafer.jdependency.asm.DependenciesClassAdapter; /** @@ -70,7 +69,7 @@ public static Set getDependenciesOfJar( final InputStream pInputStream ) public static Set getDependenciesOfClass( final InputStream pInputStream ) throws IOException { final DependenciesClassAdapter v = new DependenciesClassAdapter(); - new ClassReader( pInputStream ).accept( v, ClassReader.EXPAND_FRAMES ); + v.accept(pInputStream.readAllBytes()); final Set depNames = v.getDependencies(); return depNames; }