Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,16 @@ public final class Constants {
public static final String MAVEN_VERSION_RANGE_RESOLVER_NATURE_OVERRIDE =
"maven.versionRangeResolver.natureOverride";

/**
* Comma-separated list of XML contexts/fields to intern during POM parsing for memory optimization.
* When not specified, a default set of commonly repeated contexts will be used.
* Example: "groupId,artifactId,version,scope,type"
*
* @since 4.0.0
*/
@Config
public static final String MAVEN_MODEL_BUILDER_INTERNS = "maven.modelBuilder.interns";

/**
* All system properties used by Maven Logger start with this prefix.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ private Model doRead(XmlReaderRequest request) throws XmlReaderException {
source = new InputSource(
request.getModelId(), path != null ? path.toUri().toString() : null);
}
MavenStaxReader xml = new MavenStaxReader();
MavenStaxReader xml = request.getTransformer() != null
? new MavenStaxReader(request.getTransformer()::transform)
: new MavenStaxReader();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
if (inputStream != null) {
return xml.read(inputStream, request.isStrict(), source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ public PluginDescriptor read(@Nonnull XmlReaderRequest request) throws XmlReader
throw new IllegalArgumentException("path, url, reader or inputStream must be non null");
}
try {
PluginDescriptorStaxReader xml = new PluginDescriptorStaxReader();
PluginDescriptorStaxReader xml = request.getTransformer() != null
? new PluginDescriptorStaxReader(request.getTransformer()::transform)
: new PluginDescriptorStaxReader();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
if (inputStream != null) {
return xml.read(inputStream, request.isStrict());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ public Settings read(@Nonnull XmlReaderRequest request) throws XmlReaderExceptio
if (request.getModelId() != null || request.getLocation() != null) {
source = new InputSource(request.getLocation());
}
SettingsStaxReader xml = new SettingsStaxReader();
SettingsStaxReader xml = request.getTransformer() != null
? new SettingsStaxReader(request.getTransformer()::transform)
: new SettingsStaxReader();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
if (reader != null) {
return xml.read(reader, request.isStrict(), source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ public PersistedToolchains read(@Nonnull XmlReaderRequest request) throws XmlRea
if (request.getModelId() != null || request.getLocation() != null) {
source = new InputSource(request.getLocation());
}
MavenToolchainsStaxReader xml = new MavenToolchainsStaxReader();
MavenToolchainsStaxReader xml = request.getTransformer() != null
? new MavenToolchainsStaxReader(request.getTransformer()::transform)
: new MavenToolchainsStaxReader();
xml.setAddDefaultEntities(request.isAddDefaultEntities());
if (reader != null) {
return xml.read(reader, request.isStrict(), source);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
Expand Down Expand Up @@ -1254,7 +1255,7 @@ Model doReadFileModel() throws ModelBuilderException {
.path(modelSource.getPath())
.rootDirectory(rootDirectory)
.inputStream(is)
.transformer(new InliningTransformer())
.transformer(new InterningTransformer(session))
.build());
} catch (XmlReaderException e) {
if (!strict) {
Expand All @@ -1267,7 +1268,7 @@ Model doReadFileModel() throws ModelBuilderException {
.path(modelSource.getPath())
.rootDirectory(rootDirectory)
.inputStream(is)
.transformer(new InliningTransformer())
.transformer(new InterningTransformer(session))
.build());
} catch (XmlReaderException ne) {
// still unreadable even in non-strict mode, rethrow original error
Expand Down Expand Up @@ -2144,23 +2145,94 @@ public R getRequest() {
}
}

static class InliningTransformer implements XmlReaderRequest.Transformer {
static final Set<String> CONTEXTS = Set.of(
static class InterningTransformer implements XmlReaderRequest.Transformer {
static final Set<String> DEFAULT_CONTEXTS = Set.of(
// Core Maven coordinates
"groupId",
"artifactId",
"version",
"namespaceUri",
"packaging",

// Dependency-related fields
"scope",
"type",
"classifier",

// Build and plugin-related fields
"phase",
"goal",
"execution",

// Repository-related fields
"layout",
"policy",
"checksumPolicy",
"updatePolicy");
"updatePolicy",

// Common metadata fields
"modelVersion",
"name",
"url",
"system",
"distribution",
"status",

// SCM fields
"connection",
"developerConnection",
"tag",

// Common enum-like values that appear frequently
"id",
"inherited",
"optional");

private final Set<String> contexts;

/**
* Creates an InterningTransformer with default contexts.
*/
InterningTransformer() {
this.contexts = DEFAULT_CONTEXTS;
}

/**
* Creates an InterningTransformer with contexts from session properties.
*
* @param session the Maven session to read properties from
*/
InterningTransformer(Session session) {
this.contexts = parseContextsFromSession(session);
}

private Set<String> parseContextsFromSession(Session session) {
String contextsProperty = session.getUserProperties().get(Constants.MAVEN_MODEL_BUILDER_INTERNS);
if (contextsProperty == null) {
contextsProperty = session.getSystemProperties().get(Constants.MAVEN_MODEL_BUILDER_INTERNS);
}

if (contextsProperty == null || contextsProperty.trim().isEmpty()) {
return DEFAULT_CONTEXTS;
}

return Arrays.stream(contextsProperty.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.collect(Collectors.toSet());
}

@Override
public String transform(String input, String context) {
return CONTEXTS.contains(context) ? input.intern() : input;
return input != null && contexts.contains(context) ? input.intern() : input;
}

/**
* Get the contexts that will be interned by this transformer.
* Used for testing purposes.
*/
Set<String> getContexts() {
return contexts;
}
}
}
Loading
Loading