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
5 changes: 5 additions & 0 deletions release-notes/CREDITS
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,8 @@ Alexey Gavrilov (@agavrilov76)
Jeremy Norris (@norrisjeremy)
* Reported #200: Fix shading of `isorelax` dependency (and other msv-core components)
(6.6.2)

Stanimir Stamenkov (@stanio)

* Reported, provided fix for #204: Non-conformant `XMLEventFactory.setLocation(null)`
(7.0.0)
2 changes: 2 additions & 0 deletions release-notes/VERSION
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ Project: woodstox
#194: Remove `QNameCreator` compatibility class
#196: WstxSAXParser error handling when used with JAXB validation
(reported by @winfriedgerlach)
#204: Non-conformant `XMLEventFactory.setLocation(null)`
(fix provided by Stanimir S)

6.6.2 (26-Mar-2024)

Expand Down
25 changes: 25 additions & 0 deletions src/main/java/com/ctc/wstx/stax/WstxEventFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
import javax.xml.stream.events.*;

import aQute.bnd.annotation.spi.ServiceProvider;
import org.codehaus.stax2.XMLStreamLocation2;
import org.codehaus.stax2.ri.Stax2EventFactoryImpl;

import com.ctc.wstx.evt.*;
import com.ctc.wstx.io.WstxInputLocation;

/**
* Implementation of {@link XMLEventFactory} to be used with
Expand All @@ -37,6 +39,7 @@ public final class WstxEventFactory
{
public WstxEventFactory() {
super();
super.setLocation(WstxInputLocation.getEmptyLocation());
}

/*
Expand All @@ -45,6 +48,28 @@ public WstxEventFactory() {
/////////////////////////////////////////////////////////////
*/

@Override
public void setLocation(Location location) {
super.setLocation(location == null ? WstxInputLocation.getEmptyLocation()
: immutableLocation(location));
}

private static WstxInputLocation immutableLocation(Location location) {
if (location == null) {
return null;
}
if (location.getClass() == WstxInputLocation.class) {
return (WstxInputLocation) location;
}

WstxInputLocation context = (location instanceof XMLStreamLocation2)
? immutableLocation(((XMLStreamLocation2) location).getContext())
: null;
return new WstxInputLocation(context, location.getPublicId(),
location.getSystemId(), location.getCharacterOffset(),
location.getLineNumber(), location.getColumnNumber());
}

//public Attribute createAttribute(QName name, String value)
//public Attribute createAttribute(String localName, String value)
//public Attribute createAttribute(String prefix, String nsURI, String localName, String value)
Expand Down
102 changes: 102 additions & 0 deletions src/test/java/wstxtest/evt/TestEventFactoryLocation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package wstxtest.evt;

import static org.hamcrest.MatcherAssert.assertThat;

import java.util.Objects;

import javax.xml.stream.Location;
import javax.xml.stream.events.XMLEvent;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.junit.Before;
import org.junit.Test;

import com.ctc.wstx.io.WstxInputLocation;
import com.ctc.wstx.stax.WstxEventFactory;

public class TestEventFactoryLocation {

private WstxEventFactory eventFactory;

@Before
public void setUp() {
eventFactory = new WstxEventFactory();
}

@Test
public void testDefaultLocation() {
XMLEvent event = eventFactory.createStartDocument();

assertThat("event.location", event.getLocation(), unknownLocation());
}

@Test
public void testResetLocation() {
eventFactory.setLocation(new WstxInputLocation(null, null, "about:blank", 3L, 2, 1));
eventFactory.setLocation(null);

XMLEvent event = eventFactory.createStartElement("foo", "bar", "baz");

assertThat("event.location", event.getLocation(), unknownLocation());
}

@Test
public void testNonVolatileLocation() {
VolatileLocation volatileLocation = new VolatileLocation(2, 3);
eventFactory.setLocation(volatileLocation);

XMLEvent event = eventFactory.createEndElement("foo", "bar", "baz");
volatileLocation.line = 4;
volatileLocation.col = 5;

assertThat("event.location", event.getLocation(),
locationWithProperties(null, null, -1, 2, 3));
}

private static Matcher<Location> unknownLocation() {
// XXX: Not sure if the empty-string publicId/systemId are conformant
//return locationWithProperties(null, null, -1, -1, -1);
return locationWithProperties("", "", -1, -1, -1);
}

private static Matcher<Location> locationWithProperties(String pubId,
String sysId, int charOffset, int row, int col) {
return new TypeSafeMatcher<Location>() {
@Override public void describeTo(Description description) {
description.appendText("Location(publicId: ").appendValue(pubId)
.appendText(", systemId: ").appendValue(sysId)
.appendText(", characterOffset: ").appendValue(charOffset)
.appendText(", lineNumber: ").appendValue(row)
.appendText(", columnNumber: ").appendValue(col);
}

@Override protected boolean matchesSafely(Location item) {
return Objects.equals(item.getPublicId(), pubId)
&& Objects.equals(item.getSystemId(), sysId)
&& Objects.equals(item.getCharacterOffset(), charOffset)
&& Objects.equals(item.getLineNumber(), row)
&& Objects.equals(item.getColumnNumber(), col);
}
};
}


static class VolatileLocation implements Location {
int line;
int col;
VolatileLocation(int line, int col) {
this.line = line;
this.col = col;
}
@Override public String getPublicId() { return null; }
@Override public String getSystemId() { return null; }
@Override public int getLineNumber() { return line; }
@Override public int getColumnNumber() { return col; }
@Override public int getCharacterOffset() { return -1; }
}


}