Skip to content

Commit 6f5c837

Browse files
authored
Fix MavenStaxReader location reporting for properties (#11402)
The location for properties (Map elements) was being captured AFTER calling nextText(), which moves the parser position past the element. This resulted in incorrect location information. This commit fixes the timing of location capture for properties by saving the line and column numbers BEFORE calling nextText(). Changes: - Modified src/mdo/reader-stax.vm to capture location before nextText() for properties - Added comprehensive unit tests for location reporting: * testLocationReportingForElements() - tests regular elements with exact line/column numbers * testLocationReportingForAttributes() - tests XML attributes (root, child.scm.connection.inherit.append.path) Note: Attributes get the location of their containing element since XMLStreamReader doesn't provide individual attribute positions * testLocationReportingForListElements() - tests list elements (modules) with exact line/column numbers
1 parent a46b0c7 commit 6f5c837

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

impl/maven-support/src/test/java/org/apache/maven/model/v4/MavenStaxReaderTest.java

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222

2323
import java.io.StringReader;
2424

25+
import org.apache.maven.api.model.Dependency;
26+
import org.apache.maven.api.model.InputLocation;
27+
import org.apache.maven.api.model.InputSource;
2528
import org.apache.maven.api.model.Model;
2629
import org.junit.jupiter.api.Test;
2730

@@ -140,6 +143,144 @@ void testPluginConfigurationAllowsOtherNamespaces() throws XMLStreamException {
140143
assertEquals("http://maven.apache.org/POM/4.0.0", model.getNamespaceUri());
141144
}
142145

146+
@Test
147+
void testLocationReportingForElements() throws Exception {
148+
String xml = "<project>\n"
149+
+ " <modelVersion>4.0.0</modelVersion>\n"
150+
+ " <groupId>org.example</groupId>\n"
151+
+ " <artifactId>test-artifact</artifactId>\n"
152+
+ " <version>1.0.0</version>\n"
153+
+ " <dependencies>\n"
154+
+ " <dependency>\n"
155+
+ " <groupId>junit</groupId>\n"
156+
+ " <artifactId>junit</artifactId>\n"
157+
+ " <version>4.13.2</version>\n"
158+
+ " </dependency>\n"
159+
+ " </dependencies>\n"
160+
+ "</project>";
161+
162+
MavenStaxReader reader = new MavenStaxReader();
163+
reader.setAddLocationInformation(true);
164+
Model model = reader.read(new StringReader(xml), true, InputSource.of("test.xml"));
165+
166+
// Check root element location - should point to <project> tag on line 1, column 1
167+
InputLocation projectLocation = model.getLocation("");
168+
assertNotNull(projectLocation, "Project location should not be null");
169+
assertEquals(1, projectLocation.getLineNumber(), "Project should start at line 1");
170+
assertEquals(1, projectLocation.getColumnNumber(), "Project should start at column 1");
171+
172+
// Check modelVersion location - should point to <modelVersion> tag on line 2, column 3
173+
InputLocation modelVersionLocation = model.getLocation("modelVersion");
174+
assertNotNull(modelVersionLocation, "ModelVersion location should not be null");
175+
assertEquals(2, modelVersionLocation.getLineNumber(), "ModelVersion should start at line 2");
176+
assertEquals(3, modelVersionLocation.getColumnNumber(), "ModelVersion should start at column 3");
177+
178+
// Check groupId location - should point to <groupId> tag on line 3, column 3
179+
InputLocation groupIdLocation = model.getLocation("groupId");
180+
assertNotNull(groupIdLocation, "GroupId location should not be null");
181+
assertEquals(3, groupIdLocation.getLineNumber(), "GroupId should start at line 3");
182+
assertEquals(3, groupIdLocation.getColumnNumber(), "GroupId should start at column 3");
183+
184+
// Check dependencies location - should point to <dependencies> tag on line 6, column 3
185+
InputLocation dependenciesLocation = model.getLocation("dependencies");
186+
assertNotNull(dependenciesLocation, "Dependencies location should not be null");
187+
assertEquals(6, dependenciesLocation.getLineNumber(), "Dependencies should start at line 6");
188+
assertEquals(3, dependenciesLocation.getColumnNumber(), "Dependencies should start at column 3");
189+
190+
// Check dependency location - should point to <dependency> tag on line 7, column 5
191+
Dependency dependency = model.getDependencies().get(0);
192+
InputLocation dependencyLocation = dependency.getLocation("");
193+
assertNotNull(dependencyLocation, "Dependency location should not be null");
194+
assertEquals(7, dependencyLocation.getLineNumber(), "Dependency should start at line 7");
195+
assertEquals(5, dependencyLocation.getColumnNumber(), "Dependency should start at column 5");
196+
197+
// Check dependency groupId location - should point to <groupId> tag on line 8, column 7
198+
InputLocation depGroupIdLocation = dependency.getLocation("groupId");
199+
assertNotNull(depGroupIdLocation, "Dependency groupId location should not be null");
200+
assertEquals(8, depGroupIdLocation.getLineNumber(), "Dependency groupId should start at line 8");
201+
assertEquals(7, depGroupIdLocation.getColumnNumber(), "Dependency groupId should start at column 7");
202+
}
203+
204+
@Test
205+
void testLocationReportingForAttributes() throws Exception {
206+
String xml = "<project root=\"true\">\n"
207+
+ " <modelVersion>4.0.0</modelVersion>\n"
208+
+ " <groupId>org.example</groupId>\n"
209+
+ " <artifactId>test-artifact</artifactId>\n"
210+
+ " <version>1.0.0</version>\n"
211+
+ " <scm child.scm.connection.inherit.append.path=\"false\">\n"
212+
+ " <connection>scm:git:https://github.com/example/repo.git</connection>\n"
213+
+ " </scm>\n"
214+
+ "</project>";
215+
216+
MavenStaxReader reader = new MavenStaxReader();
217+
reader.setAddLocationInformation(true);
218+
Model model = reader.read(new StringReader(xml), true, InputSource.of("test.xml"));
219+
220+
// Check project root attribute - attributes get the location of their containing element
221+
// since XMLStreamReader doesn't provide individual attribute positions
222+
InputLocation rootLocation = model.getLocation("root");
223+
assertNotNull(rootLocation, "Root attribute location should not be null");
224+
assertEquals(1, rootLocation.getLineNumber(), "Root attribute should be on line 1 (element line)");
225+
assertEquals(1, rootLocation.getColumnNumber(), "Root attribute should point to column 1 (element column)");
226+
assertTrue(model.isRoot(), "Root should be true");
227+
228+
// Check scm element location
229+
InputLocation scmLocation = model.getScm().getLocation("");
230+
assertNotNull(scmLocation, "SCM location should not be null");
231+
assertEquals(6, scmLocation.getLineNumber(), "SCM should start at line 6");
232+
assertEquals(3, scmLocation.getColumnNumber(), "SCM should start at column 3");
233+
234+
// Check scm child.scm.connection.inherit.append.path attribute
235+
// Like all attributes, it gets the location of its containing element
236+
InputLocation scmInheritLocation = model.getScm().getLocation("child.scm.connection.inherit.append.path");
237+
assertNotNull(scmInheritLocation, "SCM inherit attribute location should not be null");
238+
assertEquals(6, scmInheritLocation.getLineNumber(), "SCM inherit attribute should be on line 6 (element line)");
239+
assertEquals(
240+
3,
241+
scmInheritLocation.getColumnNumber(),
242+
"SCM inherit attribute should point to column 3 (element column)");
243+
assertEquals("false", model.getScm().getChildScmConnectionInheritAppendPath());
244+
}
245+
246+
@Test
247+
void testLocationReportingForListElements() throws Exception {
248+
String xml = "<project>\n"
249+
+ " <modelVersion>4.0.0</modelVersion>\n"
250+
+ " <modules>\n"
251+
+ " <module>module1</module>\n"
252+
+ " <module>module2</module>\n"
253+
+ " <module>module3</module>\n"
254+
+ " </modules>\n"
255+
+ "</project>";
256+
257+
MavenStaxReader reader = new MavenStaxReader();
258+
reader.setAddLocationInformation(true);
259+
Model model = reader.read(new StringReader(xml), true, InputSource.of("test.xml"));
260+
261+
// Check modules location - should point to <modules> tag on line 3, column 3
262+
InputLocation modulesLocation = model.getLocation("modules");
263+
assertNotNull(modulesLocation, "Modules location should not be null");
264+
assertEquals(3, modulesLocation.getLineNumber(), "Modules should start at line 3");
265+
assertEquals(3, modulesLocation.getColumnNumber(), "Modules should start at column 3");
266+
267+
// Check individual module locations
268+
InputLocation module1Location = modulesLocation.getLocation(0);
269+
assertNotNull(module1Location, "Module 1 location should not be null");
270+
assertEquals(4, module1Location.getLineNumber(), "Module 1 should start at line 4");
271+
assertEquals(5, module1Location.getColumnNumber(), "Module 1 should start at column 5");
272+
273+
InputLocation module2Location = modulesLocation.getLocation(1);
274+
assertNotNull(module2Location, "Module 2 location should not be null");
275+
assertEquals(5, module2Location.getLineNumber(), "Module 2 should start at line 5");
276+
assertEquals(5, module2Location.getColumnNumber(), "Module 2 should start at column 5");
277+
278+
InputLocation module3Location = modulesLocation.getLocation(2);
279+
assertNotNull(module3Location, "Module 3 location should not be null");
280+
assertEquals(6, module3Location.getLineNumber(), "Module 3 should start at line 6");
281+
assertEquals(5, module3Location.getColumnNumber(), "Module 3 should start at column 5");
282+
}
283+
143284
private Model fromXml(String xml) throws XMLStreamException {
144285
MavenStaxReader reader = new MavenStaxReader();
145286
return reader.read(new StringReader(xml), true, null);

src/mdo/reader-stax.vm

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,14 @@ public class ${className} {
427427
#end
428428
while (parser.nextTag() == XMLStreamReader.START_ELEMENT) {
429429
String key = parser.getLocalName();
430+
#if ( $locationTracking )
431+
int propLine = parser.getLocation().getLineNumber();
432+
int propColumn = parser.getLocation().getColumnNumber();
433+
#end
430434
String value = nextText(parser, strict).trim();
431435
#if ( $locationTracking )
432436
if (addLocationInformation) {
433-
locations.put(key, InputLocation.of(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), inputSrc));
437+
locations.put(key, InputLocation.of(propLine, propColumn, inputSrc));
434438
}
435439
#end
436440
${field.name}.put(key, value);
@@ -702,7 +706,7 @@ public class ${className} {
702706
private XmlNode buildXmlNode(XMLStreamReader parser, InputSource inputSrc) throws XMLStreamException {
703707
return XmlService.read(parser,
704708
addLocationInformation
705-
? p -> InputLocation.of(parser.getLocation().getLineNumber(), parser.getLocation().getColumnNumber(), inputSrc)
709+
? p -> InputLocation.of(p.getLocation().getLineNumber(), p.getLocation().getColumnNumber(), inputSrc)
706710
: null);
707711
}
708712
#else

0 commit comments

Comments
 (0)