/* * Copyright 2002-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.http.codec.xml; import java.util.Collections; import java.util.List; import javax.xml.namespace.QName; import javax.xml.stream.events.XMLEvent; import org.junit.Test; import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import org.springframework.core.ResolvableType; import org.springframework.core.io.buffer.AbstractDataBufferAllocatingTestCase; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.MediaType; import org.springframework.http.codec.Pojo; import org.springframework.http.codec.xml.jaxb.XmlRootElement; import org.springframework.http.codec.xml.jaxb.XmlRootElementWithName; import org.springframework.http.codec.xml.jaxb.XmlRootElementWithNameAndNamespace; import org.springframework.http.codec.xml.jaxb.XmlType; import org.springframework.http.codec.xml.jaxb.XmlTypeWithName; import org.springframework.http.codec.xml.jaxb.XmlTypeWithNameAndNamespace; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * @author Sebastien Deleuze */ public class Jaxb2XmlDecoderTests extends AbstractDataBufferAllocatingTestCase { private static final String POJO_ROOT = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<pojo>" + "<foo>foofoo</foo>" + "<bar>barbar</bar>" + "</pojo>"; private static final String POJO_CHILD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<root>" + "<pojo>" + "<foo>foo</foo>" + "<bar>bar</bar>" + "</pojo>" + "<pojo>" + "<foo>foofoo</foo>" + "<bar>barbar</bar>" + "</pojo>" + "<root/>"; private final Jaxb2XmlDecoder decoder = new Jaxb2XmlDecoder(); private final XmlEventDecoder xmlEventDecoder = new XmlEventDecoder(); @Test public void canDecode() { assertTrue(this.decoder.canDecode(ResolvableType.forClass(Pojo.class), MediaType.APPLICATION_XML)); assertTrue(this.decoder.canDecode(ResolvableType.forClass(Pojo.class), MediaType.TEXT_XML)); assertFalse(this.decoder.canDecode(ResolvableType.forClass(Pojo.class), MediaType.APPLICATION_JSON)); assertTrue(this.decoder.canDecode(ResolvableType.forClass(TypePojo.class), MediaType.APPLICATION_XML)); assertFalse(this.decoder.canDecode(ResolvableType.forClass(getClass()), MediaType.APPLICATION_XML)); } @Test public void splitOneBranches() { Flux<XMLEvent> xmlEvents = this.xmlEventDecoder .decode(Flux.just(stringBuffer(POJO_ROOT)), null, null, Collections.emptyMap()); Flux<List<XMLEvent>> result = this.decoder.split(xmlEvents, new QName("pojo")); StepVerifier.create(result) .consumeNextWith(events -> { assertEquals(8, events.size()); assertStartElement(events.get(0), "pojo"); assertStartElement(events.get(1), "foo"); assertCharacters(events.get(2), "foofoo"); assertEndElement(events.get(3), "foo"); assertStartElement(events.get(4), "bar"); assertCharacters(events.get(5), "barbar"); assertEndElement(events.get(6), "bar"); assertEndElement(events.get(7), "pojo"); }) .expectComplete() .verify(); } @Test public void splitMultipleBranches() throws Exception { Flux<XMLEvent> xmlEvents = this.xmlEventDecoder .decode(Flux.just(stringBuffer(POJO_CHILD)), null, null, Collections.emptyMap()); Flux<List<XMLEvent>> result = this.decoder.split(xmlEvents, new QName("pojo")); StepVerifier.create(result) .consumeNextWith(events -> { assertEquals(8, events.size()); assertStartElement(events.get(0), "pojo"); assertStartElement(events.get(1), "foo"); assertCharacters(events.get(2), "foo"); assertEndElement(events.get(3), "foo"); assertStartElement(events.get(4), "bar"); assertCharacters(events.get(5), "bar"); assertEndElement(events.get(6), "bar"); assertEndElement(events.get(7), "pojo"); }) .consumeNextWith(events -> { assertEquals(8, events.size()); assertStartElement(events.get(0), "pojo"); assertStartElement(events.get(1), "foo"); assertCharacters(events.get(2), "foofoo"); assertEndElement(events.get(3), "foo"); assertStartElement(events.get(4), "bar"); assertCharacters(events.get(5), "barbar"); assertEndElement(events.get(6), "bar"); assertEndElement(events.get(7), "pojo"); }) .expectComplete() .verify(); } private static void assertStartElement(XMLEvent event, String expectedLocalName) { assertTrue(event.isStartElement()); assertEquals(expectedLocalName, event.asStartElement().getName().getLocalPart()); } private static void assertEndElement(XMLEvent event, String expectedLocalName) { assertTrue(event.isEndElement()); assertEquals(expectedLocalName, event.asEndElement().getName().getLocalPart()); } private static void assertCharacters(XMLEvent event, String expectedData) { assertTrue(event.isCharacters()); assertEquals(expectedData, event.asCharacters().getData()); } @Test public void decodeSingleXmlRootElement() throws Exception { Flux<DataBuffer> source = Flux.just(stringBuffer(POJO_ROOT)); Flux<Object> output = this.decoder.decode(source, ResolvableType.forClass(Pojo.class), null, Collections.emptyMap()); StepVerifier.create(output) .expectNext(new Pojo("foofoo", "barbar")) .expectComplete() .verify(); } @Test public void decodeSingleXmlTypeElement() throws Exception { Flux<DataBuffer> source = Flux.just(stringBuffer(POJO_ROOT)); Flux<Object> output = this.decoder.decode(source, ResolvableType.forClass(TypePojo.class), null, Collections.emptyMap()); StepVerifier.create(output) .expectNext(new TypePojo("foofoo", "barbar")) .expectComplete() .verify(); } @Test public void decodeMultipleXmlRootElement() throws Exception { Flux<DataBuffer> source = Flux.just(stringBuffer(POJO_CHILD)); Flux<Object> output = this.decoder.decode(source, ResolvableType.forClass(Pojo.class), null, Collections.emptyMap()); StepVerifier.create(output) .expectNext(new Pojo("foo", "bar")) .expectNext(new Pojo("foofoo", "barbar")) .expectComplete() .verify(); } @Test public void decodeMultipleXmlTypeElement() throws Exception { Flux<DataBuffer> source = Flux.just(stringBuffer(POJO_CHILD)); Flux<Object> output = this.decoder.decode(source, ResolvableType.forClass(TypePojo.class), null, Collections.emptyMap()); StepVerifier.create(output) .expectNext(new TypePojo("foo", "bar")) .expectNext(new TypePojo("foofoo", "barbar")) .expectComplete() .verify(); } @Test public void toExpectedQName() { assertEquals(new QName("pojo"), this.decoder.toQName(Pojo.class)); assertEquals(new QName("pojo"), this.decoder.toQName(TypePojo.class)); assertEquals(new QName("namespace", "name"), this.decoder.toQName(XmlRootElementWithNameAndNamespace.class)); assertEquals(new QName("namespace", "name"), this.decoder.toQName(XmlRootElementWithName.class)); assertEquals(new QName("namespace", "xmlRootElement"), this.decoder.toQName(XmlRootElement.class)); assertEquals(new QName("namespace", "name"), this.decoder.toQName(XmlTypeWithNameAndNamespace.class)); assertEquals(new QName("namespace", "name"), this.decoder.toQName(XmlTypeWithName.class)); assertEquals(new QName("namespace", "xmlType"), this.decoder.toQName(XmlType.class)); } @javax.xml.bind.annotation.XmlType(name = "pojo") public static class TypePojo { private String foo; private String bar; public TypePojo() { } public TypePojo(String foo, String bar) { this.foo = foo; this.bar = bar; } public String getFoo() { return this.foo; } public void setFoo(String foo) { this.foo = foo; } public String getBar() { return this.bar; } public void setBar(String bar) { this.bar = bar; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o instanceof TypePojo) { TypePojo other = (TypePojo) o; return this.foo.equals(other.foo) && this.bar.equals(other.bar); } return false; } @Override public int hashCode() { int result = this.foo.hashCode(); result = 31 * result + this.bar.hashCode(); return result; } } }