diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 52d8500..39421fd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -34,7 +34,7 @@ jobs:
java-version-file: .java-version
- name: Set up ja
- uses: Netflix/ja/.github/actions/setup-ja@v0.18.2
+ uses: Netflix/ja/.github/actions/setup-ja@v0.21.1
- name: Test
run: ja test --all
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 5a03577..f02c4ca 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -40,7 +40,7 @@ jobs:
run: echo "BUILD_VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_ENV"
- name: Set up ja
- uses: Netflix/ja/.github/actions/setup-ja@v0.18.2
+ uses: Netflix/ja/.github/actions/setup-ja@v0.21.1
- name: Test
run: ja test --all
diff --git a/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/MavenDeploymentTest.java b/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/MavenDeploymentTest.java
index 61dacb1..eaba8f8 100644
--- a/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/MavenDeploymentTest.java
+++ b/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/MavenDeploymentTest.java
@@ -22,8 +22,10 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.jar.Attributes.Name;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
import java.util.stream.Collectors;
import javax.tools.ToolProvider;
@@ -45,6 +47,86 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
class MavenDeploymentTest {
+ @Test
+ void publishesNamedAutomaticModule(@TempDir Path directory) throws Exception {
+ Path artifacts = Files.createDirectory(directory.resolve("artifacts"));
+ createAutomaticModuleJar("com.example.application",
+ artifacts.resolve("com.example.application.jar"));
+ Files.writeString(artifacts.resolve("com.example.application.pom"),
+ """
+
+ 4.0.0
+ com.example
+ com.example.application
+ 1.2.3
+ jar
+ Example application
+
+
+ org.example
+ example-library
+ 4.5.6
+ compile
+
+
+ com.acme
+ com.acme.library
+ 7.8.9
+
+
+ java.sql
+ java.sql
+ 25
+
+
+
+ """);
+ Path repository = directory.resolve("repository");
+ createMavenAutomaticModule(repository, "com.acme", "library", "7.8.9",
+ "com.acme.library");
+ var upstream = new Builder("test", "default", repository.toUri().toString()).build();
+
+ try (var session = ModuleRepositorySession.create(directory.resolve("session"), List.of(upstream));
+ var deployment = MavenDeployment.create(artifacts, session, "1.2.3")) {
+ Map deployed = deployment.artifacts().stream()
+ .collect(Collectors.toMap(artifact -> artifact.getExtension() + ":" + artifact.getClassifier(), artifact -> artifact));
+ assertEquals(Set.of("pom:", "jar:"), deployed.keySet());
+ Artifact jar = deployed.get("jar:");
+ assertEquals("com.example", jar.getGroupId());
+ assertEquals("com.example.application", jar.getArtifactId());
+ assertEquals("1.2.3", jar.getVersion());
+ Model consumer = readModel(deployed.get("pom:").getPath());
+ assertEquals("Example application", consumer.getName());
+ assertEquals(2, consumer.getDependencies().size());
+ var ordinary = consumer.getDependencies().stream()
+ .filter(dependency -> dependency.getArtifactId().equals("example-library"))
+ .findFirst()
+ .orElseThrow();
+ assertEquals("org.example", ordinary.getGroupId());
+ assertEquals("4.5.6", ordinary.getVersion());
+ var module = consumer.getDependencies().stream()
+ .filter(dependency -> dependency.getArtifactId().equals("library"))
+ .findFirst()
+ .orElseThrow();
+ assertEquals("com.acme", module.getGroupId());
+ assertEquals("7.8.9", module.getVersion());
+ }
+ }
+
+ @Test
+ void rejectsAutomaticModuleWithFilenameDerivedName(@TempDir Path directory) throws Exception {
+ Path artifacts = Files.createDirectory(directory.resolve("artifacts"));
+ try (var _ = new JarOutputStream(Files.newOutputStream(
+ artifacts.resolve("com.example.application.jar")))) {}
+
+ try (var session = ModuleRepositorySession.create(directory.resolve("session"), List.of())) {
+ var failure = assertThrows(IllegalArgumentException.class,
+ () -> MavenDeployment.create(artifacts, session, "1.2.3"));
+ assertEquals("Automatic module has no Automatic-Module-Name: com.example.application.jar",
+ failure.getMessage());
+ }
+ }
+
@Test
void createsConsumerPomFromFlatModuleArtifacts(@TempDir Path directory) throws Exception {
Path artifacts = Files.createDirectory(directory.resolve("artifacts"));
@@ -137,6 +219,25 @@ void appliesPublicationMetadataToTheMatchingModule(@TempDir Path directory) thro
}
}
+ @Test
+ void deploysNamedAutomaticModule(@TempDir Path directory) throws Exception {
+ Path artifacts = Files.createDirectory(directory.resolve("artifacts"));
+ createAutomaticModuleJar("com.example.application",
+ artifacts.resolve("com.example.application.jar"));
+ Path repository = directory.resolve("deployed");
+ var output = new StringWriter();
+ var errors = new StringWriter();
+
+ int result = new Jig().run(new PrintWriter(output, true), new PrintWriter(errors, true),
+ "maven", "deploy", "--module-version", "1.2.3", "--repository",
+ repository.toString(), artifacts.toString());
+
+ assertEquals(0, result, errors.toString());
+ Path deployed = repository.resolve("com/example/com.example.application/1.2.3");
+ assertTrue(Files.isRegularFile(deployed.resolve("com.example.application-1.2.3.jar")));
+ assertTrue(Files.isRegularFile(deployed.resolve("com.example.application-1.2.3.pom")));
+ }
+
@Test
void deploysToARepositorySelectedByPath(@TempDir Path directory) throws Exception {
Path artifacts = Files.createDirectory(directory.resolve("artifacts"));
@@ -256,6 +357,37 @@ private static void createModuleJar(Path directory, String moduleName, Path jar)
.name());
}
+ private static void createAutomaticModuleJar(String moduleName, Path jar) throws Exception {
+ var manifest = new Manifest();
+ manifest.getMainAttributes().put(Name.MANIFEST_VERSION, "1.0");
+ manifest.getMainAttributes().putValue("Automatic-Module-Name", moduleName);
+ try (var _ = new JarOutputStream(Files.newOutputStream(jar), manifest)) {}
+ assertTrue(ModuleFinder.of(jar)
+ .find(moduleName)
+ .orElseThrow()
+ .descriptor()
+ .isAutomatic());
+ }
+
+ private static void createMavenAutomaticModule(Path repository, String groupId,
+ String artifactId, String version, String moduleName) throws Exception {
+ Path directory = repository.resolve(groupId.replace('.', '/'))
+ .resolve(artifactId)
+ .resolve(version);
+ Files.createDirectories(directory);
+ createAutomaticModuleJar(moduleName,
+ directory.resolve(artifactId + "-" + version + ".jar"));
+ Files.writeString(directory.resolve(artifactId + "-" + version + ".pom"),
+ """
+
+ 4.0.0
+ %s
+ %s
+ %s
+
+ """.formatted(groupId, artifactId, version));
+ }
+
private static String metadata(String name) {
return """
diff --git a/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/maven/transport/ModuleIdentityTest.java b/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/ModuleIdentityTest.java
similarity index 98%
rename from src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/maven/transport/ModuleIdentityTest.java
rename to src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/ModuleIdentityTest.java
index 75f7091..ec7b3f4 100644
--- a/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/maven/transport/ModuleIdentityTest.java
+++ b/src/com.netflix.tools.jig.test/com/netflix/tools/jig/test/module/ModuleIdentityTest.java
@@ -12,7 +12,7 @@
* the License.
*/
-package com.netflix.tools.jig.test.module.maven.transport;
+package com.netflix.tools.jig.test.module;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@@ -42,7 +42,7 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import com.netflix.tools.jig.module.maven.transport.AbstractModuleTransporter.ModuleIdentity;
+import com.netflix.tools.jig.module.ModuleIdentity;
import com.netflix.tools.jig.module.maven.transport.ZipCentralDirectory;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
diff --git a/src/com.netflix.tools.jig.test/module-info.hash b/src/com.netflix.tools.jig.test/module-info.hash
index 7c8176e..d3dd09c 100644
--- a/src/com.netflix.tools.jig.test/module-info.hash
+++ b/src/com.netflix.tools.jig.test/module-info.hash
@@ -1,5 +1,5 @@
org.apiguardian.api@1.1.2=module:sha256:8fe700256df67fb279c0734898bf7c25c199ef407ae18b918947b38dfdf0af2a
-org.jspecify@1.0.0=module:sha256:db02318646febd4e03fc69910df454696d58b2be88e7232a0262c3fe0141bd03
+org.jspecify=module:sha256:db02318646febd4e03fc69910df454696d58b2be88e7232a0262c3fe0141bd03
org.junit.jupiter.api@6.1.3=module:sha256:20c0d83d6f2882d9e5d49353c0f2c51acaa1b35d96ec7f3c242530ad0179b89a
org.junit.jupiter.engine@6.1.3=module:sha256:b6dff8c85dc1513bae171968a52a659aaa52dc31fda8b6e48e6e986d1601ed78
org.junit.jupiter.params@6.1.3=module:sha256:691c45b20325740fdb25dea947f22b267161a75a243a2f13ced3f06f88d8bb30
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/Jig.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/Jig.java
index 1fd420b..f1f5b4a 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/Jig.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/Jig.java
@@ -68,11 +68,11 @@
import com.netflix.tools.jig.module.ModuleRepositorySession;
import com.netflix.tools.jig.module.ModuleResolution;
import com.netflix.tools.jig.module.ModuleResolution.IntegrityMode;
+import com.netflix.tools.jig.module.ModuleIdentity;
import com.netflix.tools.jig.module.SourceModule;
import com.netflix.tools.jig.module.SourceModuleFinder;
import com.netflix.tools.jig.module.SourceModuleReference;
import com.netflix.tools.jig.module.Trace;
-import com.netflix.tools.jig.module.maven.transport.AbstractModuleTransporter.ModuleIdentity;
import com.netflix.tools.jig.module.maven.transport.TransporterHttpHandler;
import com.sun.net.httpserver.HttpServer;
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/JigCommandLine.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/JigCommandLine.java
index b12972d..47acd0d 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/JigCommandLine.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/JigCommandLine.java
@@ -110,16 +110,17 @@ final class JigCommandLine {
private final ToolOption manualApproval = flag("--manual", "Wait for manual approval after validation");
private final CommandLine mavenInstallCommandLine = CommandLine.builder()
.description("Install flat module artifacts in the local Maven repository")
+ .option(moduleVersion)
.operand("ARTIFACT-DIRECTORY", "Directory of flat, module-named artifacts", Cardinality.EXACTLY_ONE)
.build();
private final CommandLine mavenDeployCommandLine = CommandLine.builder()
.description("Deploy flat module artifacts to a Maven repository")
- .options(repository, sign)
+ .options(moduleVersion, repository, sign)
.operand("ARTIFACT-DIRECTORY", "Directory of flat, module-named artifacts", Cardinality.EXACTLY_ONE)
.build();
private final CommandLine mavenDeployCentralCommandLine = CommandLine.builder()
.description("Deploy flat module artifacts to Maven Central")
- .options(deploymentName, manualApproval)
+ .options(moduleVersion, deploymentName, manualApproval)
.operand("ARTIFACT-DIRECTORY", "Directory of flat, module-named artifacts", Cardinality.EXACTLY_ONE)
.build();
private final CommandLine mavenCommandLine = CommandLine.builder()
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/MavenCommands.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/MavenCommands.java
index 15d5b89..f880923 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/MavenCommands.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/MavenCommands.java
@@ -49,7 +49,8 @@ static int run(PrintWriter out, PrintWriter err, Supplier");
- out.println(" jig maven deploy --repository [--sign] ");
- out.println(" jig maven deploy-central [--name ] [--manual] ");
+ out.println("Usage: jig maven install [--module-version ] ");
+ out.println(" jig maven deploy [--module-version ] --repository [--sign] ");
+ out.println(" jig maven deploy-central [--module-version ] [--name ] [--manual] ");
out.println();
out.println("Installs or deploys flat, module-named artifacts.");
}
private record Request(Path artifacts, RemoteRepository repository, String name,
- boolean sign, boolean manual) {}
+ String moduleVersion, boolean sign, boolean manual) {}
}
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ArtifactCandidates.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ArtifactCandidates.java
index b0c507f..fd94ae8 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ArtifactCandidates.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ArtifactCandidates.java
@@ -61,6 +61,18 @@ public static Artifact locationCoordinate(String moduleName, String version) {
return new DefaultArtifact(moduleNamespace(moduleName), moduleName, "pom", version);
}
+ /** Returns whether an artifact uses the canonical coordinate for its module name. */
+ public static boolean isLocationCoordinate(Artifact artifact) {
+ return isLocationCoordinate(artifact.getGroupId(), artifact.getArtifactId());
+ }
+
+ /** Returns whether a group and artifact ID form the canonical coordinate for a module name. */
+ public static boolean isLocationCoordinate(String groupId, String artifactId) {
+ return artifactId != null
+ && groupId != null
+ && locationCoordinate(artifactId, null).getGroupId().equals(groupId);
+ }
+
/** Returns the coordinate used by the virtual module location repository. */
public static Artifact moduleLocationCoordinate(String moduleName, String version) {
return new DefaultArtifact(moduleNamespace(moduleName) + ".module", moduleName, "pom", version);
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/MavenDeployment.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/MavenDeployment.java
index 8a614a2..c0f1da4 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/MavenDeployment.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/MavenDeployment.java
@@ -47,6 +47,11 @@ private MavenDeployment(Path temporaryDirectory, List artifacts) {
}
public static MavenDeployment create(Path artifactDirectory, ModuleRepositorySession session) throws IOException {
+ return create(artifactDirectory, session, null);
+ }
+
+ public static MavenDeployment create(Path artifactDirectory, ModuleRepositorySession session,
+ String automaticModuleVersion) throws IOException {
Path directory = artifactDirectory.toAbsolutePath().normalize();
if (!Files.isDirectory(directory)) {
throw new IllegalArgumentException("Maven artifact directory is not a directory: " + directory);
@@ -63,6 +68,10 @@ public static MavenDeployment create(Path artifactDirectory, ModuleRepositorySes
var modules = new LinkedHashMap();
for (Path mainArtifact : mainArtifacts) {
ModuleDescriptor descriptor = descriptor(mainArtifact);
+ if (descriptor.isAutomatic() && ModuleIdentity.parseJar(mainArtifact).moduleName() == null) {
+ throw new IllegalArgumentException("Automatic module has no Automatic-Module-Name: "
+ + mainArtifact.getFileName());
+ }
Path expected = directory.resolve(descriptor.name() + ".jar");
if (!mainArtifact.equals(expected)) {
throw new IllegalArgumentException("Module JAR must be named " + expected.getFileName() + ": " + mainArtifact);
@@ -72,16 +81,45 @@ public static MavenDeployment create(Path artifactDirectory, ModuleRepositorySes
}
}
+ var suppliedPoms = new LinkedHashMap();
+ var moduleVersions = new LinkedHashMap();
for (var entry : modules.entrySet()) {
String moduleName = entry.getKey();
ModuleDescriptor descriptor = entry.getValue();
- String version = descriptor.rawVersion().orElseThrow(() -> new IllegalArgumentException("Module has no version: " + moduleName));
- Artifact coordinate = ArtifactCandidates.locationCoordinate(moduleName, version);
Path modulePom = directory.resolve(moduleName + ".pom");
- Model metadata = Files.isRegularFile(modulePom)
- ? PublicationMetadataReader.read(modulePom)
+ Model suppliedPom = Files.isRegularFile(modulePom)
+ ? descriptor.isAutomatic()
+ ? PublicationMetadataReader.readAutomaticModulePom(modulePom)
+ : PublicationMetadataReader.read(modulePom)
: null;
- Model consumer = consumerPom(metadata, coordinate, descriptor, modules, session);
+ String suppliedVersion = suppliedPom == null ? null : suppliedPom.getVersion();
+ String version = descriptor.rawVersion()
+ .orElseGet(() -> descriptor.isAutomatic() && suppliedVersion != null
+ ? suppliedVersion
+ : automaticModuleVersion);
+ if (version == null || version.isBlank()) {
+ throw new IllegalArgumentException("Module has no version: " + moduleName);
+ }
+ suppliedPoms.put(moduleName, suppliedPom);
+ moduleVersions.put(moduleName, version);
+ }
+
+ for (var entry : modules.entrySet()) {
+ String moduleName = entry.getKey();
+ ModuleDescriptor descriptor = entry.getValue();
+ Path modulePom = directory.resolve(moduleName + ".pom");
+ Model suppliedPom = suppliedPoms.get(moduleName);
+ String version = moduleVersions.get(moduleName);
+ Artifact coordinate = ArtifactCandidates.locationCoordinate(moduleName, version);
+ boolean completePom = descriptor.isAutomatic() && isCompletePom(suppliedPom);
+ if (completePom) {
+ validateAutomaticModulePom(modulePom, suppliedPom, coordinate,
+ automaticModuleVersion);
+ }
+ Model consumer = completePom
+ ? automaticModulePom(suppliedPom, moduleVersions, session)
+ : consumerPom(suppliedPom, coordinate, descriptor, modules, moduleVersions,
+ session);
Path generatedPom = temporaryDirectory.resolve(moduleName + ".pom");
writePom(consumer, generatedPom);
artifacts.add(artifact(coordinate, "pom", "", generatedPom));
@@ -187,18 +225,88 @@ private static ModuleDescriptor descriptor(Path artifact) {
if (references.size() != 1) {
throw new IllegalArgumentException("Artifact does not contain exactly one module: " + artifact);
}
- ModuleDescriptor descriptor = references.iterator()
- .next()
- .descriptor();
- if (descriptor.isAutomatic()) {
- throw new IllegalArgumentException("Artifact does not contain module-info.class: " + artifact);
+ return references.iterator()
+ .next()
+ .descriptor();
+ }
+
+ private static boolean isCompletePom(Model model) {
+ return model != null && (model.getGroupId() != null
+ || model.getArtifactId() != null
+ || model.getVersion() != null
+ || model.getPackaging() != null
+ || !model.getDependencies().isEmpty());
+ }
+
+ private static void validateAutomaticModulePom(Path pom, Model model, Artifact coordinate,
+ String requestedVersion) {
+ if (!coordinate.getGroupId().equals(model.getGroupId())) {
+ throw new IllegalArgumentException(pom.getFileName() + " requires groupId "
+ + coordinate.getGroupId());
+ }
+ if (!coordinate.getArtifactId().equals(model.getArtifactId())) {
+ throw new IllegalArgumentException(pom.getFileName() + " requires artifactId "
+ + coordinate.getArtifactId());
+ }
+ if (!coordinate.getVersion().equals(model.getVersion())) {
+ throw new IllegalArgumentException(pom.getFileName() + " requires version "
+ + coordinate.getVersion());
+ }
+ if (requestedVersion != null && !requestedVersion.equals(model.getVersion())) {
+ throw new IllegalArgumentException(pom.getFileName() + " has version "
+ + model.getVersion() + " but --module-version is " + requestedVersion);
+ }
+ if (model.getPackaging() != null && !"jar".equals(model.getPackaging())) {
+ throw new IllegalArgumentException(pom.getFileName() + " requires packaging jar");
+ }
+ }
+
+ private static Model automaticModulePom(Model supplied, Map localVersions,
+ ModuleRepositorySession session) throws IOException {
+ var dependencies = new ArrayList();
+ for (var dependency : supplied.getDependencies()) {
+ if (!ArtifactCandidates.isLocationCoordinate(dependency.getGroupId(),
+ dependency.getArtifactId())) {
+ dependencies.add(dependency);
+ continue;
+ }
+ String moduleName = dependency.getArtifactId();
+ if (isSystemModule(moduleName)) {
+ continue;
+ }
+ String version = dependency.getVersion();
+ if (version == null || version.isBlank()) {
+ throw new IllegalArgumentException("Required module has no version: " + moduleName);
+ }
+ Artifact coordinate;
+ String localVersion = localVersions.get(moduleName);
+ if (localVersion == null) {
+ coordinate = session.locateModule(moduleName, version);
+ } else {
+ if (!version.equals(localVersion)) {
+ throw new IllegalArgumentException("Required module "
+ + moduleName
+ + "@"
+ + version
+ + " does not match the artifact directory version "
+ + localVersion);
+ }
+ coordinate = ArtifactCandidates.locationCoordinate(moduleName, version);
+ }
+ dependencies.add(Dependency.newBuilder(dependency)
+ .groupId(coordinate.getGroupId())
+ .artifactId(coordinate.getArtifactId())
+ .version(coordinate.getVersion())
+ .build());
}
- return descriptor;
+ return Model.newBuilder(supplied)
+ .dependencies(dependencies)
+ .build();
}
private static Model consumerPom(Model merged, Artifact coordinate, ModuleDescriptor descriptor,
- Map localModules, ModuleRepositorySession session)
- throws IOException {
+ Map localModules, Map localVersions,
+ ModuleRepositorySession session) throws IOException {
var dependencies = new ArrayList();
for (var requirement : descriptor.requires()) {
String name = requirement.name();
@@ -213,7 +321,7 @@ private static Model consumerPom(Model merged, Artifact coordinate, ModuleDescri
if (local == null) {
dependencyCoordinate = session.locateModule(name, version);
} else {
- String localVersion = local.rawVersion().orElseThrow(() -> new IllegalArgumentException("Module has no version: " + name));
+ String localVersion = localVersions.get(name);
if (!version.equals(localVersion)) {
throw new IllegalArgumentException(descriptor.name()
+ " requires "
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ModuleIdentity.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ModuleIdentity.java
new file mode 100644
index 0000000..e2ef33d
--- /dev/null
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/ModuleIdentity.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright 2026 Netflix, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package com.netflix.tools.jig.module;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Provides;
+import java.lang.module.ModuleFinder;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.function.Function;
+import java.util.jar.Attributes.Name;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import javax.lang.model.SourceVersion;
+
+/** Module identity and descriptor metadata observed in a module artifact. */
+public record ModuleIdentity(String moduleName, String osgiModuleName, ModuleDescriptor descriptor,
+ Set packages, String mainClass, Map> provides) {
+
+ private static final Pattern VERSIONED_MODULE_INFO = Pattern.compile("META-INF/versions/(\\d+)/module-info\\.class");
+ private static final Pattern VERSIONED_ENTRY = Pattern.compile("META-INF/versions/(\\d+)/(.+)");
+
+ public ModuleIdentity {
+ if (descriptor != null) {
+ moduleName = descriptor.name();
+ packages = descriptor.packages();
+ mainClass = descriptor.mainClass().orElse(null);
+ var descriptorProvides = new LinkedHashMap>();
+ descriptor.provides().forEach(provide -> descriptorProvides.put(provide.service(), provide.providers()));
+ provides = descriptorProvides;
+ }
+ packages = Set.copyOf(packages);
+ var copiedProvides = new LinkedHashMap>();
+ provides.forEach((service, providers) -> copiedProvides.put(service, List.copyOf(providers)));
+ provides = Map.copyOf(copiedProvides);
+ }
+
+ public static ModuleIdentity parseJarEntries(Set entryNames, Function reader) {
+ Manifest manifest = null;
+ if (entryNames.contains(JarFile.MANIFEST_NAME)) {
+ var bytes = reader.apply(JarFile.MANIFEST_NAME);
+ try {
+ manifest = new Manifest(new ByteArrayInputStream(bytes));
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ var manifestIdentity = manifestIdentity(manifest);
+ var multiRelease = manifest != null && "true".equalsIgnoreCase(manifest.getMainAttributes()
+ .getValue(Name.MULTI_RELEASE));
+ var moduleInfoEntry = findModuleInfo(entryNames, multiRelease);
+ if (moduleInfoEntry != null) {
+ var bytes = reader.apply(moduleInfoEntry);
+ var descriptor = ModuleDescriptor.read(ByteBuffer.wrap(bytes));
+ return new ModuleIdentity(null, null, descriptor, Set.of(), null,
+ Map.of());
+ }
+
+ return new ModuleIdentity(manifestIdentity.moduleName(), manifestIdentity.osgiModuleName(), null,
+ packages(entryNames, multiRelease), manifestIdentity.mainClass(), serviceProviders(entryNames, reader));
+ }
+
+ private static ModuleIdentity manifestIdentity(Manifest manifest) {
+ if (manifest == null) {
+ return new ModuleIdentity(null, null, null, Set.of(), null,
+ Map.of());
+ }
+ var attributes = manifest.getMainAttributes();
+ return new ModuleIdentity(attributes.getValue("Automatic-Module-Name"), osgiModuleName(attributes.getValue("Bundle-SymbolicName")), null,
+ Set.of(), attributes.getValue(Name.MAIN_CLASS), Map.of());
+ }
+
+ private static String osgiModuleName(String header) {
+ if (header == null) {
+ return null;
+ }
+ var parameters = header.indexOf(';');
+ var name = (parameters < 0 ? header : header.substring(0, parameters)).strip();
+ return SourceVersion.isName(name) ? name : null;
+ }
+
+ private static Map> serviceProviders(Set entryNames, Function reader) {
+ var prefix = "META-INF/services/";
+ var provides = new TreeMap>();
+ entryNames.stream()
+ .filter(name -> name.startsWith(prefix) && name.length() > prefix.length())
+ .sorted()
+ .forEach(name -> {
+ var providers = Arrays.stream(new String(reader.apply(name), StandardCharsets.UTF_8).split("\\R"))
+ .map(line -> line.replaceFirst("#.*", "").strip())
+ .filter(line -> !line.isEmpty())
+ .distinct()
+ .toList();
+ if (!providers.isEmpty()) {
+ provides.put(name.substring(prefix.length()), providers);
+ }
+ });
+ return Map.copyOf(provides);
+ }
+
+ private static Set packages(Set entryNames, boolean multiRelease) {
+ var packages = new TreeSet();
+ var runtimeVersion = JarFile.runtimeVersion().feature();
+ for (var original : entryNames) {
+ var entry = original;
+ var versioned = VERSIONED_ENTRY.matcher(entry);
+ if (versioned.matches()) {
+ var version = Integer.parseInt(versioned.group(1));
+ if (!multiRelease || version < JarFile.baseVersion().feature() || version > runtimeVersion) {
+ continue;
+ }
+ entry = versioned.group(2);
+ }
+ if (!entry.endsWith(".class") || entry.equals("module-info.class")) {
+ continue;
+ }
+ var separator = entry.lastIndexOf('/');
+ if (separator <= 0 || entry.startsWith("META-INF/")) {
+ continue;
+ }
+ packages.add(entry.substring(0, separator)
+ .replace('/', '.'));
+ }
+ return Set.copyOf(packages);
+ }
+
+ public static ModuleIdentity parseJar(Path jarPath) {
+ var reference = ModuleFinder.of(jarPath).findAll().stream()
+ .findFirst()
+ .orElseThrow();
+ var descriptor = reference.descriptor();
+ if (!descriptor.isAutomatic()) {
+ return new ModuleIdentity(null, null, descriptor, Set.of(), null,
+ Map.of());
+ }
+
+ var manifestIdentity = manifestIdentity(jarPath);
+ var provides = descriptor.provides().stream()
+ .collect(Collectors.toMap(Provides::service, Provides::providers));
+ return new ModuleIdentity(
+ manifestIdentity.moduleName(),
+ manifestIdentity.osgiModuleName(),
+ null,
+ descriptor.packages(),
+ descriptor.mainClass().orElse(null),
+ provides);
+ }
+
+ private static ModuleIdentity manifestIdentity(Path jarPath) {
+ try (var jar = new JarFile(jarPath.toFile())) {
+ return manifestIdentity(jar.getManifest());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static ModuleIdentity parseJmod(Path jmodPath) {
+ try (var zf = new ZipFile(jmodPath.toFile())) {
+ var entryNames = zf.stream()
+ .map(ZipEntry::getName)
+ .collect(Collectors.toSet());
+ return parseJmodEntries(entryNames, name -> {
+ try (var in = zf.getInputStream(zf.getEntry(name))) {
+ return in.readAllBytes();
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ public static ModuleIdentity parseJmodEntries(Set entryNames, Function reader) {
+ var prefix = "classes/";
+ var classes = entryNames.stream()
+ .filter(name -> name.startsWith(prefix))
+ .map(name -> name.substring(prefix.length()))
+ .collect(Collectors.toSet());
+ return parseJarEntries(classes, name -> reader.apply(prefix + name));
+ }
+
+ private static String findModuleInfo(Set entryNames, boolean multiRelease) {
+ var best = entryNames.contains("module-info.class") ? "module-info.class" : null;
+ if (!multiRelease) {
+ return best;
+ }
+ var highestVersion = -1;
+ var runtimeVersion = JarFile.runtimeVersion().feature();
+ for (var name : entryNames) {
+ var matcher = VERSIONED_MODULE_INFO.matcher(name);
+ if (!matcher.matches()) {
+ continue;
+ }
+ var version = Integer.parseInt(matcher.group(1));
+ if (version >= JarFile.baseVersion().feature() && version <= runtimeVersion && version > highestVersion) {
+ highestVersion = version;
+ best = name;
+ }
+ }
+ return best;
+ }
+}
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/PublicationMetadataReader.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/PublicationMetadataReader.java
index accb00f..b853b18 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/PublicationMetadataReader.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/PublicationMetadataReader.java
@@ -28,7 +28,7 @@
/** Reads the publication metadata contributed by a module POM. */
final class PublicationMetadataReader {
private static final String MODEL_NAMESPACE = "http://maven.apache.org/POM/4.0.0";
- private static final Set ALLOWED_ELEMENTS = Set.of(
+ private static final Set PUBLICATION_ELEMENTS = Set.of(
"modelVersion",
"name",
"description",
@@ -36,12 +36,33 @@ final class PublicationMetadataReader {
"licenses",
"developers",
"scm");
+ private static final Set AUTOMATIC_MODULE_ELEMENTS = Set.of(
+ "modelVersion",
+ "groupId",
+ "artifactId",
+ "version",
+ "packaging",
+ "name",
+ "description",
+ "url",
+ "licenses",
+ "developers",
+ "scm",
+ "dependencies");
private PublicationMetadataReader() {}
static Model read(Path pom) throws IOException {
+ return read(pom, PUBLICATION_ELEMENTS);
+ }
+
+ static Model readAutomaticModulePom(Path pom) throws IOException {
+ return read(pom, AUTOMATIC_MODULE_ELEMENTS);
+ }
+
+ private static Model read(Path pom, Set allowedElements) throws IOException {
Path absolute = pom.toAbsolutePath().normalize();
- validateElements(absolute);
+ validateElements(absolute, allowedElements);
try (var input = Files.newInputStream(absolute)) {
Model model = new MavenStaxReader().read(input);
if (!"4.0.0".equals(model.getModelVersion())) {
@@ -53,7 +74,7 @@ static Model read(Path pom) throws IOException {
}
}
- private static void validateElements(Path pom) throws IOException {
+ private static void validateElements(Path pom, Set allowedElements) throws IOException {
var inputFactory = XMLInputFactory.newFactory();
inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
inputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
@@ -69,7 +90,7 @@ private static void validateElements(Path pom) throws IOException {
throw new IllegalArgumentException(pom.getFileName()
+ " must be a Maven 4.0.0 project model");
}
- if (depth == 2 && !ALLOWED_ELEMENTS.contains(reader.getLocalName())) {
+ if (depth == 2 && !allowedElements.contains(reader.getLocalName())) {
throw new IllegalArgumentException(pom.getFileName()
+ " contains unsupported element "
+ reader.getLocalName());
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/AbstractModuleTransporter.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/AbstractModuleTransporter.java
index 68b176d..bb9c4b6 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/AbstractModuleTransporter.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/AbstractModuleTransporter.java
@@ -20,35 +20,19 @@
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Provides;
-import java.lang.module.ModuleFinder;
import java.net.URI;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HexFormat;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.SequencedSet;
import java.util.Set;
-import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.jar.Attributes.Name;
-import java.util.jar.JarFile;
-import java.util.jar.Manifest;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
-import javax.lang.model.SourceVersion;
import javax.xml.stream.XMLStreamException;
import com.netflix.tools.jig.internal.org.apache.maven.api.metadata.Metadata;
@@ -80,6 +64,7 @@
import com.netflix.tools.jig.internal.org.eclipse.aether.version.Version;
import com.netflix.tools.jig.internal.org.eclipse.aether.version.VersionScheme;
import com.netflix.tools.jig.module.ArtifactCandidates;
+import com.netflix.tools.jig.module.ModuleIdentity;
/**
* Base class for jig's virtual Maven transporters. Provides resolver helpers,
@@ -99,212 +84,6 @@ public abstract class AbstractModuleTransporter extends AbstractTransporter {
private static final HexFormat HEX = HexFormat.of();
- /** Module identity and descriptor metadata observed in a module artifact. */
- public record ModuleIdentity(String moduleName, String osgiModuleName, ModuleDescriptor descriptor,
- Set packages, String mainClass, Map> provides) {
-
- private static final Pattern VERSIONED_MODULE_INFO = Pattern.compile("META-INF/versions/(\\d+)/module-info\\.class");
- private static final Pattern VERSIONED_ENTRY = Pattern.compile("META-INF/versions/(\\d+)/(.+)");
-
- public ModuleIdentity {
- if (descriptor != null) {
- moduleName = descriptor.name();
- packages = descriptor.packages();
- mainClass = descriptor.mainClass().orElse(null);
- var descriptorProvides = new LinkedHashMap>();
- descriptor.provides().forEach(provide -> descriptorProvides.put(provide.service(), provide.providers()));
- provides = descriptorProvides;
- }
- packages = Set.copyOf(packages);
- var copiedProvides = new LinkedHashMap>();
- provides.forEach((service, providers) -> copiedProvides.put(service, List.copyOf(providers)));
- provides = Map.copyOf(copiedProvides);
- }
-
- public static ModuleIdentity parseJarEntries(Set entryNames, Function reader) {
- Manifest manifest = null;
- if (entryNames.contains(JarFile.MANIFEST_NAME)) {
- var bytes = reader.apply(JarFile.MANIFEST_NAME);
- try {
- manifest = new Manifest(new ByteArrayInputStream(bytes));
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
- var manifestIdentity = manifestIdentity(manifest);
- var multiRelease = manifest != null && "true".equalsIgnoreCase(manifest.getMainAttributes()
- .getValue(Name.MULTI_RELEASE));
- var moduleInfoEntry = findModuleInfo(entryNames, multiRelease);
- if (moduleInfoEntry != null) {
- var bytes = reader.apply(moduleInfoEntry);
- var descriptor = ModuleDescriptor.read(ByteBuffer.wrap(bytes));
- return new ModuleIdentity(null, null, descriptor, Set.of(), null,
- Map.of());
- }
-
- return new ModuleIdentity(manifestIdentity.moduleName(), manifestIdentity.osgiModuleName(), null,
- packages(entryNames, multiRelease), manifestIdentity.mainClass(), serviceProviders(entryNames, reader));
- }
-
- private static ModuleIdentity manifestIdentity(Manifest manifest) {
- if (manifest == null) {
- return new ModuleIdentity(null, null, null, Set.of(), null,
- Map.of());
- }
- var attributes = manifest.getMainAttributes();
- return new ModuleIdentity(attributes.getValue("Automatic-Module-Name"), osgiModuleName(attributes.getValue("Bundle-SymbolicName")), null,
- Set.of(), attributes.getValue(Name.MAIN_CLASS), Map.of());
- }
-
- private static String osgiModuleName(String header) {
- if (header == null) {
- return null;
- }
- var parameters = header.indexOf(';');
- var name = (parameters < 0 ? header : header.substring(0, parameters)).strip();
- return SourceVersion.isName(name) ? name : null;
- }
-
- private static Map> serviceProviders(Set entryNames, Function reader) {
- var prefix = "META-INF/services/";
- var provides = new TreeMap>();
- entryNames.stream()
- .filter(name -> name.startsWith(prefix) && name.length() > prefix.length())
- .sorted()
- .forEach(name -> {
- var providers = Arrays.stream(new String(reader.apply(name), StandardCharsets.UTF_8).split("\\R"))
- .map(line -> line.replaceFirst("#.*", "").strip())
- .filter(line -> !line.isEmpty())
- .distinct()
- .toList();
- if (!providers.isEmpty()) {
- provides.put(name.substring(prefix.length()), providers);
- }
- });
- return Map.copyOf(provides);
- }
-
- private static Set packages(Set entryNames, boolean multiRelease) {
- var packages = new TreeSet();
- var runtimeVersion = JarFile.runtimeVersion().feature();
- for (var original : entryNames) {
- var entry = original;
- var versioned = VERSIONED_ENTRY.matcher(entry);
- if (versioned.matches()) {
- var version = Integer.parseInt(versioned.group(1));
- if (!multiRelease || version < JarFile.baseVersion().feature() || version > runtimeVersion) {
- continue;
- }
- entry = versioned.group(2);
- }
- if (!entry.endsWith(".class") || entry.equals("module-info.class")) {
- continue;
- }
- var separator = entry.lastIndexOf('/');
- if (separator <= 0 || entry.startsWith("META-INF/")) {
- continue;
- }
- packages.add(entry.substring(0, separator)
- .replace('/', '.'));
- }
- return Set.copyOf(packages);
- }
-
- public static ModuleIdentity parseJar(Path jarPath) {
- var reference = ModuleFinder.of(jarPath).findAll().stream()
- .findFirst()
- .orElseThrow();
- var descriptor = reference.descriptor();
- if (!descriptor.isAutomatic()) {
- return new ModuleIdentity(null, null, descriptor, Set.of(), null,
- Map.of());
- }
-
- var manifestIdentity = manifestIdentity(jarPath);
- var provides = descriptor.provides().stream()
- .collect(Collectors.toMap(Provides::service, Provides::providers));
- return new ModuleIdentity(
- manifestIdentity.moduleName(),
- manifestIdentity.osgiModuleName(),
- null,
- descriptor.packages(),
- descriptor.mainClass().orElse(null),
- provides);
- }
-
- private static ModuleIdentity manifestIdentity(Path jarPath) {
- try (var jar = new JarFile(jarPath.toFile())) {
- return manifestIdentity(jar.getManifest());
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- private static ModuleIdentity parseJarEntries(Path jarPath) {
- try (var zf = new ZipFile(jarPath.toFile())) {
- var entryNames = zf.stream()
- .map(ZipEntry::getName)
- .collect(Collectors.toSet());
- return parseJarEntries(entryNames, name -> {
- try (var in = zf.getInputStream(zf.getEntry(name))) {
- return in.readAllBytes();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static ModuleIdentity parseJmod(Path jmodPath) {
- try (var zf = new ZipFile(jmodPath.toFile())) {
- var entryNames = zf.stream()
- .map(ZipEntry::getName)
- .collect(Collectors.toSet());
- return parseJmodEntries(entryNames, name -> {
- try (var in = zf.getInputStream(zf.getEntry(name))) {
- return in.readAllBytes();
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- }
-
- public static ModuleIdentity parseJmodEntries(Set entryNames, Function reader) {
- var prefix = "classes/";
- var classes = entryNames.stream()
- .filter(name -> name.startsWith(prefix))
- .map(name -> name.substring(prefix.length()))
- .collect(Collectors.toSet());
- return parseJarEntries(classes, name -> reader.apply(prefix + name));
- }
-
- private static String findModuleInfo(Set entryNames, boolean multiRelease) {
- var best = entryNames.contains("module-info.class") ? "module-info.class" : null;
- if (!multiRelease) {
- return best;
- }
- var highestVersion = -1;
- var runtimeVersion = JarFile.runtimeVersion().feature();
- for (var name : entryNames) {
- var matcher = VERSIONED_MODULE_INFO.matcher(name);
- if (!matcher.matches()) {
- continue;
- }
- var version = Integer.parseInt(matcher.group(1));
- if (version >= JarFile.baseVersion().feature() && version <= runtimeVersion && version > highestVersion) {
- highestVersion = version;
- best = name;
- }
- }
- return best;
- }
- }
-
private static final String IDENTITY_CACHE_KEY = "jig.module.identity.cache";
private static final String BOM_CACHE_KEY = "jig.module.bom.cache";
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/JdkTransporter.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/JdkTransporter.java
index 3cb3ee7..051bcf0 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/JdkTransporter.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/JdkTransporter.java
@@ -105,7 +105,7 @@
import com.netflix.tools.jig.internal.org.eclipse.aether.util.FileUtils;
import com.netflix.tools.jig.internal.org.eclipse.aether.util.FileUtils.CollocatedTempFile;
import com.netflix.tools.jig.internal.org.eclipse.aether.util.FileUtils.TempFile;
-import com.netflix.tools.jig.module.maven.transport.AbstractModuleTransporter.ModuleIdentity;
+import com.netflix.tools.jig.module.ModuleIdentity;
import com.netflix.tools.jig.module.maven.transport.JdkHttpClientState.AuthenticationScope;
import com.netflix.tools.jig.module.maven.transport.JdkHttpClientState.ClientProfile;
import com.netflix.tools.jig.module.maven.transport.JdkHttpClientState.ProxyProfile;
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/MavenModuleProbe.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/MavenModuleProbe.java
index 2dea6d2..9ae2035 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/MavenModuleProbe.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/MavenModuleProbe.java
@@ -17,7 +17,7 @@
import java.util.Objects;
import java.util.function.Supplier;
-import com.netflix.tools.jig.module.maven.transport.AbstractModuleTransporter.ModuleIdentity;
+import com.netflix.tools.jig.module.ModuleIdentity;
/**
* Scoped probe for module identity via the Maven transport layer.
diff --git a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/ModuleProxyTransporter.java b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/ModuleProxyTransporter.java
index 5921711..7a22f63 100644
--- a/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/ModuleProxyTransporter.java
+++ b/src/com.netflix.tools.jig/com/netflix/tools/jig/module/maven/transport/ModuleProxyTransporter.java
@@ -69,6 +69,7 @@
import com.netflix.tools.jig.module.ArtifactCandidates;
import com.netflix.tools.jig.module.MavenArtifactOrigin;
import com.netflix.tools.jig.module.MavenDependency;
+import com.netflix.tools.jig.module.ModuleIdentity;
/**
* Maps Maven artifacts into the canonical module coordinate space.
@@ -286,11 +287,11 @@ private static String resolutionContext(String path) {
}
}
Artifact requested = parseArtifactPath(contentPath);
- if (requested != null && isCanonical(requested)) {
+ if (requested != null && ArtifactCandidates.isLocationCoordinate(requested)) {
return "resolve " + requested.getArtifactId() + "@" + requested.getVersion();
}
Artifact metadata = parseMetadataPath(URI.create(contentPath));
- if (metadata != null && isCanonical(metadata)) {
+ if (metadata != null && ArtifactCandidates.isLocationCoordinate(metadata)) {
return "resolve " + metadata.getArtifactId() + " versions";
}
return null;
@@ -312,14 +313,14 @@ private Resource resourceInContext(String path) throws Exception {
}
Artifact metadata = parseMetadataPath(URI.create(path));
- if (metadata != null && isCanonical(metadata)) {
+ if (metadata != null && ArtifactCandidates.isLocationCoordinate(metadata)) {
trace("generate canonical metadata %s:%s", metadata.getGroupId(), metadata.getArtifactId());
var model = metadataModel(metadata);
return generatedResource(output -> serializeMetadata(output, model));
}
Artifact requested = parseArtifactPath(path);
- if (requested == null || !isCanonical(requested)) {
+ if (requested == null || !ArtifactCandidates.isLocationCoordinate(requested)) {
throw new FileNotFoundException(path);
}
trace("canonical resource %s", requested);
@@ -705,9 +706,4 @@ private void recordLocation(String moduleName, Artifact target) throws IOExcepti
}
}
- private static boolean isCanonical(Artifact artifact) {
- return ArtifactCandidates.locationCoordinate(artifact.getArtifactId(), null)
- .getGroupId()
- .equals(artifact.getGroupId());
- }
}