Skip to content

Commit 17a3eb2

Browse files
staniocowtowncoder
authored andcommitted
WstxEventFactory: Ensure events' immutable non-null location (#205)
1 parent b0c088c commit 17a3eb2

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed

release-notes/CREDITS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,8 @@ Alexey Gavrilov (@agavrilov76)
104104
Jeremy Norris (@norrisjeremy)
105105
* Reported #200: Fix shading of `isorelax` dependency (and other msv-core components)
106106
(6.6.2)
107+
108+
Stanimir Stamenkov (@stanio)
109+
110+
* Reported, provided fix for #204: Non-conformant `XMLEventFactory.setLocation(null)`
111+
(7.0.0)

release-notes/VERSION

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ Project: woodstox
66

77
6.7.0 (not yet released)
88

9-
-
9+
#204: Non-conformant `XMLEventFactory.setLocation(null)`
10+
(fix provided by Stanimir S)
1011

1112
6.6.2 (26-Mar-2024)
1213

src/main/java/com/ctc/wstx/stax/WstxEventFactory.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import javax.xml.stream.events.*;
2424

2525
import aQute.bnd.annotation.spi.ServiceProvider;
26+
import org.codehaus.stax2.XMLStreamLocation2;
2627
import org.codehaus.stax2.ri.Stax2EventFactoryImpl;
2728

2829
import com.ctc.wstx.compat.QNameCreator;
2930
import com.ctc.wstx.evt.*;
31+
import com.ctc.wstx.io.WstxInputLocation;
3032

3133
/**
3234
* Implementation of {@link XMLEventFactory} to be used with
@@ -38,6 +40,7 @@ public final class WstxEventFactory
3840
{
3941
public WstxEventFactory() {
4042
super();
43+
super.setLocation(WstxInputLocation.getEmptyLocation());
4144
}
4245

4346
/*
@@ -46,6 +49,28 @@ public WstxEventFactory() {
4649
/////////////////////////////////////////////////////////////
4750
*/
4851

52+
@Override
53+
public void setLocation(Location location) {
54+
super.setLocation(location == null ? WstxInputLocation.getEmptyLocation()
55+
: immutableLocation(location));
56+
}
57+
58+
private static WstxInputLocation immutableLocation(Location location) {
59+
if (location == null) {
60+
return null;
61+
}
62+
if (location.getClass() == WstxInputLocation.class) {
63+
return (WstxInputLocation) location;
64+
}
65+
66+
WstxInputLocation context = (location instanceof XMLStreamLocation2)
67+
? immutableLocation(((XMLStreamLocation2) location).getContext())
68+
: null;
69+
return new WstxInputLocation(context, location.getPublicId(),
70+
location.getSystemId(), location.getCharacterOffset(),
71+
location.getLineNumber(), location.getColumnNumber());
72+
}
73+
4974
//public Attribute createAttribute(QName name, String value)
5075
//public Attribute createAttribute(String localName, String value)
5176
//public Attribute createAttribute(String prefix, String nsURI, String localName, String value)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package wstxtest.evt;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
5+
import java.util.Objects;
6+
7+
import javax.xml.stream.Location;
8+
import javax.xml.stream.events.XMLEvent;
9+
10+
import org.hamcrest.Description;
11+
import org.hamcrest.Matcher;
12+
import org.hamcrest.TypeSafeMatcher;
13+
import org.junit.Before;
14+
import org.junit.Test;
15+
16+
import com.ctc.wstx.io.WstxInputLocation;
17+
import com.ctc.wstx.stax.WstxEventFactory;
18+
19+
public class TestEventFactoryLocation {
20+
21+
private WstxEventFactory eventFactory;
22+
23+
@Before
24+
public void setUp() {
25+
eventFactory = new WstxEventFactory();
26+
}
27+
28+
@Test
29+
public void testDefaultLocation() {
30+
XMLEvent event = eventFactory.createStartDocument();
31+
32+
assertThat("event.location", event.getLocation(), unknownLocation());
33+
}
34+
35+
@Test
36+
public void testResetLocation() {
37+
eventFactory.setLocation(new WstxInputLocation(null, null, "about:blank", 3L, 2, 1));
38+
eventFactory.setLocation(null);
39+
40+
XMLEvent event = eventFactory.createStartElement("foo", "bar", "baz");
41+
42+
assertThat("event.location", event.getLocation(), unknownLocation());
43+
}
44+
45+
@Test
46+
public void testNonVolatileLocation() {
47+
VolatileLocation volatileLocation = new VolatileLocation(2, 3);
48+
eventFactory.setLocation(volatileLocation);
49+
50+
XMLEvent event = eventFactory.createEndElement("foo", "bar", "baz");
51+
volatileLocation.line = 4;
52+
volatileLocation.col = 5;
53+
54+
assertThat("event.location", event.getLocation(),
55+
locationWithProperties(null, null, -1, 2, 3));
56+
}
57+
58+
private static Matcher<Location> unknownLocation() {
59+
// XXX: Not sure if the empty-string publicId/systemId are conformant
60+
//return locationWithProperties(null, null, -1, -1, -1);
61+
return locationWithProperties("", "", -1, -1, -1);
62+
}
63+
64+
private static Matcher<Location> locationWithProperties(final String pubId,
65+
final String sysId, final int charOffset, final int row, final int col) {
66+
return new TypeSafeMatcher<Location>() {
67+
@Override public void describeTo(Description description) {
68+
description.appendText("Location(publicId: ").appendValue(pubId)
69+
.appendText(", systemId: ").appendValue(sysId)
70+
.appendText(", characterOffset: ").appendValue(charOffset)
71+
.appendText(", lineNumber: ").appendValue(row)
72+
.appendText(", columnNumber: ").appendValue(col);
73+
}
74+
75+
@Override protected boolean matchesSafely(Location item) {
76+
return Objects.equals(item.getPublicId(), pubId)
77+
&& Objects.equals(item.getSystemId(), sysId)
78+
&& Objects.equals(item.getCharacterOffset(), charOffset)
79+
&& Objects.equals(item.getLineNumber(), row)
80+
&& Objects.equals(item.getColumnNumber(), col);
81+
}
82+
};
83+
}
84+
85+
static class VolatileLocation implements Location {
86+
int line;
87+
int col;
88+
VolatileLocation(int line, int col) {
89+
this.line = line;
90+
this.col = col;
91+
}
92+
@Override public String getPublicId() { return null; }
93+
@Override public String getSystemId() { return null; }
94+
@Override public int getLineNumber() { return line; }
95+
@Override public int getColumnNumber() { return col; }
96+
@Override public int getCharacterOffset() { return -1; }
97+
}
98+
}

0 commit comments

Comments
 (0)