5252import org .sonatype .plexus .build .incremental .BuildContext ;
5353
5454import java .io .*;
55+ import java .lang .reflect .Constructor ;
56+ import java .lang .reflect .InvocationTargetException ;
57+ import java .lang .reflect .Method ;
5558import java .net .MalformedURLException ;
5659import java .net .URL ;
5760import java .net .URLClassLoader ;
5861import java .util .*;
5962import java .util .jar .JarEntry ;
6063import java .util .jar .JarFile ;
64+ import java .util .zip .ZipFile ;
6165
6266/**
6367 * A Maven plugin for applying Byte Buddy transformations during a build.
@@ -74,6 +78,26 @@ public abstract class ByteBuddyMojo extends AbstractMojo {
7478 */
7579 private static final String JAVA_CLASS_EXTENSION = ".class" ;
7680
81+ /**
82+ * A dispatcher for creating a {@link JarFile}.
83+ */
84+ private static final JarFileFactory JAR_FILE_FACTORY ;
85+
86+ /*
87+ * Creates a factory for creating a jar file.
88+ */
89+ static {
90+ JarFileFactory jarFileFactory ;
91+ try {
92+ Method runtimeVersion = JarFile .class .getMethod ("runtimeVersion" );
93+ Constructor <JarFile > constructor = JarFile .class .getConstructor (File .class , boolean .class , int .class , runtimeVersion .getReturnType ());
94+ jarFileFactory = new JarFileFactory .ForMultiReleaseVm (constructor , runtimeVersion );
95+ } catch (Exception ignored ) {
96+ jarFileFactory = JarFileFactory .ForLegacyVm .INSTANCE ;
97+ }
98+ JAR_FILE_FACTORY = jarFileFactory ;
99+ }
100+
77101 /**
78102 * The Maven project.
79103 */
@@ -267,7 +291,7 @@ public void execute() throws MojoExecutionException, MojoFailureException {
267291 for (String element : elements ) {
268292 File artifact = new File (element );
269293 if (artifact .isFile ()) {
270- JarFile file = new JarFile (artifact );
294+ JarFile file = JAR_FILE_FACTORY . make (artifact );
271295 try {
272296 JarEntry entry = file .getJarEntry (Plugin .Engine .Default .PLUGIN_FILE );
273297 if (entry != null ) {
@@ -889,6 +913,9 @@ protected List<String> resolveImplicitClassPathElements() throws MojoFailureExce
889913 }
890914 }
891915
916+ /**
917+ * Transforms all jars for a folder containing jar files, typically project dependencies.
918+ */
892919 @ Mojo (name = "transform-dependencies" , defaultPhase = LifecyclePhase .PROCESS_CLASSES , threadSafe = true , requiresDependencyResolution = ResolutionScope .COMPILE )
893920 public static class ForDependencyFolder extends ByteBuddyMojo {
894921
@@ -941,6 +968,90 @@ protected void apply(List<Transformer> transformers, List<String> elements, Map<
941968 }
942969 }
943970
971+ /**
972+ * A factory for creating {@link JarFile}.
973+ */
974+ protected interface JarFileFactory {
975+
976+ /**
977+ * Creates a {@link JarFile}.
978+ *
979+ * @param file The file to represent as a {@link JarFile}.
980+ * @return Returns a {@link JarFile}.
981+ * @throws IOException If an I/O exception occurs.
982+ */
983+ JarFile make (File file ) throws IOException ;
984+
985+ /**
986+ * A dispatcher for a legacy VM that does not support multi-release jars.
987+ */
988+ enum ForLegacyVm implements JarFileFactory {
989+
990+ /**
991+ * The singleton instance.
992+ */
993+ INSTANCE ;
994+
995+ /**
996+ * {@inheritDoc}
997+ */
998+ public JarFile make (File file ) throws IOException {
999+ return new JarFile (file , false , ZipFile .OPEN_READ );
1000+ }
1001+ }
1002+
1003+ /**
1004+ * A factory for creating a {@link JarFile} which resolves multi-release properties.
1005+ */
1006+ class ForMultiReleaseVm implements JarFileFactory {
1007+
1008+ /**
1009+ * The {@code JarFile#JarFile(File, boolean, int, Runtime.Version)} constructor.
1010+ */
1011+ private final Constructor <JarFile > constructor ;
1012+
1013+ /**
1014+ * The {@code JarFile#runtimeVersion()} method.
1015+ */
1016+ private final Method runtimeVersion ;
1017+
1018+ /**
1019+ * Creates a jar file factory that is multi-release capable.
1020+ *
1021+ * @param constructor The {@code JarFile#JarFile(File, boolean, int, Runtime.Version)} constructor.
1022+ * @param runtimeVersion The {@code JarFile#runtimeVersion()} method.
1023+ */
1024+ protected ForMultiReleaseVm (Constructor <JarFile > constructor , Method runtimeVersion ) {
1025+ this .constructor = constructor ;
1026+ this .runtimeVersion = runtimeVersion ;
1027+ }
1028+
1029+ /**
1030+ * {@inheritDoc}
1031+ */
1032+ public JarFile make (File file ) throws IOException {
1033+ try {
1034+ return constructor .newInstance (file , false , ZipFile .OPEN_READ , runtimeVersion .invoke (null ));
1035+ } catch (IllegalAccessException exception ) {
1036+ throw new IllegalStateException (exception );
1037+ } catch (InstantiationException exception ) {
1038+ throw new IllegalStateException (exception );
1039+ } catch (InvocationTargetException exception ) {
1040+ Throwable cause = exception .getCause ();
1041+ if (cause instanceof RuntimeException ) {
1042+ throw (RuntimeException ) cause ;
1043+ } else if (cause instanceof Error ) {
1044+ throw (Error ) cause ;
1045+ } else if (cause instanceof IOException ) {
1046+ throw (IOException ) cause ;
1047+ } else {
1048+ throw new RuntimeException (exception );
1049+ }
1050+ }
1051+ }
1052+ }
1053+ }
1054+
9441055 /**
9451056 * A {@link BuildLogger} implementation for a Maven {@link Log}.
9461057 */
0 commit comments