3030import org .gradle .api .provider .Provider ;
3131import org .gradle .api .tasks .Input ;
3232import org .gradle .api .tasks .InputFiles ;
33+ import org .objectweb .asm .ClassReader ;
34+ import org .objectweb .asm .ClassVisitor ;
3335import org .objectweb .asm .ClassWriter ;
3436import org .objectweb .asm .ModuleVisitor ;
3537import org .objectweb .asm .Opcodes ;
@@ -144,7 +146,7 @@ public void transform(TransformOutputs outputs) {
144146 boolean realModule = isModule (originalJar );
145147 if (moduleSpec instanceof ModuleInfo ) {
146148 if (realModule && !((ModuleInfo ) moduleSpec ).patchRealModule ) {
147- throw new RuntimeException ("Patching of real modules must be explicitly enabled with 'patchRealModule()'" );
149+ throw new RuntimeException ("Patching of real modules must be explicitly enabled with 'patchRealModule()' or 'preserveExisting()' " );
148150 }
149151 String definedName = moduleSpec .getModuleName ();
150152 String expectedName = autoModuleName (originalJar );
@@ -287,12 +289,14 @@ private void addModuleDescriptor(File originalJar, File moduleJar, ModuleInfo mo
287289 try (JarOutputStream outputStream = newJarOutputStream (Files .newOutputStream (moduleJar .toPath ()), inputStream .getManifest ())) {
288290 Map <String , List <String >> providers = new LinkedHashMap <>();
289291 Set <String > packages = new TreeSet <>();
290- copyAndExtractProviders (inputStream , outputStream , !moduleInfo .getMergedJars ().isEmpty (), providers , packages );
292+ byte [] existingModuleInfo = copyAndExtractProviders (inputStream , outputStream , !moduleInfo .getMergedJars ().isEmpty (), providers , packages );
291293 mergeJars (moduleInfo , outputStream , providers , packages );
292294 outputStream .putNextEntry (newReproducibleEntry ("module-info.class" ));
293295 outputStream .write (addModuleInfo (moduleInfo , providers , versionFromFilePath (originalJar .toPath ()),
294- moduleInfo .exportAllPackages ? packages : Collections .emptySet ()));
296+ moduleInfo .exportAllPackages ? packages : Collections .emptySet (),
297+ existingModuleInfo ));
295298 outputStream .closeEntry ();
299+ System .out .println ("AAA: " + moduleJar );
296300 }
297301 } catch (IOException e ) {
298302 throw new RuntimeException (e );
@@ -310,8 +314,10 @@ private JarOutputStream newJarOutputStream(OutputStream out, @Nullable Manifest
310314 return jar ;
311315 }
312316
313- private void copyAndExtractProviders (JarInputStream inputStream , JarOutputStream outputStream , boolean willMergeJars , Map <String , List <String >> providers , Set <String > packages ) throws IOException {
317+ @ Nullable
318+ private byte [] copyAndExtractProviders (JarInputStream inputStream , JarOutputStream outputStream , boolean willMergeJars , Map <String , List <String >> providers , Set <String > packages ) throws IOException {
314319 JarEntry jarEntry = inputStream .getNextJarEntry ();
320+ byte [] existingModuleInfo = null ;
315321 while (jarEntry != null ) {
316322 byte [] content = readAllBytes (inputStream );
317323 String entryName = jarEntry .getName ();
@@ -325,8 +331,9 @@ private void copyAndExtractProviders(JarInputStream inputStream, JarOutputStream
325331 }
326332 providers .get (key ).addAll (extractImplementations (content ));
327333 }
328-
329- if (!JAR_SIGNATURE_PATH .matcher (entryName ).matches () && !"META-INF/MANIFEST.MF" .equals (entryName ) && !isModuleInfoClass (entryName )) {
334+ if (isModuleInfoClass (entryName )) {
335+ existingModuleInfo = content ;
336+ } else if (!JAR_SIGNATURE_PATH .matcher (entryName ).matches () && !"META-INF/MANIFEST.MF" .equals (entryName )) {
330337 if (!willMergeJars || !isFileInServicesFolder ) { // service provider files will be merged later
331338 jarEntry .setCompressedSize (-1 );
332339 try {
@@ -354,6 +361,7 @@ private void copyAndExtractProviders(JarInputStream inputStream, JarOutputStream
354361 }
355362 jarEntry = inputStream .getNextJarEntry ();
356363 }
364+ return existingModuleInfo ;
357365 }
358366
359367 private List <String > extractImplementations (byte [] content ) {
@@ -366,13 +374,40 @@ private List<String> extractImplementations(byte[] content) {
366374 .collect (Collectors .toList ());
367375 }
368376
369- private byte [] addModuleInfo (ModuleInfo moduleInfo , Map <String , List <String >> providers , @ Nullable String version , Set <String > autoExportedPackages ) {
370- ClassWriter classWriter = new ClassWriter (0 );
371- classWriter .visit (Opcodes .V9 , Opcodes .ACC_MODULE , "module-info" , null , null , null );
377+ private byte [] addModuleInfo (ModuleInfo moduleInfo , Map <String , List <String >> providers , @ Nullable String version , Set <String > autoExportedPackages ,
378+ @ Nullable byte [] existingModuleInfo ) {
379+ ClassReader classReader = moduleInfo .preserveExisting && existingModuleInfo != null ? new ClassReader (existingModuleInfo ) : null ;
380+ ClassWriter classWriter = new ClassWriter (classReader , 0 );
372381 int openModule = moduleInfo .openModule ? Opcodes .ACC_OPEN : 0 ;
373382 String moduleVersion = moduleInfo .getModuleVersion () == null ? version : moduleInfo .getModuleVersion ();
374- ModuleVisitor moduleVisitor = classWriter .visitModule (moduleInfo .getModuleName (), openModule , moduleVersion );
375383
384+ if (classReader == null ) {
385+ classWriter .visit (Opcodes .V9 , Opcodes .ACC_MODULE , "module-info" , null , null , null );
386+ ModuleVisitor moduleVisitor = classWriter .visitModule (moduleInfo .getModuleName (), openModule , moduleVersion );
387+ moduleVisitor .visitRequire ("java.base" , 0 , null );
388+ addModuleInfoEntires (moduleInfo , providers , autoExportedPackages , moduleVisitor );
389+ moduleVisitor .visitEnd ();
390+ classWriter .visitEnd ();
391+ } else {
392+ ClassVisitor classVisitor = new ClassVisitor (Opcodes .ASM9 , classWriter ) {
393+ @ Override
394+ public ModuleVisitor visitModule (String name , int access , String version ) {
395+ ModuleVisitor moduleVisitor = super .visitModule (name , access , version );
396+ return new ModuleVisitor (Opcodes .ASM9 , moduleVisitor ) {
397+ @ Override
398+ public void visitEnd () {
399+ addModuleInfoEntires (moduleInfo , providers , autoExportedPackages , this );
400+ super .visitEnd ();
401+ }
402+ };
403+ }
404+ };
405+ classReader .accept (classVisitor , 0 );
406+ }
407+ return classWriter .toByteArray ();
408+ }
409+
410+ private void addModuleInfoEntires (ModuleInfo moduleInfo , Map <String , List <String >> providers , Set <String > autoExportedPackages , ModuleVisitor moduleVisitor ) {
376411 for (String packageName : autoExportedPackages ) {
377412 moduleVisitor .visitExport (packageName , 0 );
378413 }
@@ -388,8 +423,6 @@ private byte[] addModuleInfo(ModuleInfo moduleInfo, Map<String, List<String>> pr
388423 moduleVisitor .visitOpen (packageName .replace ('.' , '/' ), 0 , modules .toArray (new String [0 ]));
389424 }
390425
391- moduleVisitor .visitRequire ("java.base" , 0 , null );
392-
393426 if (moduleInfo .requireAllDefinedDependencies ) {
394427 String identifier = moduleInfo .getIdentifier ();
395428 PublishedMetadata requires = getParameters ().getRequiresFromMetadata ().get ().get (identifier );
@@ -439,9 +472,6 @@ private byte[] addModuleInfo(ModuleInfo moduleInfo, Map<String, List<String>> pr
439472 implementations .stream ().map (impl -> impl .replace ('.' , '/' )).toArray (String []::new ));
440473 }
441474 }
442- moduleVisitor .visitEnd ();
443- classWriter .visitEnd ();
444- return classWriter .toByteArray ();
445475 }
446476
447477 private void mergeJars (ModuleSpec moduleSpec , JarOutputStream outputStream , Map <String , List <String >> providers , Set <String > packages ) throws IOException {
0 commit comments