-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a dedicated goal to the Jandex Maven plugin to [re]index a JAR
- Loading branch information
Showing
6 changed files
with
328 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>io.smallrye</groupId> | ||
<artifactId>smallrye-build-parent</artifactId> | ||
<version>31</version> | ||
</parent> | ||
|
||
<groupId>org.jboss.jandex</groupId> | ||
<artifactId>jandex-maven-plugin-jar</artifactId> | ||
<version>1.0-SNAPSHOT</version> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.jboss</groupId> | ||
<artifactId>jandex</artifactId> | ||
<version>2.4.0.Final</version> | ||
</dependency> | ||
<dependency> | ||
<!-- has META-INF/jandex.idx --> | ||
<groupId>io.smallrye.common</groupId> | ||
<artifactId>smallrye-common-annotation</artifactId> | ||
<version>1.11.0</version> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-shade-plugin</artifactId> | ||
<version>3.3.0</version> | ||
<executions> | ||
<execution> | ||
<id>uberjar</id> | ||
<goals> | ||
<goal>shade</goal> | ||
</goals> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
|
||
<plugin> | ||
<groupId>@project.groupId@</groupId> | ||
<artifactId>@project.artifactId@</artifactId> | ||
<version>@project.version@</version> | ||
<executions> | ||
<execution> | ||
<id>uberjar-index</id> | ||
<phase>package</phase> | ||
<goals> | ||
<goal>jandex-jar</goal> | ||
</goals> | ||
<configuration> | ||
<jar>${project.build.directory}/${project.build.finalName}.jar</jar> | ||
<includes> | ||
<include>org/jboss/jandex/maven/**/*.class</include> | ||
<include>org/jboss/jandex/MethodParameter*.class</include> | ||
<include>io/smallrye/common/annotation/Experimental.class</include> | ||
</includes> | ||
<excludes> | ||
<exclude>org/jboss/jandex/MethodParameterTypeTarget.class</exclude> | ||
</excludes> | ||
</configuration> | ||
</execution> | ||
</executions> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
4 changes: 4 additions & 0 deletions
4
maven-plugin/src/it/jar/src/main/java/org/jboss/jandex/maven/jar/SomeClass.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package org.jboss.jandex.maven.jar; | ||
|
||
public class SomeClass { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import java.util.zip.ZipFile | ||
import org.jboss.jandex.IndexReader | ||
|
||
def jarFile = new File(basedir, 'target/jandex-maven-plugin-jar-1.0-SNAPSHOT.jar') | ||
assert jarFile.exists() : "File ${jarFile} does not exist" | ||
assert jarFile.length() > 0 : "File ${jarFile} is empty" | ||
|
||
def jar = new ZipFile(jarFile) | ||
def indexEntry = jar.getEntry("META-INF/jandex.idx") | ||
assert indexEntry != null : "JAR ${jarFile} doesn't contain an index" | ||
|
||
def index = new IndexReader(jar.getInputStream(indexEntry)).read() | ||
assert index.getKnownClasses().size() == 3 : "Index in ${jarFile} does not contain exactly 3 classes" | ||
|
||
assert index.getClassByName("org.jboss.jandex.maven.jar.SomeClass") != null | ||
assert index.getClassByName("org.jboss.jandex.MethodParameterInfo") != null | ||
assert index.getClassByName("io.smallrye.common.annotation.Experimental") != null |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
181 changes: 181 additions & 0 deletions
181
maven-plugin/src/main/java/org/jboss/jandex/maven/JandexJarGoal.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
package org.jboss.jandex.maven; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.io.OutputStream; | ||
import java.nio.file.Files; | ||
import java.nio.file.Path; | ||
import java.nio.file.StandardCopyOption; | ||
import java.util.Enumeration; | ||
import java.util.List; | ||
import java.util.zip.ZipEntry; | ||
import java.util.zip.ZipFile; | ||
import java.util.zip.ZipOutputStream; | ||
|
||
import org.apache.maven.plugin.AbstractMojo; | ||
import org.apache.maven.plugin.MojoExecutionException; | ||
import org.apache.maven.plugins.annotations.Mojo; | ||
import org.apache.maven.plugins.annotations.Parameter; | ||
import org.jboss.jandex.ClassSummary; | ||
import org.jboss.jandex.Index; | ||
import org.jboss.jandex.IndexWriter; | ||
import org.jboss.jandex.Indexer; | ||
|
||
/** | ||
* Generate a Jandex index inside a given JAR. | ||
*/ | ||
@Mojo(name = "jandex-jar", threadSafe = true) | ||
public class JandexJarGoal extends AbstractMojo { | ||
/** | ||
* The JAR that should be indexed and inside which the index should be stored. | ||
*/ | ||
@Parameter(required = true) | ||
private File jar; | ||
|
||
/** | ||
* Path to the index inside the JAR. Defaults to <code>META-INF/jandex.idx</code>. | ||
*/ | ||
@Parameter(defaultValue = "META-INF/jandex.idx") | ||
private String indexName; | ||
|
||
/** | ||
* Names or glob patterns of files in the JAR that should be indexed. | ||
*/ | ||
@Parameter | ||
private List<String> includes; | ||
|
||
/** | ||
* Names or glob patterns of files in the JAR that should <em>not</em> be indexed. | ||
* Excludes have priority over includes. | ||
*/ | ||
@Parameter | ||
private List<String> excludes; | ||
|
||
@Parameter(defaultValue = "true") | ||
private boolean useDefaultExcludes; | ||
|
||
/** | ||
* Print verbose output (debug output without needing to enable -X for the whole build). | ||
*/ | ||
@Parameter(defaultValue = "false") | ||
private boolean verbose; | ||
|
||
/** | ||
* Skip execution if set. | ||
*/ | ||
@Parameter(property = "jandex.skip", defaultValue = "false") | ||
private boolean skip; | ||
|
||
public void execute() throws MojoExecutionException { | ||
if (skip) { | ||
getLog().info("Jandex execution skipped"); | ||
return; | ||
} | ||
|
||
if (!jar.isFile()) { | ||
getLog().warn("Skipping, expected JAR does not exist or is not a file: " + jar); | ||
return; | ||
} | ||
|
||
Index index = indexJar(); | ||
|
||
getLog().info("Saving Jandex index into JAR: " + jar); | ||
Path tmp = createTempFile("jandextmp"); | ||
try (ZipFile zip = new ZipFile(jar); | ||
ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(tmp.toFile().toPath()))) { | ||
Enumeration<? extends ZipEntry> entries = zip.entries(); | ||
while (entries.hasMoreElements()) { | ||
ZipEntry entry = entries.nextElement(); | ||
if (entry.isDirectory() || entry.getName().equals(indexName)) { | ||
continue; | ||
} | ||
|
||
ZipEntry newEntry = new ZipEntry(entry); | ||
// Compression level and format can vary across implementations | ||
if (newEntry.getMethod() != ZipEntry.STORED) { | ||
newEntry.setCompressedSize(-1); | ||
} | ||
out.putNextEntry(newEntry); | ||
try (InputStream in = zip.getInputStream(entry)) { | ||
copy(in, out); | ||
} | ||
} | ||
|
||
out.putNextEntry(new ZipEntry(indexName)); | ||
new IndexWriter(out).write(index); | ||
} catch (IOException e) { | ||
try { | ||
Files.deleteIfExists(tmp); | ||
} catch (IOException e1) { | ||
e.addSuppressed(e1); | ||
} | ||
throw new MojoExecutionException(e.getMessage(), e); | ||
} | ||
|
||
Path originalJar = jar.toPath(); | ||
Path backupJar = createTempFile("jandexbackup"); | ||
|
||
try { | ||
Files.move(originalJar, backupJar, StandardCopyOption.REPLACE_EXISTING); | ||
Files.move(tmp, originalJar); | ||
Files.delete(backupJar); | ||
} catch (IOException e) { | ||
throw new MojoExecutionException(e.getMessage(), e); | ||
} | ||
} | ||
|
||
private Index indexJar() throws MojoExecutionException { | ||
ArchiveScanner scanner = new ArchiveScanner(jar); | ||
scanner.setFilenameComparator(String::compareTo); | ||
if (useDefaultExcludes) { | ||
scanner.addDefaultExcludes(); | ||
} | ||
if (includes != null) { | ||
scanner.setIncludes(includes.toArray(new String[0])); | ||
} | ||
if (excludes != null) { | ||
scanner.setExcludes(excludes.toArray(new String[0])); | ||
} | ||
scanner.scan(); | ||
String[] filesInJar = scanner.getIncludedFiles(); | ||
|
||
Indexer indexer = new Indexer(); | ||
try (ZipFile zip = new ZipFile(jar)) { | ||
for (String file : filesInJar) { | ||
if (file.endsWith(".class")) { | ||
try (InputStream in = zip.getInputStream(zip.getEntry(file))) { | ||
ClassSummary info = indexer.indexWithSummary(in); | ||
if (isVerbose() && info != null) { | ||
getLog().info("Indexed " + info.name() + " (" + info.annotationsCount() + " annotations)"); | ||
} | ||
} | ||
} | ||
} | ||
} catch (IOException e) { | ||
throw new MojoExecutionException(e.getMessage(), e); | ||
} | ||
return indexer.complete(); | ||
} | ||
|
||
private Path createTempFile(String suffix) throws MojoExecutionException { | ||
try { | ||
return Files.createTempFile(jar.toPath().getParent(), jar.getName(), suffix); | ||
} catch (IOException e) { | ||
throw new MojoExecutionException(e.getMessage(), e); | ||
} | ||
} | ||
|
||
private static void copy(InputStream in, OutputStream out) throws IOException { | ||
byte[] buf = new byte[8192]; | ||
int len; | ||
while ((len = in.read(buf)) > 0) { | ||
out.write(buf, 0, len); | ||
} | ||
out.flush(); | ||
} | ||
|
||
private boolean isVerbose() { | ||
return verbose || getLog().isDebugEnabled(); | ||
} | ||
} |