Reputation: 35843
Can a Maven extension add an additional profile to a POM (during the build)?
Or are profiles already resolved when Maven extensions run?
Note that I am not talking about Maven plugins, but about Maven extensions.
Upvotes: 0
Views: 77
Reputation: 6063
I do see following option there: try to modify raw xml prior building project object model, something like:
@Component(role = ModelBuilder.class, hint = Hints.DEFAULT_HINT)
public class IMHModelBuilder extends DefaultModelBuilder implements ModelBuilder {
@Override
public ModelBuildingResult build(ModelBuildingRequest request) throws ModelBuildingException {
injectProfiles(request);
return super.build(request);
}
@Override
public ModelBuildingResult build(ModelBuildingRequest request, ModelBuildingResult result) throws ModelBuildingException {
injectProfiles(request);
return super.build(request, result);
}
@Override
public Result<? extends Model> buildRawModel(File pomFile, int validationLevel, boolean locationTracking) {
return super.buildRawModel(pomFile, validationLevel, locationTracking);
}
protected void injectProfiles(ModelBuildingRequest request) {
File pomFile = request.getPomFile();
if (pomFile == null) {
// todo: does the absence of pom file means
// we encountered parent/dependency pom?
return;
}
// todo: do we need to pay attention to request#getRawModel?
// todo: do we need to pay attention to request#getModelSource?
request.setModelSource(new ProfileAwareSource(new FileModelSource(pomFile)));
}
protected InputStream injectProfiles(InputStream inputStream) throws XmlPullParserException, IOException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model projectModel = reader.read(inputStream);
Model profileModel = reader.read(new StringReader(buildProfile()), false);
Profile profile = profileModel.getProfiles().get(0);
// todo: merge with the existing ones
projectModel.getProfiles().add(profile);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
MavenXpp3Writer writer = new MavenXpp3Writer();
writer.write(baos, projectModel);
return new ByteArrayInputStream(baos.toByteArray());
}
protected String buildProfile() {
return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<project>\n" +
" <modelVersion>4.0.0</modelVersion>\n" +
" <groupId>org.apache.maven</groupId>\n" +
" <artifactId>standalone-pom</artifactId>\n" +
" <version>1</version>\n" +
" <packaging>pom</packaging>\n" +
" <name>Maven Stub Project (No POM)</name>\n" +
" <profiles>\n" +
" <profile>\n" +
" <id>myprofile</id>\n" +
" </profile>\n" +
" </profiles>\n" +
"</project>\n";
}
class ProfileAwareSource implements ModelSource2 {
private final ModelSource2 origSource;
public ProfileAwareSource(ModelSource2 origSource) {
this.origSource = origSource;
}
@Override
public ModelSource2 getRelatedSource(String relPath) {
return new ProfileAwareSource(origSource.getRelatedSource(relPath));
}
@Override
public URI getLocationURI() {
return origSource.getLocationURI();
}
@Override
public InputStream getInputStream() throws IOException {
try (InputStream stream = origSource.getInputStream()) {
return injectProfiles(stream);
} catch (XmlPullParserException ex) {
throw new IOException(ex);
}
}
@Override
public String getLocation() {
return origSource.getLocation();
}
}
}
IMO, in case of this approach there are following challenging parts:
flatten-maven-plugin
, for example)pros: such approach seems to be less invasive - even IntelliJ
recognises new profile, although it's maven support is very poor.
Upvotes: 2