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 @@ -24,6 +24,7 @@
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.ListUtils;
import org.openrewrite.internal.StringUtils;
import org.openrewrite.maven.AddPlugin;
import org.openrewrite.maven.AddPropertyVisitor;
import org.openrewrite.maven.ChangePluginExecutions;
Expand All @@ -43,6 +44,7 @@

import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;

import static java.util.Collections.emptyList;

Expand All @@ -65,7 +67,10 @@ public class AddMockitoJavaAgentToMavenSurefirePlugin extends Recipe {
final String displayName = "Add Mockito Java Agent to Maven Surefire Plugin";

@Getter
final String description = "Adds required configuration to specifically enable the Mockito/Bytebuddy Java agent in the Maven Surefire plugin for Java 21 compatibility.";
final String description = "Mockito attaches its Byte Buddy agent to the running JVM at test time, which the JDK has " +
"warned about since Java 21 and intends to disallow. This recipe instead loads the agent up front through the " +
"Maven Surefire plugin, adding the `maven-dependency-plugin` `properties` goal to resolve the agent jar path, " +
"to silence the warning and stay ahead of the JDK change.";

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
Expand All @@ -83,7 +88,21 @@ private String getArgLineJavaAgentArgument() {
}

private Xml.Tag buildConfigurationTag(String argLineJavaAgentParam, boolean hasExistingArgLine) {
return Xml.Tag.build(String.format(CONFIGURATION_TAG_TEMPLATE, hasExistingArgLine ? argLineJavaAgentParam : "@{argLine} " + argLineJavaAgentParam));
return Xml.Tag.build(String.format(CONFIGURATION_TAG_TEMPLATE, hasExistingArgLine ? argLineJavaAgentParam : newArgLineValue(argLineJavaAgentParam)));
}

private String newArgLineValue(String argLineJavaAgentParam) {
return usesRuntimeArgLineProperty() ? "@{argLine} " + argLineJavaAgentParam : argLineJavaAgentParam;
}

/**
* The {@code @{argLine}} late replacement, and the empty {@code argLine} property it needs to not be
* passed to the JVM verbatim, are only worth adding when something actually supplies that property.
*/
private boolean usesRuntimeArgLineProperty() {
return getResolutionResult().getPom().getProperties().containsKey("argLine") ||
getResolutionResult().getPom().getPlugins().stream().anyMatch(AddMockitoJavaAgentToMavenSurefirePlugin::isJacocoPlugin) ||
declaresJacocoPlugin(getCursor().firstEnclosingOrThrow(Xml.Document.class));
}

private void maybeAddMavenDependencyPluginWithPropertiesGoal() {
Expand Down Expand Up @@ -132,11 +151,13 @@ public Xml.Document visitDocument(Xml.Document document, ExecutionContext ctx) {
}

maybeAddMavenDependencyPluginWithPropertiesGoal();
doAfterVisit(new AddPropertyVisitor("argLine", "", true));
if (usesRuntimeArgLineProperty()) {
doAfterVisit(new AddPropertyVisitor("argLine", "", true));
}

if (FindPlugin.find(document, "org.apache.maven.plugins", "maven-surefire-plugin").isEmpty()) {
doAfterVisit(new AddPlugin("org.apache.maven.plugins", "maven-surefire-plugin", null,
String.format(CONFIGURATION_TAG_TEMPLATE, "@{argLine} " + getArgLineJavaAgentArgument()), null,
String.format(CONFIGURATION_TAG_TEMPLATE, newArgLineValue(getArgLineJavaAgentArgument())), null,
null, "**/pom.xml").getVisitor());
return document;
}
Expand Down Expand Up @@ -172,11 +193,15 @@ public Xml.Tag visitTag(Xml.Tag tag, ExecutionContext ctx) {
}
if (argLineTagChildren.size() == 1) {
Xml.Tag argLineTag = argLineTagChildren.get(0);
String existingArgLineValue = argLineTag.getValue().orElse("@{argLine}");
String existingArgLineValue = argLineTag.getValue().orElse("");

if (!existingArgLineValue.contains(argLineJavaAgentParam)) {
// An empty argLine carries nothing to preserve, so it is filled in as if it were absent
String mergedArgLine = StringUtils.isBlank(existingArgLineValue) ?
newArgLineValue(argLineJavaAgentParam) :
existingArgLineValue + " " + argLineJavaAgentParam;
List<Content> nonArgLineTags = ListUtils.filter(configContents, content -> content != argLineTag);
Xml.Tag mergedConfiguration = buildConfigurationTag(existingArgLineValue + " " + argLineJavaAgentParam, true);
Xml.Tag mergedConfiguration = buildConfigurationTag(mergedArgLine, true);
Xml.Tag updatedConfig = config.withContent(ListUtils.concatAll(nonArgLineTags, mergedConfiguration.getContent()));
return autoFormat(t.withContent(ListUtils.map(pluginContents, c -> c == config ? updatedConfig : c)), ctx);
}
Expand All @@ -198,6 +223,29 @@ private static boolean isMavenPlugin(Plugin plugin, String artifactId) {
(plugin.getGroupId() == null || MAVEN_PLUGINS_GROUP_ID.equals(plugin.getGroupId()));
}

private static boolean isJacocoPlugin(Plugin plugin) {
return "jacoco-maven-plugin".equals(plugin.getArtifactId()) && "org.jacoco".equals(plugin.getGroupId());
}

/**
* Scans the raw document, as JaCoCo declared in a profile or in {@code pluginManagement} is absent from
* {@link org.openrewrite.maven.tree.ResolvedPom#getPlugins()}.
*/
private static boolean declaresJacocoPlugin(Xml.Document document) {
return new XmlIsoVisitor<AtomicBoolean>() {
@Override
public Xml.Tag visitTag(Xml.Tag tag, AtomicBoolean found) {
if ("plugin".equals(tag.getName()) &&
"jacoco-maven-plugin".equals(tag.getChildValue("artifactId").orElse(null)) &&
"org.jacoco".equals(tag.getChildValue("groupId").orElse(null))) {
found.set(true);
return tag;
}
return super.visitTag(tag, found);
}
}.reduce(document, new AtomicBoolean()).get();
}

private static boolean hasPropertiesGoal(Plugin plugin) {
return plugin.getExecutions().stream()
.anyMatch(execution -> execution.getGoals() != null && execution.getGoals().contains("properties"));
Expand Down
5 changes: 1 addition & 4 deletions src/main/resources/META-INF/rewrite/examples.yml
Original file line number Diff line number Diff line change
Expand Up @@ -225,9 +225,6 @@ examples:
<version>3.5.4</version>
<relativePath/>
</parent>
<properties>
<argLine></argLine>
</properties>

<dependencies>
<dependency>
Expand All @@ -254,7 +251,7 @@ examples:
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<!--suppress MavenModelInspection -->
<argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar}</argLine>
<argLine>-javaagent:${org.mockito:mockito-core:jar}</argLine>
</configuration>
</plugin>
</plugins>
Expand Down
Loading
Loading