Skip to content

Commit 40dd50f

Browse files
authored
[MCOMPILER-205] Add a boolean to generate missing package-info classes by default (#88)
* [MCOMPILER-205] Add a boolean to generate missing package-info classes by default * [MCOMPILER-205] Add an integration test
1 parent 12378bb commit 40dd50f

File tree

6 files changed

+230
-0
lines changed

6 files changed

+230
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
invoker.goals = clean compile
19+
invoker.buildResult = success

src/it/MCOMPILER-205/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<!--
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
-->
19+
20+
<project
21+
xmlns="http://maven.apache.org/POM/4.0.0"
22+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
23+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
24+
25+
<modelVersion>4.0.0</modelVersion>
26+
27+
<groupId>blah</groupId>
28+
<artifactId>blah</artifactId>
29+
<version>1.0</version>
30+
<packaging>jar</packaging>
31+
32+
<properties>
33+
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
34+
</properties>
35+
<build>
36+
<plugins>
37+
<plugin>
38+
<groupId>org.apache.maven.plugins</groupId>
39+
<artifactId>maven-compiler-plugin</artifactId>
40+
<version>@pom.version@</version>
41+
</plugin>
42+
</plugins>
43+
</build>
44+
</project>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package dummy;
2+
3+
/*
4+
* Licensed to the Apache Software Foundation (ASF) under one
5+
* or more contributor license agreements. See the NOTICE file
6+
* distributed with this work for additional information
7+
* regarding copyright ownership. The ASF licenses this file
8+
* to you under the Apache License, Version 2.0 (the
9+
* "License"); you may not use this file except in compliance
10+
* with the License. You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing,
15+
* software distributed under the License is distributed on an
16+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
* KIND, either express or implied. See the License for the
18+
* specific language governing permissions and limitations
19+
* under the License.
20+
*/
21+
22+
23+
public class HelloWorld
24+
{
25+
public static void main(String[] argv) {
26+
System.out.println("Hello World");
27+
}
28+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/**
21+
* This is the package javadoc
22+
*/
23+
package dummy;

src/it/MCOMPILER-205/verify.groovy

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
/*
3+
* Licensed to the Apache Software Foundation (ASF) under one
4+
* or more contributor license agreements. See the NOTICE file
5+
* distributed with this work for additional information
6+
* regarding copyright ownership. The ASF licenses this file
7+
* to you under the Apache License, Version 2.0 (the
8+
* "License"); you may not use this file except in compliance
9+
* with the License. You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing,
14+
* software distributed under the License is distributed on an
15+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
* KIND, either express or implied. See the License for the
17+
* specific language governing permissions and limitations
18+
* under the License.
19+
*/
20+
def packageInfoClassFile = new File( basedir, 'target/classes/dummy/package-info.class' )
21+
assert packageInfoClassFile.exists()

src/main/java/org/apache/maven/plugin/compiler/AbstractCompilerMojo.java

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
8383
import org.codehaus.plexus.languages.java.jpms.JavaModuleDescriptor;
8484
import org.codehaus.plexus.languages.java.version.JavaVersion;
85+
import org.objectweb.asm.ClassWriter;
86+
import org.objectweb.asm.Opcodes;
8587

8688
/**
8789
* TODO: At least one step could be optimized, currently the plugin will do two
@@ -530,6 +532,18 @@ public abstract class AbstractCompilerMojo
530532
@Parameter( defaultValue = "true", property = "maven.compiler.useIncrementalCompilation" )
531533
private boolean useIncrementalCompilation = true;
532534

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+
533547
/**
534548
* Resolves the artifacts needed.
535549
*/
@@ -1192,6 +1206,21 @@ else if ( !values[0].equals( descriptor.name() ) )
11921206
throw new MojoExecutionException( "Fatal error compiling", e );
11931207
}
11941208

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+
11951224
if ( useIncrementalCompilation )
11961225
{
11971226
if ( incrementalBuildHelperRequest.getOutputDirectory().exists() )
@@ -1296,6 +1325,72 @@ else if ( message.getKind() == CompilerMessage.Kind.WARNING
12961325
}
12971326
}
12981327

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+
12991394
protected boolean isTestCompile()
13001395
{
13011396
return false;

0 commit comments

Comments
 (0)