|
82 | 82 | import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
|
83 | 83 | import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
|
84 | 84 | import org.codehaus.plexus.languages.java.version.JavaVersion;
|
| 85 | +import org.objectweb.asm.ClassWriter; |
| 86 | +import org.objectweb.asm.Opcodes; |
85 | 87 |
|
86 | 88 | /**
|
87 | 89 | * TODO: At least one step could be optimized, currently the plugin will do two
|
@@ -530,6 +532,18 @@ public abstract class AbstractCompilerMojo
|
530 | 532 | @Parameter( defaultValue = "true", property = "maven.compiler.useIncrementalCompilation" )
|
531 | 533 | private boolean useIncrementalCompilation = true;
|
532 | 534 |
|
| 535 | + /** |
| 536 | + * Package info source files that only contain javadoc and no annotation on the package |
| 537 | + * can lead to no class file being generated by the compiler. This causes a file miss |
| 538 | + * on the next compilations and forces an unnecessary recompilation. The default value |
| 539 | + * of <code>true</code> causes an empty class file to be generated. This behavior can |
| 540 | + * be changed by setting this parameter to <code>false</code>. |
| 541 | + * |
| 542 | + * @since 3.10 |
| 543 | + */ |
| 544 | + @Parameter( defaultValue = "true", property = "maven.compiler.createMissingPackageInfoClass" ) |
| 545 | + private boolean createMissingPackageInfoClass = true; |
| 546 | + |
533 | 547 | /**
|
534 | 548 | * Resolves the artifacts needed.
|
535 | 549 | */
|
@@ -1192,6 +1206,21 @@ else if ( !values[0].equals( descriptor.name() ) )
|
1192 | 1206 | throw new MojoExecutionException( "Fatal error compiling", e );
|
1193 | 1207 | }
|
1194 | 1208 |
|
| 1209 | + if ( createMissingPackageInfoClass && compilerResult.isSuccess() |
| 1210 | + && compiler.getCompilerOutputStyle() == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE ) |
| 1211 | + { |
| 1212 | + try |
| 1213 | + { |
| 1214 | + SourceMapping sourceMapping = getSourceMapping( compilerConfiguration, compiler ); |
| 1215 | + createMissingPackageInfoClasses( compilerConfiguration, sourceMapping, sources ); |
| 1216 | + } |
| 1217 | + catch ( Exception e ) |
| 1218 | + { |
| 1219 | + getLog().warn( "Error creating missing package info classes", e ); |
| 1220 | + |
| 1221 | + } |
| 1222 | + } |
| 1223 | + |
1195 | 1224 | if ( useIncrementalCompilation )
|
1196 | 1225 | {
|
1197 | 1226 | if ( incrementalBuildHelperRequest.getOutputDirectory().exists() )
|
@@ -1296,6 +1325,72 @@ else if ( message.getKind() == CompilerMessage.Kind.WARNING
|
1296 | 1325 | }
|
1297 | 1326 | }
|
1298 | 1327 |
|
| 1328 | + private void createMissingPackageInfoClasses( CompilerConfiguration compilerConfiguration, |
| 1329 | + SourceMapping sourceMapping, |
| 1330 | + Set<File> sources ) |
| 1331 | + throws InclusionScanException, IOException |
| 1332 | + { |
| 1333 | + for ( File source : sources ) |
| 1334 | + { |
| 1335 | + String path = source.toString(); |
| 1336 | + if ( path.endsWith( File.separator + "package-info.java" ) ) |
| 1337 | + { |
| 1338 | + for ( String root : getCompileSourceRoots() ) |
| 1339 | + { |
| 1340 | + root = root + File.separator; |
| 1341 | + if ( path.startsWith( root ) ) |
| 1342 | + { |
| 1343 | + String rel = path.substring( root.length() ); |
| 1344 | + Set<File> files = sourceMapping.getTargetFiles( getOutputDirectory(), rel ); |
| 1345 | + for ( File file : files ) |
| 1346 | + { |
| 1347 | + if ( !file.exists() ) |
| 1348 | + { |
| 1349 | + byte[] bytes = generatePackage( compilerConfiguration, rel ); |
| 1350 | + Files.write( file.toPath(), bytes ); |
| 1351 | + } |
| 1352 | + } |
| 1353 | + } |
| 1354 | + } |
| 1355 | + } |
| 1356 | + } |
| 1357 | + } |
| 1358 | + |
| 1359 | + private byte[] generatePackage( CompilerConfiguration compilerConfiguration, String javaFile ) |
| 1360 | + { |
| 1361 | + int version = getOpcode( compilerConfiguration ); |
| 1362 | + ClassWriter cw = new ClassWriter( 0 ); |
| 1363 | + cw.visitSource( "package-info.java", null ); |
| 1364 | + cw.visit( version, |
| 1365 | + Opcodes.ACC_SYNTHETIC | Opcodes.ACC_ABSTRACT | Opcodes.ACC_INTERFACE, |
| 1366 | + javaFile.substring( 0, javaFile.length() - ".java".length() ), |
| 1367 | + null, "java/lang/Object", null ); |
| 1368 | + return cw.toByteArray(); |
| 1369 | + } |
| 1370 | + |
| 1371 | + private int getOpcode( CompilerConfiguration compilerConfiguration ) |
| 1372 | + { |
| 1373 | + String version = compilerConfiguration.getReleaseVersion(); |
| 1374 | + if ( version == null ) |
| 1375 | + { |
| 1376 | + version = compilerConfiguration.getTargetVersion(); |
| 1377 | + if ( version == null ) |
| 1378 | + { |
| 1379 | + version = "1.5"; |
| 1380 | + } |
| 1381 | + } |
| 1382 | + if ( version.startsWith( "1." ) ) |
| 1383 | + { |
| 1384 | + version = version.substring( 2 ); |
| 1385 | + } |
| 1386 | + int iVersion = Integer.parseInt( version ); |
| 1387 | + if ( iVersion < 2 ) |
| 1388 | + { |
| 1389 | + throw new IllegalArgumentException( "Unsupported java version '" + version + "'" ); |
| 1390 | + } |
| 1391 | + return iVersion - 2 + Opcodes.V1_2; |
| 1392 | + } |
| 1393 | + |
1299 | 1394 | protected boolean isTestCompile()
|
1300 | 1395 | {
|
1301 | 1396 | return false;
|
|
0 commit comments