Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 51ee34b

Browse files
authored
Merge pull request #247 from xmlunit/jakarta-jaxb
use Jakarta JAXB with minimal backwards incompatibility
2 parents 2e5ca1e + 528ba4f commit 51ee34b

File tree

30 files changed

+1479
-150
lines changed

30 files changed

+1479
-150
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
language: java
2-
env: VERSION=2.8.5-SNAPSHOT
2+
env: VERSION=2.9.0-SNAPSHOT
33
matrix:
44
include:
55
- dist: trusty

README.md

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,16 +221,9 @@ The `core` library provides all functionality needed to test XML
221221
output and hasn't got any dependencies. It uses JUnit 4.x for its own
222222
tests.
223223

224-
If you are using Java 9 or later the core also depends on the JAXB
225-
API. This used to be part of the standard class library but has been
226-
split out of it with Java 9.
227-
228-
If you want to use `Input.fromJaxb` - i.e. you want to serialize plain
229-
Java objects to XML as input - then you also need to add a dependency
230-
on the JAXB implementation. Starting with XMLUnit 2.6.4, xmlunit-core
231-
optionally depends on the JAXB reference implementation and its
232-
transitive dependencies. Starting with XMLUnit 2.8.0 the JAXB
233-
dependency requires the JakartaEE version of JAXB.
224+
If you want to use `Input.fromJaxb` - i.e. you want to serialize plain Java objects to XML as input - then you may also
225+
need to add a dependency on the JAXB implementation. For more details see the [User's
226+
Guide](https://github.com/xmlunit/user-guide/wiki/JAXB).
234227

235228
The core library is complemented by Hamcrest 1.x matchers and AssertJ
236229
assertions. There also exists a `legacy` project that provides the

RELEASE_NOTES.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
# Release Notes
22

3-
## XMLUnit for Java 2.8.5 - /no released, yet/
3+
## XMLUnit for Java 2.9.0 - /no released, yet/
4+
5+
* added a new module `xmlunit-jakarta-jaxb-impl` that makes
6+
`Input.fromJaxb` use `jakarta.xml.bind` rather than
7+
`javax.xml.bind`. For more details see the [User's
8+
Guide](https://github.com/xmlunit/user-guide/wiki/JAXB).
9+
10+
This change is not fully backwards compatible. The `JaxbBuilder`
11+
class has become abstract and the `withMarshaller` method has
12+
changed its signature. For most cases the change will not be noticed
13+
and for almost all other cases it should be enough to re-compile
14+
your code against XMLUnit 2.9.x.
415

516
## XMLUnit for Java 2.8.4 - /Released 2021-12-16/
617

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<groupId>org.xmlunit</groupId>
1919
<artifactId>xmlunit-parent</artifactId>
2020
<packaging>pom</packaging>
21-
<version>2.8.5-SNAPSHOT</version>
21+
<version>2.9.0-SNAPSHOT</version>
2222
<name>org.xmlunit:xmlunit-parent</name>
2323
<description>Parent POM for all artifacts of XMLUnit</description>
2424
<url>https://www.xmlunit.org/</url>
@@ -282,6 +282,10 @@
282282
<title>XMLUnit Placeholders ${project.version}</title>
283283
<packages>org.xmlunit.placeholder*</packages>
284284
</group>
285+
<group>
286+
<title>XMLUnit Jakarta XML Binding Support ${project.version}</title>
287+
<packages>org.xmlunit.builder.jakarta_jaxb*</packages>
288+
</group>
285289
</groups>
286290
<quiet>true</quiet>
287291
<source>${maven.javadoc.source}</source>
@@ -501,6 +505,7 @@
501505
</activation>
502506
<modules>
503507
<module>xmlunit-assertj3</module>
508+
<module>xmlunit-jakarta-jaxb-impl</module>
504509
</modules>
505510
<properties>
506511
<javadoc.additionalparam>-Xdoclint:html,syntax,accessibility,reference</javadoc.additionalparam>

src/main/javadoc/overview.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@
2121
contains <a href="https://assertj.github.io/doc/">AssertJ
2222
3.x</a> assertions on top of <code>xmlunit-core</code> that
2323
work with AssertJ 3.18.1 and later.</li>
24+
<li><code>xmlunit-placeholders</code> - an experimental component that uses an extensible DSL inside of the
25+
control document to simplify certain special cases for comparisons.</li>
26+
<li><code>xmlunit-jakarta-jaxb-impl</code> provides a JAXB {@code Input} builder that uses version 3.x
27+
of <a href="https://jakarta.ee/specifications/xml-binding/">Jakarta XML Binding</a> rather than it predecessor
28+
that uses the {@code javax.xml.bind} package (and is supported by <code>xmlunit-core</code> directly).</li>
2429
</ul>
2530

2631
<p>While XMLUnit is focussed on testing, parts of it may be useful

xmlunit-assertj/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<parent>
1919
<artifactId>xmlunit-parent</artifactId>
2020
<groupId>org.xmlunit</groupId>
21-
<version>2.8.5-SNAPSHOT</version>
21+
<version>2.9.0-SNAPSHOT</version>
2222
</parent>
2323
<modelVersion>4.0.0</modelVersion>
2424

xmlunit-assertj3/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<parent>
1919
<artifactId>xmlunit-parent</artifactId>
2020
<groupId>org.xmlunit</groupId>
21-
<version>2.8.5-SNAPSHOT</version>
21+
<version>2.9.0-SNAPSHOT</version>
2222
</parent>
2323
<modelVersion>4.0.0</modelVersion>
2424

xmlunit-core/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<parent>
1919
<groupId>org.xmlunit</groupId>
2020
<artifactId>xmlunit-parent</artifactId>
21-
<version>2.8.5-SNAPSHOT</version>
21+
<version>2.9.0-SNAPSHOT</version>
2222
</parent>
2323

2424
<groupId>org.xmlunit</groupId>

xmlunit-core/src/main/java/org/xmlunit/builder/Input.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void setSystemId(String id) {
115115
* byte[] (XML as byte[]), {@link String} (XML as String), {@link File} (contains XML),
116116
* {@link URL} (to an XML-Document), {@link URI} (to an XML-Document), {@link InputStream},
117117
* {@link ReadableByteChannel}, {@link Path},
118-
* Jaxb-{@link Object} (marshal-able with {@link javax.xml.bind.JAXB}.marshal(...))
118+
* Jaxb-{@link Object} (marshal-able with {@code JAXB}.marshal(...))
119119
*/
120120
public static Builder from(Object object) {
121121
Builder xml;
@@ -154,7 +154,7 @@ public static Builder from(Object object) {
154154
* Build a Source from a Jaxb-Object.
155155
*/
156156
public static JaxbBuilder fromJaxb(Object jaxbObject) {
157-
return new JaxbBuilder(jaxbObject);
157+
return JaxbBuilderFactoryLocator.getFactory().create(jaxbObject);
158158
}
159159

160160
/**

xmlunit-core/src/main/java/org/xmlunit/builder/JaxbBuilder.java

Lines changed: 34 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -16,31 +16,14 @@
1616

1717
import org.xmlunit.builder.Input.Builder;
1818

19-
import javax.xml.bind.DataBindingException;
20-
import javax.xml.bind.JAXBContext;
21-
import javax.xml.bind.JAXBElement;
22-
import javax.xml.bind.JAXBException;
23-
import javax.xml.bind.Marshaller;
24-
import javax.xml.bind.PropertyException;
25-
import javax.xml.bind.annotation.XmlRootElement;
26-
import javax.xml.bind.util.JAXBSource;
27-
import javax.xml.namespace.QName;
28-
import javax.xml.transform.Source;
29-
30-
import java.beans.Introspector;
31-
import java.lang.reflect.Method;
32-
3319
/**
34-
* {@link Builder} for Jaxb-Object and creating a {@link JAXBSource}.
35-
* <p>
36-
* If no custom {@link Marshaller} is set by {@link #withMarshaller(Marshaller)}, then the same logic as in {@link JAXB}
37-
* is used the create a default {@link Marshaller}.
20+
* {@link Builder} for Jaxb-Object and creating a {@code JAXBSource}.
3821
*/
39-
public class JaxbBuilder implements Builder {
22+
public abstract class JaxbBuilder implements Builder {
4023

4124
private final Object object;
42-
private Marshaller marshaller;
43-
private boolean userObjectFactory;
25+
private Object marshaller;
26+
private boolean useObjectFactory;
4427

4528
/**
4629
* Creates a builder based on the given object.
@@ -50,126 +33,58 @@ protected JaxbBuilder(final Object object) {
5033
}
5134

5235
/**
53-
* Sets a non-default {@link Marshaller} to use when creating the {@link Source}.
36+
* Sets a non-default {@code Marshaller} to use when creating the {@link Source}.
5437
*/
55-
public JaxbBuilder withMarshaller(final Marshaller marshaller) {
38+
public JaxbBuilder withMarshaller(final Object marshaller) {
5639
this.marshaller = marshaller;
5740
return this;
5841
}
5942

6043
/**
61-
* If the given Object has no {@link XmlRootElement} annotation and is not an instants of {@link JAXBElement} it
62-
* must be wrapped by a {@link JAXBElement}.
44+
* Whether the given Object has no {@code XmlRootElement} annotation and is not an instants of {@code JAXBElement} it
45+
* must be wrapped by a {@code JAXBElement}.
6346
* <p>
6447
* This method will find the {@code ObjectFactory} class (normally generated by jaxb) and use the first matching
65-
* factory-method for the given Object to create the {@link JAXBElement}-Wrapper.
48+
* factory-method for the given Object to create the {@code JAXBElement}-Wrapper.
6649
* <p>
6750
* If no ObjectFactory and method exists for the given object, the default behavior (same behavior as by
68-
* {@link JAXB}) will be used to create the {@link JAXBElement}-Wrapper for the given Object.
51+
* {@code JAXB}) will be used to create the {@code JAXBElement}-Wrapper for the given Object.
6952
* <p>
7053
* If you don't use the {@code xjc:simple} flag to generate your JAXB-Objects, the use of the OjectFactory is most likely
7154
* required to generate Schema-Valid XML.
7255
*/
7356
public JaxbBuilder useObjectFactory() {
74-
this.userObjectFactory = true;
57+
this.useObjectFactory = true;
7558
return this;
7659
}
7760

78-
@Override
79-
public Source build() {
80-
try {
81-
if (marshaller == null) {
82-
createDefaultMarshaller();
83-
}
84-
85-
final Object jaxbObject = getPreparedJaxbObject();
86-
final JAXBSource jaxbSource = new JAXBSource(marshaller, jaxbObject);
87-
// the fake InputSource cannot be used (the Convert.java
88-
// will create a working one if it is null)
89-
jaxbSource.setInputSource(null);
90-
return jaxbSource;
91-
} catch (final JAXBException e) {
92-
throw new DataBindingException(e);
93-
}
94-
}
95-
96-
private Object getPreparedJaxbObject() {
97-
final Object jaxbObject;
98-
if (object instanceof JAXBElement) {
99-
jaxbObject = object;
100-
} else {
101-
final Class<?> clazz = object.getClass();
102-
final XmlRootElement r = clazz.getAnnotation(XmlRootElement.class);
103-
if (r == null) {
104-
if (userObjectFactory) {
105-
jaxbObject = createJAXBElement(object);
106-
} else {
107-
jaxbObject = createInferredJAXBElement(object);
108-
}
109-
} else {
110-
jaxbObject = object;
111-
}
112-
}
113-
return jaxbObject;
114-
}
115-
116-
private void createDefaultMarshaller() throws JAXBException, PropertyException {
117-
JAXBContext context;
118-
if (object instanceof JAXBElement) {
119-
context = JAXBContext.newInstance(((JAXBElement<?>) object).getDeclaredType());
120-
} else {
121-
final Class<?> clazz = object.getClass();
122-
context = JAXBContext.newInstance(clazz);
123-
}
124-
marshaller = context.createMarshaller();
125-
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
126-
}
127-
128-
@SuppressWarnings("unchecked")
129-
private static <T> JAXBElement<T> createInferredJAXBElement(final T object) {
130-
final Class<T> clazz = (Class<T>) object.getClass();
131-
// we need to infer the name
132-
return new JAXBElement<T>(new QName(inferName(clazz)), clazz, object);
133-
}
134-
135-
private static <T> JAXBElement<T> createJAXBElement(final T jaxbObj) {
136-
final JAXBElement<T> jaxbElementFromObjectFactory = createJaxbElementFromObjectFactory(jaxbObj);
137-
if (jaxbElementFromObjectFactory == null) {
138-
return createInferredJAXBElement(jaxbObj);
139-
} else {
140-
return jaxbElementFromObjectFactory;
141-
}
61+
/**
62+
* Provides the configured object.
63+
* @return the configured object
64+
* @since 2.9.0
65+
*/
66+
protected final Object getObject() {
67+
return object;
14268
}
14369

144-
@SuppressWarnings("unchecked")
145-
private static <T> JAXBElement<T> createJaxbElementFromObjectFactory(final T obj) {
146-
try {
147-
final Class<?> objFactClass = getObjectFactoryClass(obj);
148-
final Object objFact = objFactClass.newInstance();
149-
final Method[] methods = objFactClass.getMethods();
150-
151-
Object jaxbObj = null;
152-
for (final Method method : methods) {
153-
final Class<?>[] params = method.getParameterTypes();
154-
if (params.length == 1 && params[0] == obj.getClass()
155-
&& method.getReturnType().isAssignableFrom(JAXBElement.class)) {
156-
jaxbObj = method.invoke(objFact, obj);
157-
break;
158-
}
159-
}
160-
return (JAXBElement<T>) jaxbObj;
161-
} catch (final Exception e) {
162-
// ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException
163-
return null;
164-
}
70+
/**
71+
* Provides the custom Marshaller.
72+
* @return the configured Marshaller
73+
* @since 2.9.0
74+
*/
75+
protected final Object getMarshaller() {
76+
return marshaller;
16577
}
16678

167-
private static <T> Class<?> getObjectFactoryClass(final T obj) throws ClassNotFoundException {
168-
final String objFactClassName = obj.getClass().getPackage().getName() + ".ObjectFactory";
169-
return Thread.currentThread().getContextClassLoader().loadClass(objFactClassName);
79+
/**
80+
* Provides whether the given Object has no {@code XmlRootElement} annotation and is not an instants of {@code JAXBElement} it
81+
* must be wrapped by a {@code JAXBElement}.
82+
* @return whether the given Object has no {@code XmlRootElement} annotation and is not an instants of {@code JAXBElement} it
83+
* must be wrapped by a {@code JAXBElement}.
84+
* @since 2.9.0
85+
*/
86+
protected final boolean getUseObjectFactory() {
87+
return useObjectFactory;
17088
}
17189

172-
private static String inferName(final Class clazz) {
173-
return Introspector.decapitalize(clazz.getSimpleName());
174-
}
17590
}

0 commit comments

Comments
 (0)