diff --git a/manual/Tasks/jar.html b/manual/Tasks/jar.html
index 581ae4bb3..9db18f309 100644
--- a/manual/Tasks/jar.html
+++ b/manual/Tasks/jar.html
@@ -349,6 +349,14 @@ names used for the archives depend on your manifest:
inside the META-INF directory unless the indexmetainf attribute has been set
to true
.
+indexjarsmapper
+
+Since Ant 1.10.9
+
+The nested indexjarsmapper
element can be used to perform custom filename
+transformations for the archives specified by indexjars
if the
+default filename transformation doesn't suffice.
+
service
Since Ant 1.7.0
diff --git a/src/etc/testcases/taskdefs/jar.xml b/src/etc/testcases/taskdefs/jar.xml
index c191ed289..0aaeeefed 100644
--- a/src/etc/testcases/taskdefs/jar.xml
+++ b/src/etc/testcases/taskdefs/jar.xml
@@ -248,7 +248,22 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/org/apache/tools/ant/taskdefs/Jar.java b/src/main/org/apache/tools/ant/taskdefs/Jar.java
index 42f19fbeb..0c7bff952 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Jar.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Jar.java
@@ -50,11 +50,13 @@ import org.apache.tools.ant.taskdefs.Manifest.Section;
import org.apache.tools.ant.types.ArchiveFileSet;
import org.apache.tools.ant.types.EnumeratedAttribute;
import org.apache.tools.ant.types.FileSet;
+import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.ResourceCollection;
import org.apache.tools.ant.types.ZipFileSet;
import org.apache.tools.ant.types.spi.Service;
+import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.StreamUtils;
import org.apache.tools.zip.JarMarker;
@@ -151,6 +153,14 @@ public class Jar extends Zip {
*/
private Path indexJars;
+ /**
+ * A mapper used to convert the jars to entries in the index.
+ *
+ * @since Ant 1.10.9
+ */
+ private FileNameMapper indexJarsMapper = null;
+
+
// CheckStyle:LineLength OFF - Link is too long.
/**
* Strict mode for checking rules of the JAR-Specification.
@@ -405,6 +415,30 @@ public class Jar extends Zip {
indexJars.append(p);
}
+ /**
+ * Add a mapper used to convert the jars to entries in the index.
+ *
+ * @param mapper a mapper
+ * @since Ant 1.10.9
+ */
+ public void addConfiguredIndexJarsMapper(Mapper mapper) {
+ if (indexJarsMapper != null) {
+ throw new BuildException("Cannot define more than one indexjar-mapper",
+ getLocation());
+ }
+ indexJarsMapper = mapper.getImplementation();
+ }
+
+ /**
+ * Returns the mapper used to convert the jars to entries in the index. May be null.
+ *
+ * @since Ant 1.10.9
+ */
+ public FileNameMapper getIndexJarsMapper() {
+ return indexJarsMapper;
+ }
+
+
/**
* A nested SPI service element.
* @param service the nested element.
@@ -597,27 +631,18 @@ public class Jar extends Zip {
writer.println();
if (indexJars != null) {
- Manifest mf = createManifest();
- Manifest.Attribute classpath =
- mf.getMainSection().getAttribute(Manifest.ATTRIBUTE_CLASSPATH);
- String[] cpEntries = null;
- if (classpath != null && classpath.getValue() != null) {
- StringTokenizer tok = new StringTokenizer(classpath.getValue(),
- " ");
- cpEntries = new String[tok.countTokens()];
- int c = 0;
- while (tok.hasMoreTokens()) {
- cpEntries[c++] = tok.nextToken();
- }
+ FileNameMapper mapper = indexJarsMapper;
+ if (mapper == null) {
+ mapper = createDefaultIndexJarsMapper();
}
for (String indexJarEntry : indexJars.list()) {
- String name = findJarName(indexJarEntry, cpEntries);
- if (name != null) {
+ String[] names = mapper.mapFileName(indexJarEntry);
+ if (names != null && names.length > 0) {
ArrayList dirs = new ArrayList<>();
ArrayList files = new ArrayList<>();
grabFilesAndDirs(indexJarEntry, dirs, files);
if (dirs.size() + files.size() > 0) {
- writer.println(name);
+ writer.println(names[0]);
writeIndexLikeList(dirs, files, writer);
writer.println();
}
@@ -636,6 +661,31 @@ public class Jar extends Zip {
}
}
+ /**
+ * Creates a mapper for the index based on the classpath attribute in the manifest.
+ * See {@link #findJarName(String, String[])} for more details.
+ *
+ * @return a mapper
+ * @since Ant 1.10.9
+ */
+ private FileNameMapper createDefaultIndexJarsMapper() {
+ Manifest mf = createManifest();
+ Manifest.Attribute classpath =
+ mf.getMainSection().getAttribute(Manifest.ATTRIBUTE_CLASSPATH);
+ String[] cpEntries = null;
+ if (classpath != null && classpath.getValue() != null) {
+ StringTokenizer tok = new StringTokenizer(classpath.getValue(),
+ " ");
+ cpEntries = new String[tok.countTokens()];
+ int c = 0;
+ while (tok.hasMoreTokens()) {
+ cpEntries[c++] = tok.nextToken();
+ }
+ }
+
+ return new IndexJarsFilenameMapper(cpEntries);
+ }
+
/**
* Overridden from Zip class to deal with manifests and index lists.
* @param is the stream to read data for the entry from. The
@@ -1162,4 +1212,39 @@ public class Jar extends Zip {
return "ignore".equals(getValue()) ? Project.MSG_VERBOSE : Project.MSG_WARN;
}
}
+
+ /**
+ * A mapper for the index based on the classpath attribute in the manifest.
+ * See {@link #findJarName(String, String[])} for more details.
+ *
+ * @since Ant 1.10.9
+ */
+ private static class IndexJarsFilenameMapper implements FileNameMapper {
+
+ private String[] classpath;
+
+ IndexJarsFilenameMapper(String[] classpath) {
+ this.classpath = classpath;
+ }
+
+ /**
+ * Empty implementation.
+ */
+ @Override
+ public void setFrom(String from) {
+ }
+
+ /**
+ * Empty implementation.
+ */
+ @Override
+ public void setTo(String to) {
+ }
+
+ @Override
+ public String[] mapFileName(String sourceFileName) {
+ String result = findJarName(sourceFileName, classpath);
+ return result == null ? null : new String[] {result};
+ }
+ }
}
diff --git a/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java b/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java
index d4e9cd781..21cdd6847 100644
--- a/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java
+++ b/src/tests/junit/org/apache/tools/ant/taskdefs/JarTest.java
@@ -253,6 +253,7 @@ public class JarTest {
ZipEntry ze = archive.getEntry("META-INF/INDEX.LIST");
InputStream is = archive.getInputStream(ze);
BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ boolean foundArchive = false;
boolean foundSub = false;
boolean foundSubFoo = false;
boolean foundFoo = false;
@@ -260,6 +261,9 @@ public class JarTest {
String line = r.readLine();
while (line != null) {
switch (line) {
+ case "tmp.jar":
+ foundArchive = true;
+ break;
case "foo":
foundFoo = true;
break;
@@ -273,6 +277,7 @@ public class JarTest {
line = r.readLine();
}
+ assertTrue(foundArchive);
assertTrue(foundSub);
assertFalse(foundSubFoo);
assertTrue(foundFoo);
@@ -287,8 +292,126 @@ public class JarTest {
}
@Test
- public void testIndexJarsPlusJarMarker() {
+ public void testIndexJarsPlusJarMarker() throws IOException {
buildRule.executeTarget("testIndexJarsPlusJarMarker");
+ try (ZipFile archive = new ZipFile(new File(getOutputDir(), tempJar + "2"))) {
+ ZipEntry ze = archive.getEntry("META-INF/INDEX.LIST");
+ InputStream is = archive.getInputStream(ze);
+ BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ // tmp.jar
+ boolean foundTmp = false;
+ boolean foundA = false;
+ boolean foundAB = false;
+ boolean foundABC = false;
+
+ // tmp2.jar
+ boolean foundTmp2 = false;
+ boolean foundD = false;
+ boolean foundDE = false;
+ boolean foundDEF = false;
+
+ String line = r.readLine();
+ while (line != null) {
+ switch (line) {
+ case "tmp.jar":
+ foundTmp = true;
+ break;
+ case "a":
+ foundA = true;
+ break;
+ case "a/b":
+ foundAB = true;
+ break;
+ case "a/b/c":
+ foundABC = true;
+ break;
+ case "tmp.jar2":
+ foundTmp2 = true;
+ break;
+ case "d":
+ foundD = true;
+ break;
+ case "d/e":
+ foundDE = true;
+ break;
+ case "d/e/f":
+ foundDEF = true;
+ break;
+ }
+ line = r.readLine();
+ }
+
+ assertTrue(foundTmp);
+ assertTrue(foundA);
+ assertTrue(foundAB);
+ assertTrue(foundABC);
+ assertTrue(foundTmp2);
+ assertTrue(foundD);
+ assertTrue(foundDE);
+ assertTrue(foundDEF);
+ }
+ }
+
+ @Test
+ public void testIndexJarsPlusJarMarkerWithMapping() throws IOException {
+ buildRule.executeTarget("testIndexJarsPlusJarMarkerWithMapping");
+ try (ZipFile archive = new ZipFile(new File(getOutputDir(), tempJar + "2"))) {
+ ZipEntry ze = archive.getEntry("META-INF/INDEX.LIST");
+ InputStream is = archive.getInputStream(ze);
+ BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
+ // tmp.jar
+ boolean foundTmp = false;
+ boolean foundA = false;
+ boolean foundAB = false;
+ boolean foundABC = false;
+
+ // tmp2.jar
+ boolean foundTmp2 = false;
+ boolean foundD = false;
+ boolean foundDE = false;
+ boolean foundDEF = false;
+
+ String line = r.readLine();
+ while (line != null) {
+ System.out.println("line = " + line);
+ switch (line) {
+ case "foo/tmp.jar":
+ foundTmp = true;
+ break;
+ case "a":
+ foundA = true;
+ break;
+ case "a/b":
+ foundAB = true;
+ break;
+ case "a/b/c":
+ foundABC = true;
+ break;
+ case "tmp.jar2":
+ foundTmp2 = true;
+ break;
+ case "d":
+ foundD = true;
+ break;
+ case "d/e":
+ foundDE = true;
+ break;
+ case "d/e/f":
+ foundDEF = true;
+ break;
+ }
+ line = r.readLine();
+ }
+
+ assertTrue(foundTmp);
+ assertTrue(foundA);
+ assertTrue(foundAB);
+ assertTrue(foundABC);
+ assertTrue(foundTmp2);
+ assertTrue(foundD);
+ assertTrue(foundDE);
+ assertTrue(foundDEF);
+ }
}
@Test