diff --git a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java index 9a9d2290316b..0bc054aebe3d 100644 --- a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java +++ b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoExtension.java @@ -18,6 +18,8 @@ */ package org.apache.maven.api.plugin.testing; +import javax.xml.stream.XMLStreamException; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -71,6 +73,7 @@ import org.apache.maven.api.services.ArtifactInstaller; import org.apache.maven.api.services.ArtifactManager; import org.apache.maven.api.services.LocalRepositoryManager; +import org.apache.maven.api.services.MavenException; import org.apache.maven.api.services.ProjectBuilder; import org.apache.maven.api.services.ProjectManager; import org.apache.maven.api.services.RepositoryFactory; @@ -269,7 +272,23 @@ public Object resolveParameter(ParameterContext parameterContext, ExtensionConte .map(ConfigurationContainer::getConfiguration) .orElseGet(() -> XmlNode.newInstance("config")); List children = mojoParameters.stream() - .map(mp -> XmlNode.newInstance(mp.name(), mp.value())) + .map(mp -> { + String value = mp.value(); + if (!mp.xml()) { + // Treat as plain text - escape XML special characters + value = value.replace("&", "&") + .replace("<", "<") + .replace(">", ">") + .replace("\"", """) + .replace("'", "'"); + } + String s = '<' + mp.name() + '>' + value + "'; + try { + return XmlService.read(new StringReader(s)); + } catch (XMLStreamException e) { + throw new MavenException("Unable to parse xml: " + e + System.lineSeparator() + s, e); + } + }) .collect(Collectors.toList()); XmlNode config = XmlNode.newInstance("configuration", null, null, children, null); pluginConfiguration = XmlService.merge(config, pluginConfiguration); diff --git a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java index c1e14aed339e..1ced028c6263 100644 --- a/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java +++ b/impl/maven-testing/src/main/java/org/apache/maven/api/plugin/testing/MojoParameter.java @@ -88,4 +88,28 @@ * @return the parameter value */ String value(); + + /** + * Whether to parse the value as XML. + * When {@code true} (default), the value is parsed as XML content within the parameter element. + * When {@code false}, the value is treated as plain text (useful for comma-separated lists). + * + *

Example with XML parsing enabled (default):

+ *
+     * {@code
+     * @MojoParameter(name = "items", value = "onetwo")
+     * }
+     * 
+ * + *

Example with XML parsing disabled:

+ *
+     * {@code
+     * @MojoParameter(name = "items", value = "one,two,three", xml = false)
+     * }
+     * 
+ * + * @return {@code true} to parse as XML, {@code false} to treat as plain text + * @since 4.0.0 + */ + boolean xml() default true; } diff --git a/impl/maven-testing/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java b/impl/maven-testing/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java index 30834c5b25d9..65868a2abc8e 100644 --- a/impl/maven-testing/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java +++ b/impl/maven-testing/src/test/java/org/apache/maven/api/plugin/testing/ExpressionEvaluatorTest.java @@ -20,6 +20,8 @@ import java.nio.file.Path; import java.nio.file.Paths; +import java.util.List; +import java.util.Map; import java.util.Properties; import org.apache.maven.api.Project; @@ -94,6 +96,129 @@ public void testParams(ExpressionEvaluatorMojo mojo) { assertDoesNotThrow(mojo::execute); } + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @Basedir("${basedir}/target/test-classes") + @MojoParameter(name = "strings", value = "value1value2") + public void testComplexParam(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.basedir); + assertNotNull(mojo.workdir); + assertEquals(List.of("value1", "value2"), mojo.strings); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @Basedir("${basedir}/target/test-classes") + @MojoParameter(name = "strings", value = "value1,value2", xml = false) + public void testCommaSeparatedParam(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.basedir); + assertNotNull(mojo.workdir); + assertEquals(List.of("value1", "value2"), mojo.strings); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "stringArray", value = "item1item2item3") + public void testStringArray(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.stringArray); + assertEquals(3, mojo.stringArray.length); + assertEquals("item1", mojo.stringArray[0]); + assertEquals("item2", mojo.stringArray[1]); + assertEquals("item3", mojo.stringArray[2]); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "mapParam", value = "value1value2") + public void testMapParam(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.mapParam); + assertEquals(2, mojo.mapParam.size()); + assertEquals("value1", mojo.mapParam.get("key1")); + assertEquals("value2", mojo.mapParam.get("key2")); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter( + name = "propertiesParam", + value = "prop1val1" + + "prop2val2") + public void testPropertiesParam(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.propertiesParam); + assertEquals(2, mojo.propertiesParam.size()); + assertEquals("val1", mojo.propertiesParam.getProperty("prop1")); + assertEquals("val2", mojo.propertiesParam.getProperty("prop2")); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "beanParam", value = "fieldValue42") + public void testBeanParam(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.beanParam); + assertEquals("fieldValue", mojo.beanParam.field1); + assertEquals(42, mojo.beanParam.field2); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "intValue", value = "123") + public void testIntValue(ExpressionEvaluatorMojo mojo) { + assertEquals(123, mojo.intValue); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "boolValue", value = "true") + public void testBoolValue(ExpressionEvaluatorMojo mojo) { + assertEquals(true, mojo.boolValue); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "strings", value = "one,two,three,four", xml = false) + public void testCommaSeparatedListWithXmlFalse(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.strings); + assertEquals(4, mojo.strings.size()); + assertEquals("one", mojo.strings.get(0)); + assertEquals("two", mojo.strings.get(1)); + assertEquals("three", mojo.strings.get(2)); + assertEquals("four", mojo.strings.get(3)); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter( + name = "strings", + value = "alphabetagamma", + xml = true) + public void testListWithXmlTrue(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.strings); + assertEquals(3, mojo.strings.size()); + assertEquals("alpha", mojo.strings.get(0)); + assertEquals("beta", mojo.strings.get(1)); + assertEquals("gamma", mojo.strings.get(2)); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "strings", value = "value-with-&chars", xml = false) + public void testSpecialCharactersWithXmlFalse(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.strings); + assertEquals(1, mojo.strings.size()); + assertEquals("value-with-&chars", mojo.strings.get(0)); + } + + @Test + @InjectMojo(goal = COORDINATES, pom = CONFIG) + @MojoParameter(name = "stringArray", value = "a,b,c", xml = false) + public void testArrayWithCommaSeparated(ExpressionEvaluatorMojo mojo) { + assertNotNull(mojo.stringArray); + assertEquals(3, mojo.stringArray.length); + assertEquals("a", mojo.stringArray[0]); + assertEquals("b", mojo.stringArray[1]); + assertEquals("c", mojo.stringArray[2]); + } + @Mojo(name = "goal") @Named("test:test-plugin:0.0.1-SNAPSHOT:goal") // this one is usually generated by maven-plugin-plugin public static class ExpressionEvaluatorMojo implements org.apache.maven.api.plugin.Mojo { @@ -105,6 +230,20 @@ public static class ExpressionEvaluatorMojo implements org.apache.maven.api.plug private String param2; + private List strings; + + private String[] stringArray; + + private Map mapParam; + + private Properties propertiesParam; + + private TestBean beanParam; + + private int intValue; + + private boolean boolValue; + /** {@inheritDoc} */ @Override public void execute() throws MojoException { @@ -120,6 +259,30 @@ public void execute() throws MojoException { } } + /** + * A simple bean for testing complex parameter injection. + */ + public static class TestBean { + private String field1; + private int field2; + + public String getField1() { + return field1; + } + + public void setField1(String field1) { + this.field1 = field1; + } + + public int getField2() { + return field2; + } + + public void setField2(int field2) { + this.field2 = field2; + } + } + @Provides @SuppressWarnings("unused") Session session() { diff --git a/impl/maven-testing/src/test/resources/META-INF/maven/plugin.xml b/impl/maven-testing/src/test/resources/META-INF/maven/plugin.xml index 6657446b6327..ca0b24ff8904 100644 --- a/impl/maven-testing/src/test/resources/META-INF/maven/plugin.xml +++ b/impl/maven-testing/src/test/resources/META-INF/maven/plugin.xml @@ -55,6 +55,34 @@ under the License. param2 java.lang.String + + strings + java.util.List + + + stringArray + [Ljava.lang.String; + + + mapParam + java.util.Map + + + propertiesParam + java.util.Properties + + + beanParam + org.apache.maven.api.plugin.testing.ExpressionEvaluatorTest$TestBean + + + intValue + int + + + boolValue + boolean +