Issue
I have a requirement to read plugin configurations in Java. I have used the aether library to get run time dependencies, compile time dependencies etc. But can I use aether to read plugin configurations based in the pom file?
<properties>
<servicePort>8080</servicePort>
<adminPort>8081</adminPort>
</properties>
<build>
<plugins>
<plugin>
<groupId>com.company.group</groupId>
<artifactId>my-plugin</artifactId>
<version>0.1-SNAPSHOT</version>
<configuration>
<myConfig>
<somePropName>someProp</somePropName>
<portMappings>
<someProp>${servicePort}</someProp>
<someProp-admin>${adminPort}</someProp-admin>
</portMappings>
</myConfig>
</configuration>
</plugin>
</plugins>
</build>
I want to be able to resolve
some-Prop 8080
some-prop-admin 8081
from this mechanism
Currently I fetch the compile tie dependencies like this
Dependency dependency = new Dependency(new DefaultArtifact(
coordinate), COMPILE);
CollectRequest collectRequest = new CollectRequest();
collectRequest.setRoot(dependency);
collectRequest.addRepository(this.aetherSession
.getRemoteRepository());
DependencyNode node = this.aetherSession
.getRepoSystem()
.collectDependencies(this.aetherSession.getRepoSession(),
collectRequest).getRoot();
DependencyRequest dependencyRequest = new DependencyRequest();
dependencyRequest.setRoot(node);
result = this.aetherSession
.getRepoSystem()
.resolveDependencies(this.aetherSession.getRepoSession(),
dependencyRequest).getArtifactResults();
FinalResult.addAll(result);
Solution
I don't know if there is a simpler way, but you can use the Aether API to resolve the POM artifact you're interested in, and then build a Maven model from it with the Model Builder API.
First of all, if the coordinates to your artifact isn't to the POM artifact, you need to convert them to the POM artifact by creating a new DefaultArtifact
with the same GAV, but of type "pom"
. To resolve the artifact, you can invoke resolveArtifact
on the repository system, and retrieve the result with getArtifact()
.
Once you have the resolved artifact, you can use maven-model-builder
to build the Maven model from the artifact's file. The ModelBuilder
can be created with DefaultModelBuilderFactory.newInstance()
factory method.
For artifacts that have a parent POM, a ModelResolver
needs to be set on the request to build a Model. However, the only usable implementation with Aether, which is DefaultModelResolver
, is package-private inside maven-aether-provider
so we need to use the Reflection API to construct it. It needs to be injected components that are retrieved with the serviceLocator
returned by MavenRepositorySystemUtils.newServiceLocator()
. This needs to be the same locator with which the Aether session was constructed.
DefaultArtifact artifact = new DefaultArtifact(coordinate);
Artifact pomArtifact = new DefaultArtifact(artifact.getGroupId(), artifact.getArtifactId(), "pom", artifact.getVersion());
ArtifactRequest request = new ArtifactRequest(pomArtifact, Arrays.asList(aetherSession.getRemoteRepository()), null);
pomArtifact = aetherSession.getRepoSystem().resolveArtifact(session, request).getArtifact();
ModelBuilder modelBuilder = new DefaultModelBuilderFactory().newInstance();
ModelBuildingRequest buildingRequest = new DefaultModelBuildingRequest();
buildingRequest.setPomFile(pomArtifact.getFile());
buildingRequest.setProcessPlugins(true);
buildingRequest.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
Constructor<?> constr = Class.forName("org.apache.maven.repository.internal.DefaultModelResolver").getConstructors()[0];
constr.setAccessible(true);
ModelResolver modelResolver = (ModelResolver) constr.newInstance(session, null, null,
serviceLocator.getService(ArtifactResolver.class),
serviceLocator.getService(VersionRangeResolver.class),
serviceLocator.getService(RemoteRepositoryManager.class), request.getRepositories());
buildingRequest.setModelResolver(modelResolver);
Model model = modelBuilder.build(buildingRequest).getEffectiveModel();
Xpp3Dom pluginConfiguration = (Xpp3Dom) model.getBuild().getPluginsAsMap().get("com.company.group:my-plugin").getConfiguration();
Xpp3Dom myConfig = pluginConfiguration.getChild("myConfig");
System.out.println(myConfig.getChild("somePropName").getValue()); // prints "someProp"
By default, the model builder isn't configured to process plugins, so we need to invoke setProcessPlugin(true)
. Once the effective model is obtained, the configuration is contained in a Xpp3Dom
object that you can navigate with the help of getChild(name)
, to get the named child XML element, and getValue()
to get the value of the XML element.
Answered By - Tunaki
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)