1818import java .io .InputStream ;
1919import java .security .MessageDigest ;
2020import java .security .NoSuchAlgorithmException ;
21+ import java .util .ArrayList ;
2122import java .util .Collection ;
2223import java .util .Enumeration ;
2324import java .util .HexFormat ;
@@ -43,9 +44,26 @@ public class Utils {
4344 }
4445 }
4546
47+ private record MismatchInfo (String jarEntryName , String expectedClassSha256 , String foundClassSha256 ) {
48+ @ Override
49+ public String toString () {
50+ return "[class='"
51+ + jarEntryName
52+ + '\''
53+ + ", expected='"
54+ + expectedClassSha256
55+ + '\''
56+ + ", found='"
57+ + foundClassSha256
58+ + '\''
59+ + ']' ;
60+ }
61+ }
62+
4663 /**
47- * Patches the classes in the input JAR file, using the collection of patchers. If the patcher info specify a SHA256 digest, and
48- * the class to patch does not match it, an IllegalArgumentException is thrown.
64+ * Patches the classes in the input JAR file, using the collection of patchers. Each patcher specifies a target class (its jar entry
65+ * name) and the SHA256 digest on the class bytes.
66+ * This digest is checked against the class bytes in the JAR, and if it does not match, an IllegalArgumentException is thrown.
4967 * If the input file does not contain all the classes to patch specified in the patcher info collection, an IllegalArgumentException
5068 * is also thrown.
5169 * @param inputFile the JAR file to patch
@@ -54,6 +72,7 @@ public class Utils {
5472 */
5573 public static void patchJar (File inputFile , File outputFile , Collection <PatcherInfo > patchers ) {
5674 var classPatchers = patchers .stream ().collect (Collectors .toMap (PatcherInfo ::jarEntryName , Function .identity ()));
75+ var mismatchedClasses = new ArrayList <MismatchInfo >();
5776 try (JarFile jarFile = new JarFile (inputFile ); JarOutputStream jos = new JarOutputStream (new FileOutputStream (outputFile ))) {
5877 Enumeration <JarEntry > entries = jarFile .entries ();
5978 while (entries .hasMoreElements ()) {
@@ -67,27 +86,20 @@ public static void patchJar(File inputFile, File outputFile, Collection<PatcherI
6786 byte [] classToPatch = jarFile .getInputStream (entry ).readAllBytes ();
6887 var classSha256 = SHA_256 .digest (classToPatch );
6988
70- if (classPatcher .matches (classSha256 ) == false ) {
71- throw new IllegalArgumentException (
72- String .format (
73- Locale .ROOT ,
74- """
75- Error patching JAR [%s]: SHA256 digest mismatch for class [%s] (expected: [%s], \
76- found: [%s]). This JAR was updated to a version that contains a different class, \
77- for which this patcher was not designed for. Please check if the patcher still \
78- applies correctly to this class, and update its SHA256 digest.""" ,
79- inputFile .getName (),
89+ if (classPatcher .matches (classSha256 )) {
90+ ClassReader classReader = new ClassReader (classToPatch );
91+ ClassWriter classWriter = new ClassWriter (classReader , COMPUTE_MAXS | COMPUTE_FRAMES );
92+ classReader .accept (classPatcher .createVisitor (classWriter ), 0 );
93+ jos .write (classWriter .toByteArray ());
94+ } else {
95+ mismatchedClasses .add (
96+ new MismatchInfo (
8097 classPatcher .jarEntryName (),
8198 HexFormat .of ().formatHex (classPatcher .classSha256 ()),
8299 HexFormat .of ().formatHex (classSha256 )
83100 )
84101 );
85102 }
86-
87- ClassReader classReader = new ClassReader (classToPatch );
88- ClassWriter classWriter = new ClassWriter (classReader , COMPUTE_MAXS | COMPUTE_FRAMES );
89- classReader .accept (classPatcher .visitorFactory ().apply (classWriter ), 0 );
90- jos .write (classWriter .toByteArray ());
91103 } else {
92104 // Read the entry's data and write it to the new JAR
93105 try (InputStream is = jarFile .getInputStream (entry )) {
@@ -100,6 +112,20 @@ public static void patchJar(File inputFile, File outputFile, Collection<PatcherI
100112 throw new RuntimeException (ex );
101113 }
102114
115+ if (mismatchedClasses .isEmpty () == false ) {
116+ throw new IllegalArgumentException (
117+ String .format (
118+ Locale .ROOT ,
119+ """
120+ Error patching JAR [%s]: SHA256 digest mismatch (%s). This JAR was updated to a version that contains different \
121+ classes, for which this patcher was not designed. Please check if the patcher still \
122+ applies correctly, and update the SHA256 digest(s).""" ,
123+ inputFile .getName (),
124+ mismatchedClasses .stream ().map (MismatchInfo ::toString ).collect (Collectors .joining ())
125+ )
126+ );
127+ }
128+
103129 if (classPatchers .isEmpty () == false ) {
104130 throw new IllegalArgumentException (
105131 String .format (
0 commit comments