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 @@ -563,9 +563,8 @@ private List<ProjectBuildingResult> build(File pomFile, boolean recursive) {
File pom = r.getSource().getPath().toFile();
MavenProject project =
projectIndex.get(r.getEffectiveModel().getId());
Path rootDirectory =
rootLocator.findRoot(pom.getParentFile().toPath());
project.setRootDirectory(rootDirectory);
project.setRootDirectory(
rootLocator.findRoot(pom.getParentFile().toPath()));
project.setFile(pom);
project.setExecutionRoot(pom.equals(pomFile));
initProject(project, r);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1217,7 +1217,11 @@ public boolean equals(Object other) {

@Override
public int hashCode() {
return Objects.hash(getGroupId(), getArtifactId(), getVersion());
// Inlined hash avoids Object[] varargs allocation from Objects.hash()
int result = 31 + Objects.hashCode(getGroupId());
result = 31 * result + Objects.hashCode(getArtifactId());
result = 31 * result + Objects.hashCode(getVersion());
return result;
}

public List<Extension> getBuildExtensions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@
public interface InternalSession extends Session {

static InternalSession from(Session session) {
if (session instanceof InternalSession is) {
return is;
}
return cast(InternalSession.class, session, "session should be an " + InternalSession.class);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ public PropertiesAsMap(Map<Object, Object> properties) {
}

@Override
@SuppressWarnings("unchecked")
public Set<Entry<String, String>> entrySet() {
return new AbstractSet<Entry<String, String>>() {
@Override
public Iterator<Entry<String, String>> iterator() {
Iterator<Entry<Object, Object>> iterator = properties.entrySet().iterator();
return new Iterator<Entry<String, String>>() {
Entry<String, String> next;
Entry<Object, Object> next;

{
advance();
Expand All @@ -51,22 +52,7 @@ private void advance() {
while (iterator.hasNext()) {
Entry<Object, Object> e = iterator.next();
if (PropertiesAsMap.matches(e)) {
next = new Entry<String, String>() {
@Override
public String getKey() {
return (String) e.getKey();
}

@Override
public String getValue() {
return (String) e.getValue();
}

@Override
public String setValue(String value) {
return (String) e.setValue(value);
}
};
next = e;
break;
}
}
Expand All @@ -79,21 +65,26 @@ public boolean hasNext() {

@Override
public Entry<String, String> next() {
Entry<String, String> item = next;
Entry<Object, Object> item = next;
if (item == null) {
throw new NoSuchElementException();
}
advance();
return item;
// Safe cast: matches() guarantees both key and value are Strings.
return (Entry<String, String>) (Entry<?, ?>) item;
}
};
}

@Override
public int size() {
return (int) properties.entrySet().stream()
.filter(PropertiesAsMap::matches)
.count();
int count = 0;
for (Entry<Object, Object> e : properties.entrySet()) {
if (PropertiesAsMap.matches(e)) {
count++;
}
}
return count;
}
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,14 @@ public static String unescape(@Nullable String val) {
if (val == null || val.isEmpty()) {
return val;
}
val = val.replace(MARKER, "$");
// Fast path: if the string contains neither the escape marker ($__)
// nor the escape char (\), there is nothing to unescape.
if (val.indexOf(MARKER.charAt(0)) < 0 && val.indexOf(ESCAPE_CHAR) < 0) {
return val;
}
if (val.contains(MARKER)) {
val = val.replace(MARKER, "$");
}
int escape = val.indexOf(ESCAPE_CHAR);
while (escape >= 0 && escape < val.length() - 1) {
char c = val.charAt(escape + 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand Down Expand Up @@ -102,7 +103,19 @@ interface InnerInterpolator {
public Model interpolateModel(
Model model, Path projectDir, ModelBuilderRequest request, ModelProblemCollector problems) {
InnerInterpolator innerInterpolator = createInterpolator(model, projectDir, request, problems);
return new MavenTransformer(innerInterpolator::interpolate).visit(model);
return new MavenTransformer(innerInterpolator::interpolate) {
@Override
protected String transform(String value) {
// Fast path: skip the interpolation callback chain for strings
// that cannot contain variable references (the vast majority).
// This is safe here because this transformer is only used for
// interpolation (${...}), NOT for decryption ({...}).
if (value == null || value.indexOf('$') < 0) {
return value;
}
return super.transform(value);
}
}.visit(model);
}

private InnerInterpolator createInterpolator(
Expand All @@ -113,9 +126,19 @@ private InnerInterpolator createInterpolator(
v -> Optional.ofNullable(callback(model, projectDir, request, problems, v));
UnaryOperator<String> cb = v -> cache.computeIfAbsent(v, ucb).orElse(null);
BinaryOperator<String> postprocessor = (e, v) -> postProcess(projectDir, request, e, v);
// Reuse a single HashSet for cycle detection across all strings in this model.
// The set is cleared after each substVars call returns, avoiding a new HashSet
// allocation per interpolated string (~550 allocations per Camel build).
HashSet<String> cycleMap = new HashSet<>();
// Downcast to access the package-private interpolate() overload that accepts
// an externally-managed cycleMap, allowing us to reuse the same HashSet across
// all strings in this model. Safe because DefaultInterpolator is the only
// implementation bound via DI in the Maven runtime.
DefaultInterpolator di = (DefaultInterpolator) interpolator;
return value -> {
try {
return interpolator.interpolate(value, cb, postprocessor, false);
cycleMap.clear();
return di.interpolate(value, null, cycleMap, cb, postprocessor, false);
} catch (InterpolatorException e) {
problems.add(BuilderProblem.Severity.ERROR, ModelProblem.Version.BASE, e.getMessage(), e);
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,27 @@ private void validateEffectiveDependencies(

String prefix = management ? "dependencyManagement.dependencies.dependency." : "dependencies.dependency.";

// Pre-compute scope validation data once before the loop instead of per-dependency.
// On Camel (676 modules, ~20+ deps each), this avoids thousands of redundant
// InternalSession.from() calls, stream pipelines, and array allocations.
String[] validScopes = null;
if (validationLevel >= ModelValidator.VALIDATION_LEVEL_MAVEN_2_0 && !dependencies.isEmpty()) {
ScopeManager scopeManager =
InternalSession.from(session).getSession().getScopeManager();
if (management) {
Set<String> scopes = scopeManager.getDependencyScopeUniverse().stream()
.map(org.eclipse.aether.scope.DependencyScope::getId)
.collect(Collectors.toCollection(HashSet::new));
scopes.add("import");
validScopes = scopes.toArray(new String[0]);
} else {
validScopes = scopeManager.getDependencyScopeUniverse().stream()
.map(org.eclipse.aether.scope.DependencyScope::getId)
.distinct()
.toArray(String[]::new);
}
}

for (Dependency dependency : dependencies) {
validateEffectiveDependency(problems, dependency, management, prefix, validationLevel);

Expand Down Expand Up @@ -1344,8 +1365,6 @@ private void validateEffectiveDependencies(
* Extensions like Flex Mojos use custom scopes like "merged", "internal", "external", etc. In
* order to not break backward-compat with those, only warn but don't error out.
*/
ScopeManager scopeManager =
InternalSession.from(session).getSession().getScopeManager();
validateDependencyScope(
prefix,
"scope",
Expand All @@ -1355,20 +1374,11 @@ private void validateEffectiveDependencies(
dependency.getScope(),
SourceHint.dependencyManagementKey(dependency),
dependency,
scopeManager.getDependencyScopeUniverse().stream()
.map(org.eclipse.aether.scope.DependencyScope::getId)
.distinct()
.toArray(String[]::new),
validScopes,
false);

validateEffectiveModelAgainstDependency(prefix, problems, model, dependency);
} else {
ScopeManager scopeManager =
InternalSession.from(session).getSession().getScopeManager();
Set<String> scopes = scopeManager.getDependencyScopeUniverse().stream()
.map(org.eclipse.aether.scope.DependencyScope::getId)
.collect(Collectors.toCollection(HashSet::new));
scopes.add("import");
validateDependencyScope(
prefix,
"scope",
Expand All @@ -1378,7 +1388,7 @@ private void validateEffectiveDependencies(
dependency.getScope(),
SourceHint.dependencyManagementKey(dependency),
dependency,
scopes.toArray(new String[0]),
validScopes,
true);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -42,6 +41,8 @@
public class ReflectionValueExtractor {
private static final Object[] OBJECT_ARGS = new Object[0];

private static final List<String> ACCESSOR_PREFIXES = List.of("get", "is", "to", "as");

/**
* Use a WeakHashMap here, so the keys (Class objects) can be garbage collected.
* This approach prevents permgen space overflows due to retention of discarded
Expand Down Expand Up @@ -271,7 +272,7 @@ private static Object getPropertyValue(Object value, String property) throws Int
ClassMap classMap = getClassMap(value.getClass());
String methodBase = Character.toTitleCase(property.charAt(0)) + property.substring(1);
try {
for (String prefix : Arrays.asList("get", "is", "to", "as")) {
for (String prefix : ACCESSOR_PREFIXES) {
Method method = classMap.findMethod(prefix + methodBase);
if (method != null) {
return method.invoke(value, OBJECT_ARGS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
*/
package org.apache.maven.impl.resolver.type;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.apache.maven.api.PathType;
import org.apache.maven.api.Type;
import org.apache.maven.api.services.TypeRegistry;
Expand All @@ -28,16 +31,23 @@

/**
* Adapter between Maven {@link TypeRegistry} and Resolver {@link ArtifactTypeRegistry}.
* <p>
* Results are cached per typeId since type definitions are immutable during a build.
*/
public class TypeRegistryAdapter implements ArtifactTypeRegistry {
private final TypeRegistry typeRegistry;
private final ConcurrentMap<String, ArtifactType> cache = new ConcurrentHashMap<>();

public TypeRegistryAdapter(TypeRegistry typeRegistry) {
this.typeRegistry = requireNonNull(typeRegistry, "typeRegistry");
}

@Override
public ArtifactType get(String typeId) {
return cache.computeIfAbsent(typeId, this::doGet);
}

private ArtifactType doGet(String typeId) {
Type type = typeRegistry.require(typeId);
if (type instanceof ArtifactType artifactType) {
return artifactType;
Expand Down
2 changes: 1 addition & 1 deletion src/mdo/transformer.vm
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public class ${className} {
* The transformation function.
*/
protected String transform(String value) {
return transformer.apply(value);
return value != null ? transformer.apply(value) : null;
}

#foreach ( $class in $model.allClasses )
Expand Down
Loading