Polishing

This commit is contained in:
Arjen Poutsma
2016-04-21 12:23:44 +02:00
parent dd607d3e53
commit df3cf69a96
7 changed files with 273 additions and 70 deletions

View File

@@ -40,6 +40,7 @@ import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.util.ClassUtils;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.xml.StaxUtils2;
/**
* Decode from a bytes stream of XML elements to a stream of {@code Object} (POJO).
@@ -193,10 +194,10 @@ public class Jaxb2Decoder extends AbstractDecoder<Object> {
});
}
private Object unmarshal(List<XMLEvent> eventFlux, Class<?> outputClass) {
private Object unmarshal(List<XMLEvent> events, Class<?> outputClass) {
try {
Unmarshaller unmarshaller = this.jaxbContexts.createUnmarshaller(outputClass);
XMLEventReader eventReader = new ListBasedXMLEventReader(eventFlux);
XMLEventReader eventReader = StaxUtils2.createXMLEventReader(events);
if (outputClass.isAnnotationPresent(XmlRootElement.class)) {
return unmarshaller.unmarshal(eventReader);
}

View File

@@ -23,7 +23,6 @@ import java.io.SequenceInputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@@ -36,6 +35,7 @@ import reactor.core.subscriber.SubscriberWithContext;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferAllocator;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils2;
/**i
* Utility class for working with {@link DataBuffer}s.
@@ -67,7 +67,7 @@ public abstract class DataBufferUtils {
toIterable(1);
Enumeration<InputStream> enumeration =
new IteratorEnumeration<InputStream>(streams.iterator());
CollectionUtils2.toEnumeration(streams.iterator());
return new SequenceInputStream(enumeration);
}
@@ -169,29 +169,6 @@ public abstract class DataBufferUtils {
});
}
/**
* Enumeration wrapping an Iterator.
*/
// TODO: move to CollectionUtils when we merge with Spring Framework?
private static class IteratorEnumeration<T> implements Enumeration<T> {
private final Iterator<T> iterator;
public IteratorEnumeration(Iterator<T> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasMoreElements() {
return this.iterator.hasNext();
}
@Override
public T nextElement() {
return this.iterator.next();
}
}
private static class ReadableByteChannelConsumer
implements Consumer<SubscriberWithContext<DataBuffer, ReadableByteChannel>> {

View File

@@ -0,0 +1,60 @@
/*
* 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.util;
import java.util.Enumeration;
import java.util.Iterator;
/**
* TODO: to be merged with {@link CollectionUtils}
* @author Arjen Poutsma
*/
public abstract class CollectionUtils2 {
/**
* Adapt an iterator to an enumeration.
* @param iterator the iterator
* @return the enumeration
*/
public static <E> Enumeration<E> toEnumeration(Iterator<E> iterator) {
return new IteratorEnumeration<E>(iterator);
}
/**
* Enumeration wrapping an Iterator.
*/
private static class IteratorEnumeration<T> implements Enumeration<T> {
private final Iterator<T> iterator;
public IteratorEnumeration(Iterator<T> iterator) {
this.iterator = iterator;
}
@Override
public boolean hasMoreElements() {
return this.iterator.hasNext();
}
@Override
public T nextElement() {
return this.iterator.next();
}
}
}

View File

@@ -14,9 +14,8 @@
* limitations under the License.
*/
package org.springframework.core.codec.support;
package org.springframework.util.xml;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
@@ -24,60 +23,26 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
/**
* TODO: move to org.springframework.util.xml when merging, hidden behind StaxUtils
*
* Abstract base class for {@code XMLEventReader}s.
* @author Arjen Poutsma
*/
class ListBasedXMLEventReader implements XMLEventReader {
abstract class AbstractXMLEventReader implements XMLEventReader {
private final XMLEvent[] events;
private int cursor = 0;
public ListBasedXMLEventReader(List<XMLEvent> events) {
Assert.notNull(events, "'events' must not be null");
this.events = events.toArray(new XMLEvent[events.size()]);
}
private boolean closed;
@Override
public boolean hasNext() {
Assert.notNull(events, "'events' must not be null");
return cursor != events.length;
}
@Override
public XMLEvent nextEvent() {
if (cursor < events.length) {
return events[cursor++];
public Object next() {
try {
return nextEvent();
}
else {
catch (XMLStreamException ex) {
throw new NoSuchElementException();
}
}
@Override
public XMLEvent peek() {
if (cursor < events.length) {
return events[cursor];
}
else {
return null;
}
}
@Override
public Object next() {
return nextEvent();
}
/**
* Throws an {@code UnsupportedOperationException} when called.
* @throws UnsupportedOperationException when called
*/
@Override
public void remove() {
throw new UnsupportedOperationException(
@@ -86,6 +51,7 @@ class ListBasedXMLEventReader implements XMLEventReader {
@Override
public String getElementText() throws XMLStreamException {
checkIfClosed();
if (!peek().isStartElement()) {
throw new XMLStreamException("Not at START_ELEMENT");
}
@@ -110,6 +76,7 @@ class ListBasedXMLEventReader implements XMLEventReader {
@Override
public XMLEvent nextTag() throws XMLStreamException {
checkIfClosed();
while (true) {
XMLEvent event = nextEvent();
switch (event.getEventType()) {
@@ -145,7 +112,28 @@ class ListBasedXMLEventReader implements XMLEventReader {
throw new IllegalArgumentException("Property not supported: [" + name + "]");
}
/**
* Returns {@code true} if closed; {@code false} otherwise.
* @see #close()
*/
protected boolean isClosed() {
return closed;
}
/**
* Checks if the reader is closed, and throws a {@code XMLStreamException} if so.
* @throws XMLStreamException if the reader is closed
* @see #close()
* @see #isClosed()
*/
protected void checkIfClosed() throws XMLStreamException {
if (isClosed()) {
throw new XMLStreamException("XMLEventReader has been closed");
}
}
@Override
public void close() {
closed = true;
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.util.xml;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import javax.xml.stream.events.XMLEvent;
import org.springframework.util.Assert;
/**
* Implementation of {@code XMLEventReader} based on a list of {@link XMLEvent}s.
*
* @author Arjen Poutsma
*/
class ListBasedXMLEventReader extends AbstractXMLEventReader {
private final List<XMLEvent> events;
private int cursor = 0;
public ListBasedXMLEventReader(List<XMLEvent> events) {
Assert.notNull(events, "'events' must not be null");
this.events = Collections.unmodifiableList(events);
}
@Override
public boolean hasNext() {
return cursor != events.size();
}
@Override
public XMLEvent nextEvent() {
if (cursor < events.size()) {
return events.get(cursor++);
}
else {
throw new NoSuchElementException();
}
}
@Override
public XMLEvent peek() {
if (cursor < events.size()) {
return events.get(cursor);
}
else {
return null;
}
}
@Override
public void close() {
super.close();
this.events.clear();
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.util.xml;
import java.util.List;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.XMLEvent;
/**
* TODO: to be merged with {@link StaxUtils}.
* @author Arjen Poutsma
*/
public abstract class StaxUtils2 {
/**
* Create a {@link XMLEventReader} from the given list of {@link XMLEvent}.
* @param events the list of {@link XMLEvent}s.
* @return an {@code XMLEventReader} that reads from the given events
*/
public static XMLEventReader createXMLEventReader(List<XMLEvent> events) {
return new ListBasedXMLEventReader(events);
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.util.xml;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import org.junit.Test;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
/**
* @author Arjen Poutsma
*/
public class ListBasedXMLEventReaderTests {
private final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
private final XMLOutputFactory outputFactory = XMLOutputFactory.newFactory();
@Test
public void standard() throws Exception {
String xml = "<foo><bar>baz</bar></foo>";
List<XMLEvent> events = readEvents(xml);
ListBasedXMLEventReader reader = new ListBasedXMLEventReader(events);
StringWriter resultWriter = new StringWriter();
XMLEventWriter writer = this.outputFactory.createXMLEventWriter(resultWriter);
writer.add(reader);
assertXMLEqual(xml, resultWriter.toString());
}
private List<XMLEvent> readEvents(String xml) throws XMLStreamException {
XMLEventReader reader =
this.inputFactory.createXMLEventReader(new StringReader(xml));
List<XMLEvent> events = new ArrayList<>();
while (reader.hasNext()) {
events.add(reader.nextEvent());
}
return events;
}
}