1
1
/*
2
- * Copyright 2002-2016 the original author or authors.
2
+ * Copyright 2002-2017 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
23
23
import javax .xml .XMLConstants ;
24
24
import javax .xml .bind .JAXBElement ;
25
25
import javax .xml .bind .JAXBException ;
26
+ import javax .xml .bind .UnmarshalException ;
26
27
import javax .xml .bind .Unmarshaller ;
27
28
import javax .xml .bind .annotation .XmlRootElement ;
28
29
import javax .xml .bind .annotation .XmlSchema ;
37
38
38
39
import org .springframework .core .ResolvableType ;
39
40
import org .springframework .core .codec .AbstractDecoder ;
41
+ import org .springframework .core .codec .CodecException ;
40
42
import org .springframework .core .codec .DecodingException ;
41
43
import org .springframework .core .io .buffer .DataBuffer ;
42
44
import org .springframework .util .ClassUtils ;
@@ -92,15 +94,34 @@ public Flux<Object> decode(Publisher<DataBuffer> inputStream, ResolvableType ele
92
94
MimeType mimeType , Map <String , Object > hints ) {
93
95
94
96
Class <?> outputClass = elementType .getRawClass ();
95
- Flux <XMLEvent > xmlEventFlux =
96
- this .xmlEventDecoder .decode (inputStream , null , mimeType , hints );
97
+ Flux <XMLEvent > xmlEventFlux = this .xmlEventDecoder .decode (inputStream , null , mimeType , hints );
97
98
98
99
QName typeName = toQName (outputClass );
99
100
Flux <List <XMLEvent >> splitEvents = split (xmlEventFlux , typeName );
100
101
101
102
return splitEvents .map (events -> unmarshal (events , outputClass ));
102
103
}
103
104
105
+ private Object unmarshal (List <XMLEvent > events , Class <?> outputClass ) {
106
+ try {
107
+ Unmarshaller unmarshaller = this .jaxbContexts .createUnmarshaller (outputClass );
108
+ XMLEventReader eventReader = StaxUtils .createXMLEventReader (events );
109
+ if (outputClass .isAnnotationPresent (XmlRootElement .class )) {
110
+ return unmarshaller .unmarshal (eventReader );
111
+ }
112
+ else {
113
+ JAXBElement <?> jaxbElement = unmarshaller .unmarshal (eventReader , outputClass );
114
+ return jaxbElement .getValue ();
115
+ }
116
+ }
117
+ catch (UnmarshalException ex ) {
118
+ throw new DecodingException ("Could not unmarshal XML to " + outputClass , ex );
119
+ }
120
+ catch (JAXBException ex ) {
121
+ throw new CodecException ("Invalid JAXB configuration" , ex );
122
+ }
123
+ }
124
+
104
125
/**
105
126
* Returns the qualified name for the given class, according to the mapping rules
106
127
* in the JAXB specification.
@@ -120,17 +141,16 @@ else if (outputClass.isAnnotationPresent(XmlType.class)) {
120
141
namespaceUri = annotation .namespace ();
121
142
}
122
143
else {
123
- throw new IllegalArgumentException ("Outputclass [" + outputClass + "] is " +
124
- "neither annotated with @XmlRootElement nor @XmlType" );
144
+ throw new IllegalArgumentException ("Output class [" + outputClass . getName () +
145
+ "] is neither annotated with @XmlRootElement nor @XmlType" );
125
146
}
126
147
127
148
if (JAXB_DEFAULT_ANNOTATION_VALUE .equals (localPart )) {
128
149
localPart = ClassUtils .getShortNameAsProperty (outputClass );
129
150
}
130
151
if (JAXB_DEFAULT_ANNOTATION_VALUE .equals (namespaceUri )) {
131
152
Package outputClassPackage = outputClass .getPackage ();
132
- if (outputClassPackage != null &&
133
- outputClassPackage .isAnnotationPresent (XmlSchema .class )) {
153
+ if (outputClassPackage != null && outputClassPackage .isAnnotationPresent (XmlSchema .class )) {
134
154
XmlSchema annotation = outputClassPackage .getAnnotation (XmlSchema .class );
135
155
namespaceUri = annotation .namespace ();
136
156
}
@@ -142,21 +162,20 @@ else if (outputClass.isAnnotationPresent(XmlType.class)) {
142
162
}
143
163
144
164
/**
145
- * Split a flux of {@link XMLEvent}s into a flux of XMLEvent lists, one list for each
146
- * branch of the tree that starts with the given qualified name.
147
- * That is, given the XMLEvents shown
148
- * {@linkplain XmlEventDecoder here},
149
- * and the {@code desiredName} "{@code child}", this method
150
- * returns a flux of two lists, each of which containing the events of a particular
151
- * branch of the tree that starts with "{@code child}".
165
+ * Split a flux of {@link XMLEvent}s into a flux of XMLEvent lists, one list
166
+ * for each branch of the tree that starts with the given qualified name.
167
+ * That is, given the XMLEvents shown {@linkplain XmlEventDecoder here},
168
+ * and the {@code desiredName} "{@code child}", this method returns a flux
169
+ * of two lists, each of which containing the events of a particular branch
170
+ * of the tree that starts with "{@code child}".
152
171
* <ol>
153
- * <li>The first list, dealing with the first branch of the tree
172
+ * <li>The first list, dealing with the first branch of the tree:
154
173
* <ol>
155
174
* <li>{@link javax.xml.stream.events.StartElement} {@code child}</li>
156
175
* <li>{@link javax.xml.stream.events.Characters} {@code foo}</li>
157
176
* <li>{@link javax.xml.stream.events.EndElement} {@code child}</li>
158
177
* </ol>
159
- * <li>The second list, dealing with the second branch of the tree
178
+ * <li>The second list, dealing with the second branch of the tree:
160
179
* <ol>
161
180
* <li>{@link javax.xml.stream.events.StartElement} {@code child}</li>
162
181
* <li>{@link javax.xml.stream.events.Characters} {@code bar}</li>
@@ -166,57 +185,47 @@ else if (outputClass.isAnnotationPresent(XmlType.class)) {
166
185
* </ol>
167
186
*/
168
187
Flux <List <XMLEvent >> split (Flux <XMLEvent > xmlEventFlux , QName desiredName ) {
169
- return xmlEventFlux
170
- .flatMap (new Function <XMLEvent , Publisher <? extends List <XMLEvent >>>() {
171
-
172
- private List <XMLEvent > events = null ;
173
-
174
- private int elementDepth = 0 ;
175
-
176
- private int barrier = Integer .MAX_VALUE ;
177
-
178
- @ Override
179
- public Publisher <? extends List <XMLEvent >> apply (XMLEvent event ) {
180
- if (event .isStartElement ()) {
181
- if (this .barrier == Integer .MAX_VALUE ) {
182
- QName startElementName = event .asStartElement ().getName ();
183
- if (desiredName .equals (startElementName )) {
184
- this .events = new ArrayList <XMLEvent >();
185
- this .barrier = this .elementDepth ;
186
- }
187
- }
188
- this .elementDepth ++;
189
- }
190
- if (this .elementDepth > this .barrier ) {
191
- this .events .add (event );
192
- }
193
- if (event .isEndElement ()) {
194
- this .elementDepth --;
195
- if (this .elementDepth == this .barrier ) {
196
- this .barrier = Integer .MAX_VALUE ;
197
- return Mono .just (this .events );
198
- }
199
- }
200
- return Mono .empty ();
201
- }
202
- });
188
+ return xmlEventFlux .flatMap (new SplitFunction (desiredName ));
203
189
}
204
190
205
- private Object unmarshal (List <XMLEvent > events , Class <?> outputClass ) {
206
- try {
207
- Unmarshaller unmarshaller = this .jaxbContexts .createUnmarshaller (outputClass );
208
- XMLEventReader eventReader = StaxUtils .createXMLEventReader (events );
209
- if (outputClass .isAnnotationPresent (XmlRootElement .class )) {
210
- return unmarshaller .unmarshal (eventReader );
191
+
192
+ private static class SplitFunction implements Function <XMLEvent , Publisher <? extends List <XMLEvent >>> {
193
+
194
+ private final QName desiredName ;
195
+
196
+ private List <XMLEvent > events ;
197
+
198
+ private int elementDepth = 0 ;
199
+
200
+ private int barrier = Integer .MAX_VALUE ;
201
+
202
+ public SplitFunction (QName desiredName ) {
203
+ this .desiredName = desiredName ;
204
+ }
205
+
206
+ @ Override
207
+ public Publisher <? extends List <XMLEvent >> apply (XMLEvent event ) {
208
+ if (event .isStartElement ()) {
209
+ if (this .barrier == Integer .MAX_VALUE ) {
210
+ QName startElementName = event .asStartElement ().getName ();
211
+ if (this .desiredName .equals (startElementName )) {
212
+ this .events = new ArrayList <>();
213
+ this .barrier = this .elementDepth ;
214
+ }
215
+ }
216
+ this .elementDepth ++;
211
217
}
212
- else {
213
- JAXBElement <?> jaxbElement =
214
- unmarshaller .unmarshal (eventReader , outputClass );
215
- return jaxbElement .getValue ();
218
+ if (this .elementDepth > this .barrier ) {
219
+ this .events .add (event );
216
220
}
217
- }
218
- catch (JAXBException ex ) {
219
- throw new DecodingException (ex .getMessage (), ex );
221
+ if (event .isEndElement ()) {
222
+ this .elementDepth --;
223
+ if (this .elementDepth == this .barrier ) {
224
+ this .barrier = Integer .MAX_VALUE ;
225
+ return Mono .just (this .events );
226
+ }
227
+ }
228
+ return Mono .empty ();
220
229
}
221
230
}
222
231
0 commit comments