|
2 | 2 |
|
3 | 3 | import org.junit.jupiter.api.Test; |
4 | 4 |
|
| 5 | +import com.fasterxml.jackson.annotation.JsonRootName; |
| 6 | + |
5 | 7 | import tools.jackson.databind.ObjectWriter; |
6 | 8 | import tools.jackson.dataformat.xml.XmlMapper; |
7 | 9 | import tools.jackson.dataformat.xml.XmlTestUtil; |
8 | 10 | import tools.jackson.dataformat.xml.XmlWriteFeature; |
| 11 | +import tools.jackson.dataformat.xml.annotation.JacksonXmlProperty; |
9 | 12 |
|
10 | 13 | import static org.junit.jupiter.api.Assertions.assertEquals; |
11 | 14 | import static org.junit.jupiter.api.Assertions.fail; |
12 | 15 |
|
13 | 16 | public class XmlGeneratorInitializerTest extends XmlTestUtil |
14 | 17 | { |
| 18 | + // For [dataformat-xml#207]: namespace prefix binding |
| 19 | + @JsonRootName("Ingredients") |
| 20 | + static class Ingredients { |
| 21 | + public String eggs = "12"; |
| 22 | + @JacksonXmlProperty(namespace = "urn:produce:fruit") |
| 23 | + public String bananas = "6"; |
| 24 | + } |
| 25 | + |
| 26 | + @JsonRootName("Root") |
| 27 | + static class NsAttrBean { |
| 28 | + @JacksonXmlProperty(isAttribute = true, namespace = "urn:attr:x", localName = "lang") |
| 29 | + public String lang = "en"; |
| 30 | + } |
| 31 | + |
15 | 32 | private final XmlMapper MAPPER = newMapper(); |
16 | 33 |
|
17 | 34 | // // [dataformat-xml#150]: DTD writing -- ok cases |
@@ -305,6 +322,122 @@ public void testInvalidPIEmptyTarget() throws Exception |
305 | 322 | } |
306 | 323 | } |
307 | 324 |
|
| 325 | + // // [dataformat-xml#207]: namespace prefix bindings |
| 326 | + |
| 327 | + // Without binding, Woodstox emits a synthetic "wstxns1" prefix; with |
| 328 | + // `addNamespace(prefix, uri)` the generator should use the caller-supplied prefix |
| 329 | + // |
| 330 | + // NOTE: somewhat fragile since its Woodstox-specific |
| 331 | + @Test |
| 332 | + public void testNamespacePrefixBinding() throws Exception |
| 333 | + { |
| 334 | + // Without binding: auto-generated prefix (sanity baseline) |
| 335 | + assertEquals(a2q("<Ingredients>" |
| 336 | + +"<wstxns1:bananas xmlns:wstxns1='urn:produce:fruit'>6</wstxns1:bananas>" |
| 337 | + +"<eggs>12</eggs>" |
| 338 | + +"</Ingredients>"), |
| 339 | + MAPPER.writeValueAsString(new Ingredients())); |
| 340 | + |
| 341 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 342 | + .addNamespace("fruit", "urn:produce:fruit")); |
| 343 | + assertEquals(a2q("<Ingredients>" |
| 344 | + +"<fruit:bananas xmlns:fruit='urn:produce:fruit'>6</fruit:bananas>" |
| 345 | + +"<eggs>12</eggs>" |
| 346 | + +"</Ingredients>"), |
| 347 | + w.writeValueAsString(new Ingredients())); |
| 348 | + } |
| 349 | + |
| 350 | + // `addDefaultNamespace(uri)` binds URI as the (unprefixed) default namespace |
| 351 | + @Test |
| 352 | + public void testDefaultNamespaceBinding() throws Exception |
| 353 | + { |
| 354 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 355 | + .addDefaultNamespace("urn:produce:fruit")); |
| 356 | + assertEquals(a2q("<Ingredients>" |
| 357 | + +"<bananas xmlns='urn:produce:fruit'>6</bananas>" |
| 358 | + +"<eggs>12</eggs>" |
| 359 | + +"</Ingredients>"), |
| 360 | + w.writeValueAsString(new Ingredients())); |
| 361 | + } |
| 362 | + |
| 363 | + // Empty prefix must behave identically to `addDefaultNamespace(uri)` (per ArgUtil.emptyToNull) |
| 364 | + @Test |
| 365 | + public void testNamespacePrefixEmptyTreatedAsDefault() throws Exception |
| 366 | + { |
| 367 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 368 | + .addNamespace("", "urn:produce:fruit")); |
| 369 | + assertEquals(a2q("<Ingredients>" |
| 370 | + +"<bananas xmlns='urn:produce:fruit'>6</bananas>" |
| 371 | + +"<eggs>12</eggs>" |
| 372 | + +"</Ingredients>"), |
| 373 | + w.writeValueAsString(new Ingredients())); |
| 374 | + } |
| 375 | + |
| 376 | + // Multiple bindings can be registered; only those actually referenced should appear in output |
| 377 | + @Test |
| 378 | + public void testMultipleNamespaceBindings() throws Exception |
| 379 | + { |
| 380 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 381 | + .addNamespace("fruit", "urn:produce:fruit") |
| 382 | + .addNamespace("veg", "urn:produce:veg")); |
| 383 | + assertEquals(a2q("<Ingredients>" |
| 384 | + +"<fruit:bananas xmlns:fruit='urn:produce:fruit'>6</fruit:bananas>" |
| 385 | + +"<eggs>12</eggs>" |
| 386 | + +"</Ingredients>"), |
| 387 | + w.writeValueAsString(new Ingredients())); |
| 388 | + } |
| 389 | + |
| 390 | + // Namespace binding should also apply to attributes (prefix moves to root element) |
| 391 | + @Test |
| 392 | + public void testNamespacePrefixBindingOnAttribute() throws Exception |
| 393 | + { |
| 394 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 395 | + .addNamespace("x", "urn:attr:x")); |
| 396 | + assertEquals(a2q("<Root xmlns:x='urn:attr:x' x:lang='en'/>"), |
| 397 | + w.writeValueAsString(new NsAttrBean())); |
| 398 | + } |
| 399 | + |
| 400 | + // Registering a namespace URI that isn't referenced by any written |
| 401 | + // element/attribute should not affect output |
| 402 | + @Test |
| 403 | + public void testUnusedNamespaceBindingHasNoEffect() throws Exception |
| 404 | + { |
| 405 | + final String EXPECTED = MAPPER.writeValueAsString(new Ingredients()); |
| 406 | + ObjectWriter w = _writer(new XmlGeneratorInitializer() |
| 407 | + .addNamespace("unused", "urn:nobody:cares")); |
| 408 | + assertEquals(EXPECTED, w.writeValueAsString(new Ingredients())); |
| 409 | + } |
| 410 | + |
| 411 | + // // [dataformat-xml#207]: namespace binding -- failing cases |
| 412 | + |
| 413 | + @Test |
| 414 | + public void testInvalidNamespaceBindings() throws Exception |
| 415 | + { |
| 416 | + try { |
| 417 | + new XmlGeneratorInitializer().addNamespace("p", null); |
| 418 | + fail("Should not pass"); |
| 419 | + } catch (IllegalArgumentException e) { |
| 420 | + verifyException(e, "Illegal argument for 'namespaceURI': must be"); |
| 421 | + } |
| 422 | + try { |
| 423 | + new XmlGeneratorInitializer().addNamespace("p", ""); |
| 424 | + fail("Should not pass"); |
| 425 | + } catch (IllegalArgumentException e) { |
| 426 | + verifyException(e, "Illegal argument for 'namespaceURI': must be"); |
| 427 | + } |
| 428 | + } |
| 429 | + |
| 430 | + @Test |
| 431 | + public void testInvalidDefaultNamespaceNullURI() throws Exception |
| 432 | + { |
| 433 | + try { |
| 434 | + new XmlGeneratorInitializer().addDefaultNamespace(null); |
| 435 | + fail("Should not pass"); |
| 436 | + } catch (IllegalArgumentException e) { |
| 437 | + verifyException(e, "Illegal argument for 'namespaceURI': must be"); |
| 438 | + } |
| 439 | + } |
| 440 | + |
308 | 441 | // // Other tests |
309 | 442 |
|
310 | 443 | private ObjectWriter _writer(XmlGeneratorInitializer initializer) { |
|
0 commit comments