Skip to content

Commit b159b3d

Browse files
desruisseauxanukalp2804
authored andcommitted
docs: complete deprecation documentation for XmlNode
Adds consistent Javadoc deprecation rationale and replacement references for deprecated XmlNode constants and methods. No functional behavior is changed.
1 parent 1eba25e commit b159b3d

File tree

4 files changed

+197
-21
lines changed

4 files changed

+197
-21
lines changed

api/maven-api-xml/src/main/java/org/apache/maven/api/xml/XmlNode.java

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,41 +61,76 @@ public interface XmlNode {
6161
@Deprecated(since = "4.0.0", forRemoval = true)
6262
String CHILDREN_COMBINATION_MODE_ATTRIBUTE = XmlService.CHILDREN_COMBINATION_MODE_ATTRIBUTE;
6363

64+
/**
65+
* @deprecated since 4.0.0.
66+
* Use {@link XmlService#CHILDREN_COMBINATION_MERGE} instead.
67+
*/
6468
@Deprecated(since = "4.0.0", forRemoval = true)
6569
String CHILDREN_COMBINATION_MERGE = XmlService.CHILDREN_COMBINATION_MERGE;
6670

71+
72+
/**
73+
* @deprecated since 4.0.0.
74+
* Use {@link XmlService#CHILDREN_COMBINATION_APPEND} instead.
75+
*/
6776
@Deprecated(since = "4.0.0", forRemoval = true)
6877
String CHILDREN_COMBINATION_APPEND = XmlService.CHILDREN_COMBINATION_APPEND;
6978

79+
7080
/**
7181
* This default mode for combining children DOMs during merge means that where element names match, the process will
7282
* try to merge the element data, rather than putting the dominant and recessive elements (which share the same
7383
* element name) as siblings in the resulting DOM.
84+
*
85+
* @deprecated since 4.0.0.
86+
* Use {@link XmlService#DEFAULT_CHILDREN_COMBINATION_MODE} instead.
7487
*/
7588
@Deprecated(since = "4.0.0", forRemoval = true)
7689
String DEFAULT_CHILDREN_COMBINATION_MODE = XmlService.DEFAULT_CHILDREN_COMBINATION_MODE;
7790

91+
/**
92+
* @deprecated since 4.0.0.
93+
* Use {@link XmlService#SELF_COMBINATION_MODE_ATTRIBUTE} instead.
94+
*/
7895
@Deprecated(since = "4.0.0", forRemoval = true)
7996
String SELF_COMBINATION_MODE_ATTRIBUTE = XmlService.SELF_COMBINATION_MODE_ATTRIBUTE;
80-
97+
/**
98+
* @deprecated since 4.0.0.
99+
* Use {@link XmlService#SELF_COMBINATION_OVERRIDE} instead.
100+
*/
81101
@Deprecated(since = "4.0.0", forRemoval = true)
82102
String SELF_COMBINATION_OVERRIDE = XmlService.SELF_COMBINATION_OVERRIDE;
83103

104+
/**
105+
* @deprecated since 4.0.0.
106+
* Use {@link XmlService#SELF_COMBINATION_MERGE} instead.
107+
*/
108+
84109
@Deprecated(since = "4.0.0", forRemoval = true)
85110
String SELF_COMBINATION_MERGE = XmlService.SELF_COMBINATION_MERGE;
111+
/**
112+
* @deprecated since 4.0.0.
113+
* Use {@link XmlService#SELF_COMBINATION_REMOVE} instead.
114+
*/
86115

87116
@Deprecated(since = "4.0.0", forRemoval = true)
88117
String SELF_COMBINATION_REMOVE = XmlService.SELF_COMBINATION_REMOVE;
89118

90119
/**
91120
* In case of complex XML structures, combining can be done based on id.
121+
*
122+
* @deprecated since 4.0.0.
123+
* Use {@link XmlService#ID_COMBINATION_MODE_ATTRIBUTE} instead.
92124
*/
93125
@Deprecated(since = "4.0.0", forRemoval = true)
94126
String ID_COMBINATION_MODE_ATTRIBUTE = XmlService.ID_COMBINATION_MODE_ATTRIBUTE;
95127

96128
/**
97129
* In case of complex XML structures, combining can be done based on keys.
98130
* This is a comma separated list of attribute names.
131+
*
132+
* @deprecated since 4.0.0.
133+
* Use {@link XmlService#KEYS_COMBINATION_MODE_ATTRIBUTE} instead.
99134
*/
100135
@Deprecated(since = "4.0.0", forRemoval = true)
101136
String KEYS_COMBINATION_MODE_ATTRIBUTE = XmlService.KEYS_COMBINATION_MODE_ATTRIBUTE;
@@ -105,6 +140,9 @@ public interface XmlNode {
105140
* try to merge the element attributes and values, rather than overriding the recessive element completely with the
106141
* dominant one. This means that wherever the dominant element doesn't provide the value or a particular attribute,
107142
* that value or attribute will be set from the recessive DOM node.
143+
*
144+
* @deprecated since 4.0.0.
145+
* Use {@link XmlService#DEFAULT_SELF_COMBINATION_MODE} instead.
108146
*/
109147
@Deprecated(since = "4.0.0", forRemoval = true)
110148
String DEFAULT_SELF_COMBINATION_MODE = XmlService.DEFAULT_SELF_COMBINATION_MODE;
@@ -186,76 +224,114 @@ public interface XmlNode {
186224
Object inputLocation();
187225

188226
// Deprecated methods that delegate to new ones
227+
/**
228+
* @deprecated since 4.0.0.
229+
* Use {@link #name()} instead.
230+
*/
189231
@Deprecated(since = "4.0.0", forRemoval = true)
190232
@Nonnull
191233
default String getName() {
192234
return name();
193235
}
194236

237+
/**
238+
* @deprecated since 4.0.0.
239+
* Use {@link #namespaceUri()} instead.
240+
*/
195241
@Deprecated(since = "4.0.0", forRemoval = true)
196242
@Nonnull
197243
default String getNamespaceUri() {
198244
return namespaceUri();
199245
}
200246

247+
/**
248+
* @deprecated since 4.0.0.
249+
* Use {@link #prefix()} instead.
250+
*/
201251
@Deprecated(since = "4.0.0", forRemoval = true)
202252
@Nonnull
203253
default String getPrefix() {
204254
return prefix();
205255
}
206-
256+
/**
257+
* @deprecated since 4.0.0.
258+
* Use {@link #value()} instead.
259+
*/
207260
@Deprecated(since = "4.0.0", forRemoval = true)
208261
@Nullable
209262
default String getValue() {
210263
return value();
211264
}
212265

266+
/**
267+
* @deprecated since 4.0.0.
268+
* Use {@link #attributes()} instead.
269+
*/
213270
@Deprecated(since = "4.0.0", forRemoval = true)
214271
@Nonnull
215272
default Map<String, String> getAttributes() {
216273
return attributes();
217274
}
218275

276+
/**
277+
* @deprecated since 4.0.0.
278+
* Use {@link #attribute(String)} instead.
279+
*/
219280
@Deprecated(since = "4.0.0", forRemoval = true)
220281
@Nullable
221282
default String getAttribute(@Nonnull String name) {
222283
return attribute(name);
223284
}
224285

286+
/**
287+
* @deprecated since 4.0.0.
288+
* Use {@link #children()} instead.
289+
*/
225290
@Deprecated(since = "4.0.0", forRemoval = true)
226291
@Nonnull
227292
default List<XmlNode> getChildren() {
228293
return children();
229294
}
230295

296+
/**
297+
* @deprecated since 4.0.0.
298+
* Use {@link #child(String)} instead.
299+
*/
231300
@Deprecated(since = "4.0.0", forRemoval = true)
232301
@Nullable
233302
default XmlNode getChild(String name) {
234303
return child(name);
235304
}
236305

306+
/**
307+
* @deprecated since 4.0.0.
308+
* Use {@link #inputLocation()} instead.
309+
*/
237310
@Deprecated(since = "4.0.0", forRemoval = true)
238311
@Nullable
239312
default Object getInputLocation() {
240313
return inputLocation();
241314
}
242315

243316
/**
244-
* @deprecated use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead
317+
* @deprecated since 4.0.0.
318+
* Use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead.
245319
*/
246320
@Deprecated(since = "4.0.0", forRemoval = true)
247321
default XmlNode merge(@Nullable XmlNode source) {
248322
return XmlService.merge(this, source);
249323
}
250324

251325
/**
252-
* @deprecated use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead
326+
* @deprecated since 4.0.0.
327+
* Use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead.
253328
*/
254329
@Deprecated(since = "4.0.0", forRemoval = true)
255330
default XmlNode merge(@Nullable XmlNode source, @Nullable Boolean childMergeOverride) {
256331
return XmlService.merge(this, source, childMergeOverride);
257332
}
258333

334+
259335
/**
260336
* Merge recessive into dominant and return either {@code dominant}
261337
* with merged information or a clone of {@code recessive} if
@@ -265,7 +341,8 @@ default XmlNode merge(@Nullable XmlNode source, @Nullable Boolean childMergeOver
265341
* @param recessive if {@code null}, nothing will happen
266342
* @return the merged node
267343
*
268-
* @deprecated use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead
344+
* @deprecated since 4.0.0.
345+
* Use {@link XmlService#merge(XmlNode, XmlNode, Boolean)} instead.
269346
*/
270347
@Deprecated(since = "4.0.0", forRemoval = true)
271348
@Nullable

impl/maven-core/src/main/java/org/apache/maven/internal/impl/DefaultProjectManager.java

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,55 @@ public void attachArtifact(@Nonnull Project project, @Nonnull ProducedArtifact a
119119
artifact.getExtension(),
120120
null);
121121
}
122-
if (!Objects.equals(project.getGroupId(), artifact.getGroupId())
123-
|| !Objects.equals(project.getArtifactId(), artifact.getArtifactId())
124-
|| !Objects.equals(
125-
project.getVersion(), artifact.getBaseVersion().toString())) {
126-
throw new IllegalArgumentException(
127-
"The produced artifact must have the same groupId/artifactId/version than the project it is attached to. Expecting "
128-
+ project.getGroupId() + ":" + project.getArtifactId() + ":" + project.getVersion()
129-
+ " but received " + artifact.getGroupId() + ":" + artifact.getArtifactId() + ":"
130-
+ artifact.getBaseVersion());
122+
// Verify groupId and version, intentionally allow artifactId to differ as Maven project may be
123+
// multi-module with modular sources structure that provide module names used as artifactIds.
124+
String g1 = project.getGroupId();
125+
String a1 = project.getArtifactId();
126+
String v1 = project.getVersion();
127+
String g2 = artifact.getGroupId();
128+
String a2 = artifact.getArtifactId();
129+
String v2 = artifact.getBaseVersion().toString();
130+
131+
// ArtifactId may differ only for multi-module projects, in which case
132+
// it must match the module name from a source root in modular sources.
133+
boolean isMultiModule = false;
134+
boolean validArtifactId = Objects.equals(a1, a2);
135+
for (SourceRoot sr : getSourceRoots(project)) {
136+
Optional<String> moduleName = sr.module();
137+
if (moduleName.isPresent()) {
138+
isMultiModule = true;
139+
if (moduleName.get().equals(a2)) {
140+
validArtifactId = true;
141+
break;
142+
}
143+
}
144+
}
145+
boolean isSameGroupAndVersion = Objects.equals(g1, g2) && Objects.equals(v1, v2);
146+
if (!(isSameGroupAndVersion && validArtifactId)) {
147+
String message;
148+
if (isMultiModule) {
149+
// Multi-module project: artifactId may match any declared module name
150+
message = String.format(
151+
"Cannot attach artifact to project: groupId and version must match the project, "
152+
+ "and artifactId must match either the project or a declared module name.%n"
153+
+ " Project coordinates: %s:%s:%s%n"
154+
+ " Artifact coordinates: %s:%s:%s%n",
155+
g1, a1, v1, g2, a2, v2);
156+
if (isSameGroupAndVersion) {
157+
message += String.format(
158+
" Hint: The artifactId '%s' does not match the project artifactId '%s' "
159+
+ "nor any declared module name in source roots.",
160+
a2, a1);
161+
}
162+
} else {
163+
// Non-modular project: artifactId must match exactly
164+
message = String.format(
165+
"Cannot attach artifact to project: groupId, artifactId and version must match the project.%n"
166+
+ " Project coordinates: %s:%s:%s%n"
167+
+ " Artifact coordinates: %s:%s:%s",
168+
g1, a1, v1, g2, a2, v2);
169+
}
170+
throw new IllegalArgumentException(message);
131171
}
132172
getMavenProject(project)
133173
.addAttachedArtifact(

impl/maven-core/src/test/java/org/apache/maven/internal/impl/DefaultProjectManagerTest.java

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,43 +20,102 @@
2020

2121
import java.nio.file.Path;
2222
import java.nio.file.Paths;
23+
import java.util.function.Supplier;
2324

25+
import org.apache.maven.api.Language;
2426
import org.apache.maven.api.ProducedArtifact;
2527
import org.apache.maven.api.Project;
28+
import org.apache.maven.api.ProjectScope;
2629
import org.apache.maven.api.services.ArtifactManager;
2730
import org.apache.maven.impl.DefaultModelVersionParser;
31+
import org.apache.maven.impl.DefaultSourceRoot;
2832
import org.apache.maven.impl.DefaultVersionParser;
2933
import org.apache.maven.project.MavenProject;
3034
import org.eclipse.aether.util.version.GenericVersionScheme;
3135
import org.junit.jupiter.api.Test;
3236
import org.mockito.Mockito;
3337

3438
import static org.junit.jupiter.api.Assertions.assertThrows;
39+
import static org.junit.jupiter.api.Assertions.assertTrue;
3540
import static org.mockito.Mockito.when;
3641

3742
class DefaultProjectManagerTest {
3843

44+
private DefaultProjectManager projectManager;
45+
46+
private Project project;
47+
48+
private ProducedArtifact artifact;
49+
50+
private Path artifactPath;
51+
3952
@Test
4053
void attachArtifact() {
4154
InternalMavenSession session = Mockito.mock(InternalMavenSession.class);
4255
ArtifactManager artifactManager = Mockito.mock(ArtifactManager.class);
4356
MavenProject mavenProject = new MavenProject();
44-
Project project = new DefaultProject(session, mavenProject);
45-
ProducedArtifact artifact = Mockito.mock(ProducedArtifact.class);
46-
Path path = Paths.get("");
57+
project = new DefaultProject(session, mavenProject);
58+
artifact = Mockito.mock(ProducedArtifact.class);
59+
artifactPath = Paths.get("");
4760
DefaultVersionParser versionParser =
4861
new DefaultVersionParser(new DefaultModelVersionParser(new GenericVersionScheme()));
49-
DefaultProjectManager projectManager = new DefaultProjectManager(session, artifactManager);
62+
projectManager = new DefaultProjectManager(session, artifactManager);
5063

5164
mavenProject.setGroupId("myGroup");
5265
mavenProject.setArtifactId("myArtifact");
5366
mavenProject.setVersion("1.0-SNAPSHOT");
5467
when(artifact.getGroupId()).thenReturn("myGroup");
5568
when(artifact.getArtifactId()).thenReturn("myArtifact");
5669
when(artifact.getBaseVersion()).thenReturn(versionParser.parseVersion("1.0-SNAPSHOT"));
57-
projectManager.attachArtifact(project, artifact, path);
70+
projectManager.attachArtifact(project, artifact, artifactPath);
5871

72+
// Verify that an exception is thrown when the artifactId differs
5973
when(artifact.getArtifactId()).thenReturn("anotherArtifact");
60-
assertThrows(IllegalArgumentException.class, () -> projectManager.attachArtifact(project, artifact, path));
74+
assertExceptionMessageContains("myGroup:myArtifact:1.0-SNAPSHOT", "myGroup:anotherArtifact:1.0-SNAPSHOT");
75+
76+
// Add a Java module. It should relax the restriction on artifactId.
77+
projectManager.addSourceRoot(
78+
project,
79+
new DefaultSourceRoot(
80+
ProjectScope.MAIN,
81+
Language.JAVA_FAMILY,
82+
"org.foo.bar",
83+
null,
84+
Path.of("myProject"),
85+
null,
86+
null,
87+
false,
88+
null,
89+
true));
90+
91+
// Verify that we get the same exception when the artifactId does not match the module name
92+
assertExceptionMessageContains("", "anotherArtifact");
93+
94+
// Verify that no exception is thrown when the artifactId is the module name
95+
when(artifact.getArtifactId()).thenReturn("org.foo.bar");
96+
projectManager.attachArtifact(project, artifact, artifactPath);
97+
98+
// Verify that an exception is thrown when the groupId differs
99+
when(artifact.getGroupId()).thenReturn("anotherGroup");
100+
assertExceptionMessageContains("myGroup:myArtifact:1.0-SNAPSHOT", "anotherGroup:org.foo.bar:1.0-SNAPSHOT");
101+
}
102+
103+
/**
104+
* Verifies that {@code projectManager.attachArtifact(…)} throws an exception,
105+
* and that the expecption message contains the expected and actual <abbr>GAV</abbr>.
106+
*
107+
* @param expectedGAV the actual <abbr>GAV</abbr> that the exception message should contain
108+
* @param actualGAV the actual <abbr>GAV</abbr> that the exception message should contain
109+
*/
110+
private void assertExceptionMessageContains(String expectedGAV, String actualGAV) {
111+
String cause = assertThrows(
112+
IllegalArgumentException.class,
113+
() -> projectManager.attachArtifact(project, artifact, artifactPath))
114+
.getMessage();
115+
Supplier<String> message = () ->
116+
String.format("The exception message does not contain the expected GAV. Message was:%n%s%n", cause);
117+
118+
assertTrue(cause.contains(expectedGAV), message);
119+
assertTrue(cause.contains(actualGAV), message);
61120
}
62121
}

impl/maven-impl/src/main/java/org/apache/maven/impl/DefaultSourceRoot.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ public DefaultSourceRoot(
9494
@Nonnull Language language,
9595
@Nullable String moduleName,
9696
@Nullable Version targetVersionOrNull,
97-
@Nullable Path directory,
97+
@Nonnull Path directory,
9898
@Nullable List<String> includes,
9999
@Nullable List<String> excludes,
100100
boolean stringFiltering,

0 commit comments

Comments
 (0)