diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestUtil.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestUtil.java
new file mode 100644
index 000000000..94dacb2c2
--- /dev/null
+++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/XmlTestUtil.java
@@ -0,0 +1,384 @@
+package com.fasterxml.jackson.dataformat.xml;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+import com.fasterxml.jackson.core.*;
+import com.fasterxml.jackson.databind.AnnotationIntrospector;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public abstract class XmlTestUtil
+{
+
+ protected static final String DEFAULT_NEW_LINE;
+
+ static {
+ String newLine = System.getProperty("line.separator");
+ DEFAULT_NEW_LINE = newLine == null ? "\n" : newLine;
+ }
+
+ @JsonPropertyOrder({ "first", "last", "id" })
+ protected static class NameBean {
+ @JacksonXmlProperty(isAttribute=true)
+ public int age;
+ public String last, first;
+
+ public NameBean() { }
+ public NameBean(int age, String f, String l) {
+ this.age = age;
+ first = f;
+ last = l;
+ }
+ }
+
+ /**
+ * Sample class from Jackson tutorial ("JacksonInFiveMinutes")
+ */
+ public static class FiveMinuteUser {
+ public enum Gender { MALE, FEMALE };
+
+ public static class Name
+ {
+ private String _first, _last;
+
+ public Name() { }
+ public Name(String f, String l) {
+ _first = f;
+ _last = l;
+ }
+
+ public String getFirst() { return _first; }
+ public String getLast() { return _last; }
+
+ public void setFirst(String s) { _first = s; }
+ public void setLast(String s) { _last = s; }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == this) return true;
+ if (o == null || o.getClass() != getClass()) return false;
+ Name other = (Name) o;
+ return _first.equals(other._first) && _last.equals(other._last);
+ }
+ }
+
+ private Gender _gender;
+ private Name _name;
+ private boolean _isVerified;
+ private byte[] _userImage;
+
+ public FiveMinuteUser() { }
+
+ public FiveMinuteUser(String first, String last, boolean verified, Gender g, byte[] data)
+ {
+ _name = new Name(first, last);
+ _isVerified = verified;
+ _gender = g;
+ _userImage = data;
+ }
+
+ public Name getName() { return _name; }
+ public boolean isVerified() { return _isVerified; }
+ public Gender getGender() { return _gender; }
+ public byte[] getUserImage() { return _userImage; }
+
+ public void setName(Name n) { _name = n; }
+ public void setVerified(boolean b) { _isVerified = b; }
+ public void setGender(Gender g) { _gender = g; }
+ public void setUserImage(byte[] b) { _userImage = b; }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (o == this) return true;
+ if (o == null || o.getClass() != getClass()) return false;
+ FiveMinuteUser other = (FiveMinuteUser) o;
+ if (_isVerified != other._isVerified) return false;
+ if (_gender != other._gender) return false;
+ if (!_name.equals(other._name)) return false;
+ byte[] otherImage = other._userImage;
+ if (otherImage.length != _userImage.length) return false;
+ for (int i = 0, len = _userImage.length; i < len; ++i) {
+ if (_userImage[i] != otherImage[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ protected static class StringBean
+ {
+ public String text;
+
+ public StringBean() { this("foobar"); }
+ public StringBean(String s) { text = s; }
+
+ @Override
+ public String toString() {
+ if (text == null) return "NULL";
+ return "\""+text+"\"";
+ }
+ }
+
+ /**
+ * Simple wrapper around String type, usually to test value
+ * conversions or wrapping
+ */
+ protected static class StringWrapper {
+ public String str;
+
+ public StringWrapper() { }
+ public StringWrapper(String value) {
+ str = value;
+ }
+ }
+
+ protected static class IntWrapper {
+ public int i;
+
+ public IntWrapper() { }
+ public IntWrapper(int value) {
+ i = value;
+ }
+ }
+
+ public static class Point {
+ public int x, y;
+
+ protected Point() { } // for deser
+ public Point(int x0, int y0) {
+ x = x0;
+ y = y0;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Point)) {
+ return false;
+ }
+ Point other = (Point) o;
+ return (other.x == x) && (other.y == y);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[x=%d, y=%d]", x, y);
+ }
+ }
+
+ /*
+ /**********************************************************
+ /* Some sample documents:
+ /**********************************************************
+ */
+
+ protected final static int SAMPLE_SPEC_VALUE_WIDTH = 800;
+ protected final static int SAMPLE_SPEC_VALUE_HEIGHT = 600;
+ protected final static String SAMPLE_SPEC_VALUE_TITLE = "View from 15th Floor";
+ protected final static String SAMPLE_SPEC_VALUE_TN_URL = "http://www.example.com/image/481989943";
+ protected final static int SAMPLE_SPEC_VALUE_TN_HEIGHT = 125;
+ protected final static String SAMPLE_SPEC_VALUE_TN_WIDTH = "100";
+ protected final static int SAMPLE_SPEC_VALUE_TN_ID1 = 116;
+ protected final static int SAMPLE_SPEC_VALUE_TN_ID2 = 943;
+ protected final static int SAMPLE_SPEC_VALUE_TN_ID3 = 234;
+ protected final static int SAMPLE_SPEC_VALUE_TN_ID4 = 38793;
+
+ protected final static String SAMPLE_DOC_JSON_SPEC =
+ "{\n"
+ +" \"Image\" : {\n"
+ +" \"Width\" : "+SAMPLE_SPEC_VALUE_WIDTH+",\n"
+ +" \"Height\" : "+SAMPLE_SPEC_VALUE_HEIGHT+","
+ +"\"Title\" : \""+SAMPLE_SPEC_VALUE_TITLE+"\",\n"
+ +" \"Thumbnail\" : {\n"
+ +" \"Url\" : \""+SAMPLE_SPEC_VALUE_TN_URL+"\",\n"
+ +"\"Height\" : "+SAMPLE_SPEC_VALUE_TN_HEIGHT+",\n"
+ +" \"Width\" : \""+SAMPLE_SPEC_VALUE_TN_WIDTH+"\"\n"
+ +" },\n"
+ +" \"IDs\" : ["+SAMPLE_SPEC_VALUE_TN_ID1+","+SAMPLE_SPEC_VALUE_TN_ID2+","+SAMPLE_SPEC_VALUE_TN_ID3+","+SAMPLE_SPEC_VALUE_TN_ID4+"]\n"
+ +" }"
+ +"}"
+ ;
+
+ /*
+ /**********************************************************
+ /* Construction, factory methods
+ /**********************************************************
+ */
+
+ protected XmlTestUtil() {
+ super();
+ }
+
+ protected XmlFactoryBuilder streamFactoryBuilder() {
+ return XmlFactory.builder();
+ }
+
+ protected static XmlMapper newMapper() {
+ return new XmlMapper();
+ }
+
+ protected static XmlMapper.Builder mapperBuilder() {
+ return XmlMapper.builder();
+ }
+
+ protected static XmlMapper.Builder mapperBuilder(XmlFactory f) {
+ return XmlMapper.builder(f);
+ }
+
+ protected XmlMapper xmlMapper(boolean useListWrapping)
+ {
+ JacksonXmlModule module = new JacksonXmlModule();
+ module.setDefaultUseWrapper(useListWrapping);
+ return new XmlMapper(module);
+ }
+
+ protected AnnotationIntrospector jakartaXMLBindAnnotationIntrospector() {
+ return new JakartaXmlBindAnnotationIntrospector(TypeFactory.defaultInstance());
+ }
+
+ /*
+ /**********************************************************
+ /* Additional assertion methods
+ /**********************************************************
+ */
+
+ protected void assertToken(JsonToken expToken, JsonToken actToken)
+ {
+ if (actToken != expToken) {
+ fail("Expected token "+expToken+", current token "+actToken);
+ }
+ }
+
+ protected void assertToken(JsonToken expToken, JsonParser jp)
+ {
+ assertToken(expToken, jp.getCurrentToken());
+ }
+
+ /**
+ * Method that gets textual contents of the current token using
+ * available methods, and ensures results are consistent, before
+ * returning them
+ */
+ protected String getAndVerifyText(JsonParser jp)
+ throws IOException, JsonParseException
+ {
+ // Ok, let's verify other accessors
+ int actLen = jp.getTextLength();
+ char[] ch = jp.getTextCharacters();
+ String str2 = new String(ch, jp.getTextOffset(), actLen);
+ String str = jp.getText();
+
+ if (str.length() != actLen) {
+ fail("Internal problem (jp.token == "+jp.getCurrentToken()+"): jp.getText().length() ['"+str+"'] == "+str.length()+"; jp.getTextLength() == "+actLen);
+ }
+ assertEquals("String access via getText(), getTextXxx() must be the same", str, str2);
+
+ return str;
+ }
+
+ protected void verifyFieldName(JsonParser jp, String expName)
+ throws IOException
+ {
+ assertEquals(expName, jp.getText());
+ assertEquals(expName, jp.currentName());
+ }
+
+ protected void verifyException(Throwable e, String... matches)
+ {
+ String msg = e.getMessage();
+ String lmsg = (msg == null) ? "" : msg.toLowerCase();
+ for (String match : matches) {
+ String lmatch = match.toLowerCase();
+ if (lmsg.indexOf(lmatch) >= 0) {
+ return;
+ }
+ }
+ fail("Expected an exception with one of substrings ("+Arrays.asList(matches)+"): got one ("+
+ e.getClass().getName()+") with message \""+msg+"\"");
+ }
+
+ /*
+ /**********************************************************
+ /* Helper methods, other
+ /**********************************************************
+ */
+
+ protected static String a2q(String content) {
+ return content.replace("'", "\"");
+ }
+
+ protected byte[] utf8Bytes(String str) {
+ return str.getBytes(StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Helper method that tries to remove unnecessary namespace
+ * declaration that default JDK XML parser (SJSXP) sees fit
+ * to add.
+ */
+ protected static String removeSjsxpNamespace(String xml)
+ {
+ final String match = " xmlns=\"\"";
+ int ix = xml.indexOf(match);
+ if (ix > 0) {
+ xml = xml.substring(0, ix) + xml.substring(ix+match.length());
+ }
+ return xml;
+ }
+
+ protected String readAll(File f) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+ BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
+ String line;
+
+ while ((line = br.readLine()) != null) {
+ sb.append(line).append("\n");
+ }
+ br.close();
+ return sb.toString();
+ }
+
+ protected byte[] readResource(String ref)
+ {
+ ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+ final byte[] buf = new byte[4000];
+
+ InputStream in = getClass().getResourceAsStream(ref);
+ if (in != null) {
+ try {
+ int len;
+ while ((len = in.read(buf)) > 0) {
+ bytes.write(buf, 0, len);
+ }
+ in.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to read resource '"+ref+"': "+e);
+ }
+ }
+ if (bytes.size() == 0) {
+ throw new IllegalArgumentException("Failed to read resource '"+ref+"': empty resource?");
+ }
+ return bytes.toByteArray();
+ }
+
+ public String jaxbSerialized(Object ob, Class>... classes) throws Exception
+ {
+ StringWriter sw = new StringWriter();
+ if (classes.length == 0) {
+ jakarta.xml.bind.JAXB.marshal(ob, sw);
+ } else {
+ jakarta.xml.bind.JAXBContext.newInstance(classes).createMarshaller().marshal(ob, sw);
+ }
+ sw.close();
+ return sw.toString();
+ }
+}
diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/adapters/TestIssue47Attribute.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/adapters/TestIssue47Attribute.java
index 8c01e8e78..0e6655010 100644
--- a/src/test/java/com/fasterxml/jackson/dataformat/xml/adapters/TestIssue47Attribute.java
+++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/adapters/TestIssue47Attribute.java
@@ -2,10 +2,14 @@
import java.util.List;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.dataformat.xml.*;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
-public class TestIssue47Attribute extends XmlTestBase
+import static org.junit.jupiter.api.Assertions.*;
+
+public class TestIssue47Attribute extends XmlTestUtil
{
public static class Response
{
@@ -20,6 +24,7 @@ public static class Item
public String b;
}
+ @Test
public void testEmptyStringFromElemAndAttr() throws Exception
{
final XmlMapper MAPPER = new XmlMapper();
diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java
index 06839f6dd..072d88b3d 100644
--- a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java
+++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CaseInsensitiveDeserTest.java
@@ -2,18 +2,22 @@
import java.util.List;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
-import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
+import com.fasterxml.jackson.dataformat.xml.*;
+
+import static org.junit.jupiter.api.Assertions.*;
-public class CaseInsensitiveDeserTest extends XmlTestBase
+public class CaseInsensitiveDeserTest extends XmlTestUtil
{
static class BaseResponse {
public int errorCode;
@@ -80,6 +84,7 @@ public void setName(String n) {
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES)
.build();
+ @Test
public void testCaseInsensitive1036() throws Exception
{
final String DOC =
@@ -100,6 +105,7 @@ public void testCaseInsensitive1036() throws Exception
}
// [dataformat-xml#273]
+ @Test
public void testCaseInsensitiveComplex() throws Exception
{
final String DOC =
diff --git a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CoerceFromEmptyStringTest.java b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CoerceFromEmptyStringTest.java
index 96377db26..01e357bb5 100644
--- a/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CoerceFromEmptyStringTest.java
+++ b/src/test/java/com/fasterxml/jackson/dataformat/xml/deser/CoerceFromEmptyStringTest.java
@@ -3,13 +3,16 @@
import java.util.List;
import java.util.Map;
+import org.junit.jupiter.api.Test;
+
import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.dataformat.xml.XmlMapper;
-import com.fasterxml.jackson.dataformat.xml.XmlTestBase;
+import com.fasterxml.jackson.dataformat.xml.*;
+
+import static org.junit.jupiter.api.Assertions.*;
// Note: copied from coercion tests of `jackson-databind`
-public class CoerceFromEmptyStringTest extends XmlTestBase
+public class CoerceFromEmptyStringTest extends XmlTestUtil
{
static class PointWrapper {
public Point p;
@@ -46,6 +49,7 @@ public NoCtorPOJO(boolean b) { }
private final static String EMPTY_XML = "";
+ @Test
public void testNullsToEmptyPojo() throws Exception
{
PointWrapper pw = MAPPER.readValue("",
@@ -56,6 +60,7 @@ public void testNullsToEmptyPojo() throws Exception
assertEquals(0, pw.p.y);
}
+ @Test
public void testNullsToGenericPojo() throws Exception
{
// String xml = MAPPER.writeValueAsString(new GeneralEmpty(new Point(1, 2)));
@@ -67,6 +72,7 @@ public void testNullsToGenericPojo() throws Exception
assertEquals(0, p.y);
}
+ @Test
public void testNullsToEmptyCollection() throws Exception
{
GeneralEmpty> result = MAPPER.readValue(EMPTY_XML,
@@ -81,6 +87,7 @@ public void testNullsToEmptyCollection() throws Exception
assertEquals(0, result2.value.size());
}
+ @Test
public void testNullsToEmptyMap() throws Exception
{
GeneralEmpty