1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.xml;
18
19 import static org.assertj.core.api.Assertions.assertThat;
20 import static org.mockito.Mockito.mock;
21
22 import jakarta.xml.bind.Marshaller;
23 import jakarta.xml.bind.ValidationEventHandler;
24 import jakarta.xml.bind.attachment.AttachmentMarshaller;
25 import jakarta.xml.bind.attachment.AttachmentUnmarshaller;
26 import java.io.StringReader;
27 import java.io.StringWriter;
28 import java.time.Duration;
29 import java.time.OffsetDateTime;
30 import java.time.format.DateTimeFormatter;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.ServiceLoader;
34 import org.assertj.core.api.InstanceOfAssertFactories;
35 import org.assertj.core.api.SoftAssertions;
36 import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
37 import org.bremersee.xml.adapter.DateXmlAdapter;
38 import org.bremersee.xml.adapter.DurationXmlAdapter;
39 import org.bremersee.xml.adapter.EpochMilliXmlAdapter;
40 import org.bremersee.xml.adapter.OffsetDateTimeXmlAdapter;
41 import org.bremersee.xml.model1.Person;
42 import org.bremersee.xml.model2.Vehicle;
43 import org.bremersee.xml.model3.Company;
44 import org.bremersee.xml.model4.Address;
45 import org.bremersee.xml.model5.StartEnd;
46 import org.bremersee.xml.model6.StandaloneModel;
47 import org.bremersee.xml.model7a.Fender;
48 import org.bremersee.xml.model7a.ObjectFactory;
49 import org.bremersee.xml.model7b.DirtBikeReseller;
50 import org.bremersee.xml.model7b.MountainBike;
51 import org.bremersee.xml.model7b.RacingBike;
52 import org.bremersee.xml.model7b.RacingReseller;
53 import org.bremersee.xml.model7b.SportBikes;
54 import org.bremersee.xml.model7c.Carrier;
55 import org.bremersee.xml.model8.AnyElementList;
56 import org.junit.jupiter.api.Test;
57 import org.junit.jupiter.api.extension.ExtendWith;
58 import org.w3c.dom.Element;
59
60
61
62
63
64
65 @ExtendWith({SoftAssertionsExtension.class})
66 class JaxbContextBuilderTest {
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 private static final String XML1 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
95 + "<ns2:MountainBike "
96 + "xsi:schemaLocation=\"http://bremersee.org/xmlschemas/common-xml-test-model-7a "
97 + "http://bremersee.github.io/xmlschemas/common-xml-test-model-7a.xsd "
98 + "http://bremersee.org/xmlschemas/common-xml-test-model-7b "
99 + "http://bremersee.github.io/xmlschemas/common-xml-test-model-7b.xsd\" "
100 + "xmlns=\"http://bremersee.org/xmlschemas/common-xml-test-model-7a\" "
101 + "xmlns:ns2=\"http://bremersee.org/xmlschemas/common-xml-test-model-7b\" "
102 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
103 + "<producer xsi:type=\"ns2:sportBikesType\">"
104 + "<name>Sport Bikes</name>"
105 + "<ns2:Reseller xsi:type=\"ns2:dirtBikeResellerType\">"
106 + "<name>Dirt Bikes</name></ns2:Reseller>"
107 + "<ns2:Reseller xsi:type=\"ns2:racingResellerType\">"
108 + "<name>Racing Fun</name></ns2:Reseller>"
109 + "</producer><color>Red</color><extraParts>"
110 + "<ns2:Carrier "
111 + "xsi:schemaLocation=\"http://bremersee.org/xmlschemas/common-xml-test-model-7a "
112 + "http://bremersee.github.io/xmlschemas/common-xml-test-model-7a.xsd "
113 + "http://bremersee.org/xmlschemas/common-xml-test-model-7c "
114 + "http://bremersee.github.io/xmlschemas/common-xml-test-model-7c.xsd\" "
115 + "xmlns:ns2=\"http://bremersee.org/xmlschemas/common-xml-test-model-7c\">"
116 + "<partNumber>123456789</partNumber>"
117 + "<ns2:capacity>15 kg</ns2:capacity>"
118 + "</ns2:Carrier>"
119 + "</extraParts>"
120 + "<ns2:seatHeight>60</ns2:seatHeight></ns2:MountainBike>";
121
122
123
124
125
126
127
128 @Test
129 void readAndWriteElement(SoftAssertions softly) throws Exception {
130
131 Carrier carrier = new Carrier();
132 carrier.setPartNumber("123456789");
133 carrier.setCapacity("15 kg");
134
135 DirtBikeReseller r0 = new DirtBikeReseller();
136 r0.setName("Dirt Bikes");
137 RacingReseller r1 = new RacingReseller();
138 r1.setName("Racing Fun");
139
140 SportBikes sportBikes = new SportBikes();
141 sportBikes.setName("Sport Bikes");
142 sportBikes.getChain().add(r0);
143 sportBikes.getChain().add(r1);
144
145 JaxbContextBuilder builder = JaxbContextBuilder
146 .newInstance()
147 .withDependenciesResolver(new JaxbDependenciesResolverImpl())
148 .withXmlAdapters(Arrays.asList(new OffsetDateTimeXmlAdapter(), new DurationXmlAdapter()))
149 .copy()
150 .withFormattedOutput(false)
151 .withSchemaMode(SchemaMode.MARSHAL)
152 .withSchemaBuilder(SchemaBuilder.newInstance())
153 .withContextClassLoader(Thread.currentThread().getContextClassLoader())
154 .addAll(Arrays.asList(
155 new JaxbContextData(ObjectFactory.class.getPackage()),
156 new JaxbContextData(org.bremersee.xml.model7b.ObjectFactory.class.getPackage()),
157 new JaxbContextData(org.bremersee.xml.model7c.ObjectFactory.class.getPackage())))
158 .process(() -> List.of(new JaxbContextData(StandaloneModel.class)))
159 .processAll(ServiceLoader.load(JaxbContextDataProvider.class));
160
161 MountainBike model = new MountainBike();
162 model.setSeatHeight(60);
163 model.setColor("Red");
164 model.setProducer(sportBikes);
165
166 Element carrierElement = XmlDocumentBuilder.newInstance()
167 .buildDocument(carrier, builder.buildMarshaller(carrier))
168 .getDocumentElement();
169 model.getExtraParts().add(carrierElement);
170
171 MountainBike actualModel = (MountainBike) builder
172 .copy()
173 .withDependenciesResolver(null)
174 .buildUnmarshaller(MountainBike.class)
175 .unmarshal(new StringReader(XML1));
176 softly.assertThat(actualModel)
177 .isEqualTo(model);
178 softly.assertThat(actualModel.getExtraParts())
179 .map(elem -> builder
180 .buildUnmarshaller().unmarshal(elem))
181 .containsExactly(carrier);
182
183 StringWriter sw = new StringWriter();
184 builder.buildMarshaller(model).marshal(model, sw);
185 String actualXml = sw.toString();
186 softly.assertThat(actualXml)
187 .isEqualTo(XML1);
188 }
189
190
191
192
193
194
195 @Test
196 void writeAndReadAnyElements() throws Exception {
197 OffsetDateTime start = OffsetDateTime
198 .parse("2000-01-16T12:00:00.000Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME);
199 AnyElementList list = new AnyElementList(List.of(
200
201
202 new Company("UnitTest"),
203
204
205 new Address("Surefire", "123", new StartEnd(start, null, null)),
206
207
208 new StandaloneModel("assert")
209 ));
210
211 JaxbContextBuilder builder = JaxbContextBuilder
212 .newInstance();
213 Marshaller marshaller = builder.buildMarshaller(list);
214 StringWriter sw = new StringWriter();
215 marshaller.marshal(list, sw);
216
217 String xml = sw.toString();
218
219 AnyElementList actual = (AnyElementList) builder
220 .buildUnmarshaller().unmarshal(new StringReader(xml));
221 assertThat(actual)
222 .isEqualTo(list);
223 }
224
225
226
227
228
229
230
231 @Test
232 void writeAndReadDateTime(SoftAssertions softly) throws Exception {
233
234 JaxbContextBuilder builder = JaxbContextBuilder
235 .newInstance()
236 .initJaxbContext()
237 .withFormattedOutput(true)
238 .withSchemaMode(SchemaMode.ALWAYS)
239 .addAll(List.of(new JaxbContextData(Address.class)).iterator())
240 .initJaxbContext();
241
242 softly.assertThat(builder.canMarshal(Address.class))
243 .isTrue();
244 softly.assertThat(builder.canUnmarshal(Address.class))
245 .isTrue();
246
247 StartEnd startEnd = new StartEnd();
248 startEnd.setStart(OffsetDateTime
249 .parse("2000-01-16T12:00:00Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME));
250 startEnd.setEnd(OffsetDateTime
251 .parse("2000-01-20T12:00:00Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME));
252 startEnd.setDuration(Duration.ofDays(4));
253
254 Address model = new Address();
255 model.setStreet("Casparstreet");
256 model.setStreetNumber("1234");
257 model.setStartEnd(startEnd);
258
259 StringWriter sw = new StringWriter();
260 builder.buildMarshaller().marshal(model, sw);
261 String xml = sw.toString();
262
263 Address actual = (Address) builder.buildUnmarshaller(Address.class, Company.class)
264 .unmarshal(new StringReader(xml));
265 softly.assertThat(actual)
266 .isEqualTo(model);
267 }
268
269
270
271
272
273
274
275 @Test
276 void writeAndReadDateTimeWithEmptyContext(SoftAssertions softly) throws Exception {
277
278 StartEnd startEnd = new StartEnd();
279 startEnd.setStart(OffsetDateTime
280 .parse("2000-01-16T12:00:00Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME));
281 startEnd.setEnd(OffsetDateTime
282 .parse("2000-01-20T12:00:00Z", DateTimeFormatter.ISO_OFFSET_DATE_TIME));
283
284 Address model = new Address();
285 model.setStreet("Casparstreet");
286 model.setStreetNumber("1234");
287 model.setStartEnd(startEnd);
288
289 JaxbContextBuilder builder = JaxbContextBuilder
290 .newInstance()
291 .withSchemaMode(SchemaMode.UNMARSHAL);
292
293 StringWriter sw = new StringWriter();
294 builder.buildMarshaller(new Class[]{Address.class, Company.class}).marshal(model, sw);
295 String xml = sw.toString();
296
297 Address actual = (Address) builder.buildUnmarshaller(Address.class)
298 .unmarshal(new StringReader(xml));
299 softly.assertThat(actual)
300 .isEqualTo(model);
301
302 JaxbContextBuilder jaxbContextBuilder = JaxbContextBuilder.newInstance()
303 .withXmlAdapters(null)
304 .withDependenciesResolver(null);
305 sw = new StringWriter();
306 jaxbContextBuilder.buildMarshaller(model).marshal(model, sw);
307 xml = sw.toString();
308
309 actual = (Address) builder.buildUnmarshaller(Address.class)
310 .unmarshal(new StringReader(xml));
311 softly.assertThat(actual)
312 .isEqualTo(model);
313 }
314
315
316
317
318
319
320
321 @Test
322 void buildJaxbContext(SoftAssertions softly) throws Exception {
323 JaxbContextWrapper ctx = JaxbContextBuilder.newInstance().copy()
324 .withFormattedOutput(true)
325 .withSchemaMode(SchemaMode.EXTERNAL_XSD)
326 .withAttachmentMarshaller(mock(AttachmentMarshaller.class))
327 .withAttachmentUnmarshaller(mock(AttachmentUnmarshaller.class))
328 .withValidationEventHandler(mock(ValidationEventHandler.class))
329 .withXmlAdapters(Arrays.asList(
330 new EpochMilliXmlAdapter(),
331 new DateXmlAdapter()))
332 .add(new JaxbContextData(RacingBike.class))
333 .buildJaxbContext();
334
335 softly.assertThat(ctx)
336 .extracting(JaxbContextWrapper::createJAXBIntrospector)
337 .isNotNull();
338 softly.assertThat(ctx)
339 .extracting(JaxbContextWrapper::getAttachmentMarshaller)
340 .isNotNull();
341 softly.assertThat(ctx)
342 .extracting(JaxbContextWrapper::getAttachmentUnmarshaller)
343 .isNotNull();
344 softly.assertThat(ctx)
345 .extracting(JaxbContextWrapper::getXmlAdapters)
346 .isNotNull();
347 softly.assertThat(ctx)
348 .extracting(JaxbContextWrapper::getSchema)
349 .isNotNull();
350 softly.assertThat(ctx)
351 .extracting(JaxbContextWrapper::getDetails)
352 .isNotNull();
353 softly.assertThat(ctx)
354 .extracting(JaxbContextWrapper::getValidationEventHandler)
355 .isNotNull();
356 softly.assertThat(ctx)
357 .extracting(JaxbContextWrapper::isFormattedOutput, InstanceOfAssertFactories.BOOLEAN)
358 .isTrue();
359 softly.assertThat(ctx)
360 .extracting(JaxbContextWrapper::getSchemaMode)
361 .isEqualTo(SchemaMode.EXTERNAL_XSD);
362
363 softly.assertThat(ctx.createMarshaller())
364 .isNotNull();
365 softly.assertThat(ctx.createUnmarshaller())
366 .isNotNull();
367 }
368
369
370
371
372
373
374 @Test
375 void buildUnmarshaller(SoftAssertions softly) {
376 JaxbContextBuilder builder = JaxbContextBuilder.newInstance()
377 .withSchemaMode(SchemaMode.EXTERNAL_XSD);
378 softly.assertThat(builder.buildUnmarshaller(Fender.class)).isNotNull();
379 softly.assertThat(builder.buildUnmarshaller(StandaloneModel.class)).isNotNull();
380 }
381
382
383
384
385
386
387 @Test
388 void buildMarshaller(SoftAssertions softly) {
389 JaxbContextBuilder builder = JaxbContextBuilder.newInstance()
390 .withSchemaMode(SchemaMode.EXTERNAL_XSD);
391 softly.assertThat(builder.buildMarshaller(new Fender())).isNotNull();
392 softly.assertThat(builder.buildMarshaller(StandaloneModel.class)).isNotNull();
393 softly.assertThat(builder
394 .copy()
395 .withDependenciesResolver(null)
396 .buildMarshaller(new Class<?>[]{Person.class, Vehicle.class}))
397 .isNotNull();
398 }
399
400
401
402
403
404
405 @Test
406 void buildSchema(SoftAssertions softly) {
407 JaxbContextBuilder builder = JaxbContextBuilder.newInstance()
408 .withSchemaMode(SchemaMode.EXTERNAL_XSD)
409 .add(new JaxbContextData(Person.class));
410 softly.assertThat(builder.buildSchema()).isNotNull();
411 softly.assertThat(builder.buildSchema(new Fender())).isNotNull();
412 }
413
414 }