diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
index f9f788e00316..dc1e0c3650c8 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/DependencyScope.java
@@ -62,9 +62,22 @@ public enum DependencyScope {
COMPILE_ONLY("compile-only", false),
/**
- * Compile, runtime and test.
+ * Compile, runtime and test (non-transitive).
+ *
+ * Note: If a project uses this scope and doesn't explicitly opt-in to
+ * Maven 4 modelVersion (e.g., 4.1.0) through other features, the generated
+ * consumer POM may be downgraded to 4.0.0. In this case, downstream resolvers
+ * will remap this scope to {@code api} for backward compatibility, making it
+ * behave transitively again. To enforce non-transitive behavior, the project
+ * must ensure its modelVersion is preserved (e.g., via {@code preserveModelVersion=true}).
+ *
*/
- COMPILE("compile", true),
+ COMPILE("compile", false),
+
+ /**
+ * Compile, runtime and test, transitively.
+ */
+ API("api", true),
/**
* Runtime and test.
diff --git a/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java b/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java
index bd8a6f1bf51c..16188f23ca15 100644
--- a/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java
+++ b/api/maven-api-core/src/main/java/org/apache/maven/api/PathScope.java
@@ -58,15 +58,17 @@ public interface PathScope extends ExtensibleEnum {
ProjectScope.MAIN,
DependencyScope.COMPILE_ONLY,
DependencyScope.COMPILE,
+ DependencyScope.API,
DependencyScope.PROVIDED);
- PathScope MAIN_RUNTIME =
- pathScope("main-runtime", ProjectScope.MAIN, DependencyScope.COMPILE, DependencyScope.RUNTIME);
+ PathScope MAIN_RUNTIME = pathScope(
+ "main-runtime", ProjectScope.MAIN, DependencyScope.COMPILE, DependencyScope.API, DependencyScope.RUNTIME);
PathScope TEST_COMPILE = pathScope(
"test-compile",
ProjectScope.TEST,
DependencyScope.COMPILE,
+ DependencyScope.API,
DependencyScope.PROVIDED,
DependencyScope.TEST_ONLY,
DependencyScope.TEST);
@@ -75,6 +77,7 @@ public interface PathScope extends ExtensibleEnum {
"test-runtime",
ProjectScope.TEST,
DependencyScope.COMPILE,
+ DependencyScope.API,
DependencyScope.RUNTIME,
DependencyScope.PROVIDED,
DependencyScope.TEST,
diff --git a/compat/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java b/compat/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java
index 9c3555aefff7..7a9618e77267 100644
--- a/compat/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java
+++ b/compat/maven-model/src/test/java/org/apache/maven/model/v4/MavenModelVersionTest.java
@@ -20,8 +20,11 @@
import java.io.InputStream;
import java.util.Collections;
+import java.util.List;
import org.apache.maven.api.model.Build;
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.model.DependencyManagement;
import org.apache.maven.api.model.Model;
import org.apache.maven.api.model.Plugin;
import org.apache.maven.api.model.PluginExecution;
@@ -72,4 +75,57 @@ void testV4ModelPriority() {
PluginExecution.newInstance().withPriority(5))))));
assertEquals("4.0.0", new MavenModelVersion().getModelVersion(m));
}
+
+ @Test
+ void testApiScopeDependencyRequires410() {
+ // A model with an api-scoped dependency should require modelVersion 4.1.0
+ Model m = model.withDependencies(List.of(Dependency.newBuilder()
+ .groupId("org.example")
+ .artifactId("api-lib")
+ .version("1.0")
+ .scope("api")
+ .build()));
+ assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+ }
+
+ @Test
+ void testApiScopeInDependencyManagementRequires410() {
+ // A model with an api-scoped dependency in dependencyManagement should require 4.1.0
+ Model m = model.withDependencyManagement(DependencyManagement.newBuilder()
+ .dependencies(List.of(Dependency.newBuilder()
+ .groupId("org.example")
+ .artifactId("api-lib")
+ .version("1.0")
+ .scope("api")
+ .build()))
+ .build());
+ assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+ }
+
+ @Test
+ void testCompileScopeDependencyRemains400() {
+ // A model with only compile-scoped dependencies should stay at 4.0.0
+ Model m = model.withDependencies(List.of(Dependency.newBuilder()
+ .groupId("org.example")
+ .artifactId("compile-lib")
+ .version("1.0")
+ .scope("compile")
+ .build()));
+ assertEquals("4.0.0", new MavenModelVersion().getModelVersion(m));
+ }
+
+ @Test
+ void testApiScopeInProfileRequires410() {
+ // A model with an api-scoped dependency in a profile should require 4.1.0
+ Model m = model.withProfiles(List.of(org.apache.maven.api.model.Profile.newBuilder()
+ .id("my-profile")
+ .dependencies(List.of(Dependency.newBuilder()
+ .groupId("org.example")
+ .artifactId("api-lib")
+ .version("1.0")
+ .scope("api")
+ .build()))
+ .build()));
+ assertEquals("4.1.0", new MavenModelVersion().getModelVersion(m));
+ }
}
diff --git a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/Maven4ScopeManagerConfiguration.java b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/Maven4ScopeManagerConfiguration.java
index a38833076355..8cec4de3667d 100644
--- a/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/Maven4ScopeManagerConfiguration.java
+++ b/compat/maven-resolver-provider/src/main/java/org/apache/maven/repository/internal/scopes/Maven4ScopeManagerConfiguration.java
@@ -90,6 +90,8 @@ public Collection buildDependencyScope
ArrayList result = new ArrayList<>();
result.add(internalScopeManager.createDependencyScope(
DependencyScope.COMPILE.id(), DependencyScope.COMPILE.isTransitive(), all()));
+ result.add(internalScopeManager.createDependencyScope(
+ DependencyScope.API.id(), DependencyScope.API.isTransitive(), all()));
result.add(internalScopeManager.createDependencyScope(
DependencyScope.RUNTIME.id(),
DependencyScope.RUNTIME.isTransitive(),
diff --git a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
index 5aba71386686..2bc05fe854fd 100644
--- a/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
+++ b/impl/maven-core/src/main/java/org/apache/maven/internal/transformation/impl/DefaultConsumerPomBuilder.java
@@ -257,7 +257,7 @@ private Model buildEffectiveModel(RepositorySystemSession session, MavenProject
}
return dependency;
});
- // Only keep transitive scopes (null/empty => COMPILE)
+ // Only keep consumer-visible scopes (compile, api, runtime)
directDependencies.values().removeIf(DefaultConsumerPomBuilder::hasDependencyScope);
managedDependencies.keySet().removeAll(directDependencies.keySet());
@@ -275,7 +275,7 @@ private Model buildEffectiveModel(RepositorySystemSession session, MavenProject
Function.identity(),
this::merge,
LinkedHashMap::new));
- // Only keep transitive scopes
+ // Only keep consumer-visible scopes (compile, api, runtime)
directDependencies.values().removeIf(DefaultConsumerPomBuilder::hasDependencyScope);
model = model.withDependencies(directDependencies.isEmpty() ? null : directDependencies.values());
}
@@ -291,7 +291,7 @@ private static boolean hasDependencyScope(Dependency dependency) {
} else {
scope = DependencyScope.forId(scopeId);
}
- return scope == null || !scope.isTransitive();
+ return scope != DependencyScope.COMPILE && scope != DependencyScope.RUNTIME && scope != DependencyScope.API;
}
private Dependency merge(Dependency dep1, Dependency dep2) {
diff --git a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
index 76a9752f5506..e87a97bc8020 100644
--- a/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
+++ b/impl/maven-core/src/test/java/org/apache/maven/internal/transformation/impl/ConsumerPomBuilderTest.java
@@ -276,4 +276,108 @@ void testConsumerPomPassesProjectRepositoriesToModelBuilder() throws Exception {
consumerRequest.getRepositories().stream().anyMatch(r -> "custom-repo".equals(r.getId()));
assertTrue(hasCustomRepo, "Consumer POM model builder request should include the project's custom repository");
}
+
+ @Test
+ void testConsumerPomRetainsCompileApiRuntimeDeps() throws Exception {
+ // Consumer POMs must retain compile, api, and runtime dependencies
+ org.apache.maven.api.model.Dependency compileDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("compile-dep")
+ .version("1")
+ .scope("compile")
+ .build();
+ org.apache.maven.api.model.Dependency apiDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("api-dep")
+ .version("1")
+ .scope("api")
+ .build();
+ org.apache.maven.api.model.Dependency runtimeDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("runtime-dep")
+ .version("1")
+ .scope("runtime")
+ .build();
+ org.apache.maven.api.model.Dependency unscopedDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("unscoped-dep")
+ .version("1")
+ .build();
+
+ Model model = Model.newBuilder()
+ .groupId("test")
+ .artifactId("test")
+ .version("1.0")
+ .dependencies(List.of(compileDep, apiDep, runtimeDep, unscopedDep))
+ .build();
+
+ Model transformed = DefaultConsumerPomBuilder.transformNonPom(model, null);
+ assertNotNull(transformed.getDependencies());
+ // All four should be retained
+ assertTrue(
+ transformed.getDependencies().stream().anyMatch(d -> "compile-dep".equals(d.getArtifactId())),
+ "compile-scoped dep should be retained");
+ assertTrue(
+ transformed.getDependencies().stream().anyMatch(d -> "api-dep".equals(d.getArtifactId())),
+ "api-scoped dep should be retained");
+ assertTrue(
+ transformed.getDependencies().stream().anyMatch(d -> "runtime-dep".equals(d.getArtifactId())),
+ "runtime-scoped dep should be retained");
+ assertTrue(
+ transformed.getDependencies().stream().anyMatch(d -> "unscoped-dep".equals(d.getArtifactId())),
+ "unscoped (default compile) dep should be retained");
+ }
+
+ @Test
+ void testConsumerPomStripsProvidedTestSystemDeps() throws Exception {
+ // Consumer POMs must strip provided, test, and system dependencies
+ org.apache.maven.api.model.Dependency compileDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("compile-dep")
+ .version("1")
+ .scope("compile")
+ .build();
+ org.apache.maven.api.model.Dependency providedDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("provided-dep")
+ .version("1")
+ .scope("provided")
+ .build();
+ org.apache.maven.api.model.Dependency testDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("test-dep")
+ .version("1")
+ .scope("test")
+ .build();
+ org.apache.maven.api.model.Dependency systemDep = org.apache.maven.api.model.Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("system-dep")
+ .version("1")
+ .scope("system")
+ .build();
+
+ Model model = Model.newBuilder()
+ .groupId("test")
+ .artifactId("test")
+ .version("1.0")
+ .dependencies(List.of(compileDep, providedDep, testDep, systemDep))
+ .build();
+
+ Model transformed = DefaultConsumerPomBuilder.transformNonPom(model, null);
+ assertNotNull(transformed.getDependencies());
+ // compile should be retained
+ assertTrue(
+ transformed.getDependencies().stream().anyMatch(d -> "compile-dep".equals(d.getArtifactId())),
+ "compile-scoped dep should be retained");
+ // provided, test, system should be stripped
+ assertFalse(
+ transformed.getDependencies().stream().anyMatch(d -> "provided-dep".equals(d.getArtifactId())),
+ "provided-scoped dep should be stripped");
+ assertFalse(
+ transformed.getDependencies().stream().anyMatch(d -> "test-dep".equals(d.getArtifactId())),
+ "test-scoped dep should be stripped");
+ assertFalse(
+ transformed.getDependencies().stream().anyMatch(d -> "system-dep".equals(d.getArtifactId())),
+ "system-scoped dep should be stripped");
+ }
}
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
index 0c8739a22ade..6211f14d947b 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/model/DefaultModelValidator.java
@@ -1239,7 +1239,8 @@ private void validate20RawDependencies(
String scope = dependency.getScope();
if (DependencyScope.COMPILE_ONLY.id().equals(scope)
|| DependencyScope.TEST_ONLY.id().equals(scope)
- || DependencyScope.TEST_RUNTIME.id().equals(scope)) {
+ || DependencyScope.TEST_RUNTIME.id().equals(scope)
+ || DependencyScope.API.id().equals(scope)) {
addViolation(
problems,
Severity.ERROR,
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
index 4283cfceaec2..433f3cfb5b34 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReader.java
@@ -345,6 +345,12 @@ private int getPolicy(RepositorySystemSession session, Artifact a, ArtifactDescr
private void populateResult(InternalSession session, ArtifactDescriptorResult result, Model model) {
ArtifactTypeRegistry stereotypes = session.getSession().getArtifactTypeRegistry();
+ // Compute once whether compile-scoped dependencies should be remapped to api (transitive)
+ // for backward compatibility. Use the declared modelVersion rather than feature detection
+ // to respect the developer's explicit intent.
+ String declaredModelVersion = model.getModelVersion();
+ boolean remapCompileToApi = declaredModelVersion == null || declaredModelVersion.startsWith("4.0.");
+
for (Repository repository : model.getRepositories()) {
result.addRepository(session.toRepository(
session.getService(RepositoryFactory.class).createRemote(repository)));
@@ -355,7 +361,7 @@ private void populateResult(InternalSession session, ArtifactDescriptorResult re
logger.debug("Filtered dependency with uninterpolated expression: {}", dependency);
continue;
}
- result.addDependency(convert(dependency, stereotypes));
+ result.addDependency(convert(dependency, stereotypes, remapCompileToApi));
}
DependencyManagement dependencyManagement = model.getDependencyManagement();
@@ -365,7 +371,7 @@ private void populateResult(InternalSession session, ArtifactDescriptorResult re
logger.debug("Filtered managed dependency with uninterpolated expression: {}", dependency);
continue;
}
- result.addManagedDependency(convert(dependency, stereotypes));
+ result.addManagedDependency(convert(dependency, stereotypes, remapCompileToApi));
}
}
@@ -391,7 +397,10 @@ private void populateResult(InternalSession session, ArtifactDescriptorResult re
setArtifactProperties(result, model);
}
- private Dependency convert(org.apache.maven.api.model.Dependency dependency, ArtifactTypeRegistry stereotypes) {
+ private Dependency convert(
+ org.apache.maven.api.model.Dependency dependency,
+ ArtifactTypeRegistry stereotypes,
+ boolean remapCompileToApi) {
ArtifactType stereotype = stereotypes.get(dependency.getType());
if (stereotype == null) {
stereotype = new DefaultType(dependency.getType(), Language.NONE, dependency.getType(), null, false)
@@ -420,11 +429,13 @@ private Dependency convert(org.apache.maven.api.model.Dependency dependency, Art
exclusions.add(convert(exclusion));
}
+ String scope = dependency.getScope() != null ? dependency.getScope() : "";
+ if (remapCompileToApi && ("compile".equals(scope) || scope.isEmpty())) {
+ scope = "api";
+ }
+
return new Dependency(
- artifact,
- dependency.getScope(),
- dependency.getOptional() != null ? dependency.isOptional() : null,
- exclusions);
+ artifact, scope, dependency.getOptional() != null ? dependency.isOptional() : null, exclusions);
}
private Exclusion convert(org.apache.maven.api.model.Exclusion exclusion) {
diff --git a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/scopes/Maven4ScopeManagerConfiguration.java b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/scopes/Maven4ScopeManagerConfiguration.java
index 896b240053f6..8c64bc31f00c 100644
--- a/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/scopes/Maven4ScopeManagerConfiguration.java
+++ b/impl/maven-impl/src/main/java/org/apache/maven/impl/resolver/scopes/Maven4ScopeManagerConfiguration.java
@@ -88,6 +88,8 @@ public Collection buildDependencyScope
ArrayList result = new ArrayList<>();
result.add(internalScopeManager.createDependencyScope(
DependencyScope.COMPILE.id(), DependencyScope.COMPILE.isTransitive(), all()));
+ result.add(internalScopeManager.createDependencyScope(
+ DependencyScope.API.id(), DependencyScope.API.isTransitive(), all()));
result.add(internalScopeManager.createDependencyScope(
DependencyScope.RUNTIME.id(),
DependencyScope.RUNTIME.isTransitive(),
diff --git a/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReaderTest.java b/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReaderTest.java
new file mode 100644
index 000000000000..d5051078787b
--- /dev/null
+++ b/impl/maven-impl/src/test/java/org/apache/maven/impl/resolver/DefaultArtifactDescriptorReaderTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.maven.impl.resolver;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+
+import org.apache.maven.api.model.Dependency;
+import org.apache.maven.api.services.ModelBuilder;
+import org.eclipse.aether.artifact.ArtifactType;
+import org.eclipse.aether.artifact.ArtifactTypeRegistry;
+import org.eclipse.aether.artifact.DefaultArtifactType;
+import org.eclipse.aether.impl.ArtifactResolver;
+import org.eclipse.aether.impl.RepositoryEventDispatcher;
+import org.eclipse.aether.impl.VersionResolver;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class DefaultArtifactDescriptorReaderTest {
+
+ @Test
+ void testRemapCompileToApi() throws Exception {
+ // Create an instance of DefaultArtifactDescriptorReader
+ DefaultArtifactDescriptorReader reader = new DefaultArtifactDescriptorReader(
+ Mockito.mock(VersionResolver.class),
+ Mockito.mock(ArtifactResolver.class),
+ Mockito.mock(ModelBuilder.class),
+ Mockito.mock(RepositoryEventDispatcher.class),
+ Collections.emptyMap());
+
+ // Get the private convert() method via reflection
+ Method convertMethod = DefaultArtifactDescriptorReader.class.getDeclaredMethod(
+ "convert", Dependency.class, ArtifactTypeRegistry.class, boolean.class);
+ convertMethod.setAccessible(true);
+
+ // Mock ArtifactTypeRegistry
+ ArtifactTypeRegistry stereotypes = new ArtifactTypeRegistry() {
+ @Override
+ public ArtifactType get(String typeId) {
+ return new DefaultArtifactType(typeId, "jar", "", "java");
+ }
+ };
+
+ // 1. Test remapCompileToApi = true, scope = compile -> api
+ Dependency depCompile = Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("a")
+ .version("1")
+ .type("jar")
+ .scope("compile")
+ .build();
+ org.eclipse.aether.graph.Dependency aetherDep1 =
+ (org.eclipse.aether.graph.Dependency) convertMethod.invoke(reader, depCompile, stereotypes, true);
+ assertEquals("api", aetherDep1.getScope(), "Compile scope should be remapped to api when remap=true");
+
+ // 2. Test remapCompileToApi = true, scope = "" -> api
+ Dependency depEmpty = Dependency.newBuilder()
+ .groupId("g")
+ .artifactId("a")
+ .version("1")
+ .type("jar")
+ .scope("")
+ .build();
+ org.eclipse.aether.graph.Dependency aetherDep2 =
+ (org.eclipse.aether.graph.Dependency) convertMethod.invoke(reader, depEmpty, stereotypes, true);
+ assertEquals("api", aetherDep2.getScope(), "Empty scope should be remapped to api when remap=true");
+
+ // 3. Test remapCompileToApi = false, scope = compile -> compile
+ org.eclipse.aether.graph.Dependency aetherDep3 =
+ (org.eclipse.aether.graph.Dependency) convertMethod.invoke(reader, depCompile, stereotypes, false);
+ assertEquals("compile", aetherDep3.getScope(), "Compile scope should remain compile when remap=false");
+
+ // 4. Test remapCompileToApi = false, scope = "" -> ""
+ org.eclipse.aether.graph.Dependency aetherDep4 =
+ (org.eclipse.aether.graph.Dependency) convertMethod.invoke(reader, depEmpty, stereotypes, false);
+ assertEquals("", aetherDep4.getScope(), "Empty scope should remain empty when remap=false");
+ }
+}
diff --git a/src/mdo/model-version.vm b/src/mdo/model-version.vm
index 0fcca232e44a..b7be7f1c975a 100644
--- a/src/mdo/model-version.vm
+++ b/src/mdo/model-version.vm
@@ -161,11 +161,31 @@ public class ${className} {
#end
#set ( $pfx = "||" )
#end
+ #if ( $v == "4_1_0" && $class.name == "Model" )
+ $pfx hasApiDependency(${var}) // Dependency scope api
+ #end
);
}
#end
#end
+ private boolean hasApiDependency(Model model) {
+ return hasApiDependency((ModelBase) model)
+ || model.getProfiles().stream().anyMatch(this::hasApiDependency);
+ }
+
+ private boolean hasApiDependency(Profile profile) {
+ return hasApiDependency((ModelBase) profile);
+ }
+
+ private boolean hasApiDependency(ModelBase model) {
+ return model != null
+ && (model.getDependencies().stream().anyMatch(dependency -> "api".equals(dependency.getScope()))
+ || (model.getDependencyManagement() != null
+ && model.getDependencyManagement().getDependencies().stream()
+ .anyMatch(dependency -> "api".equals(dependency.getScope()))));
+ }
+
private boolean has(String str) {
return str != null;
}