1616
1717import 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