1717package org .springframework .http .converter .xml ;
1818
1919import java .io .ByteArrayInputStream ;
20- import java .io .ByteArrayOutputStream ;
2120import java .io .IOException ;
2221import java .io .InputStream ;
2322import java .io .OutputStream ;
23+ import java .util .HashSet ;
24+ import java .util .Set ;
2425import javax .xml .parsers .DocumentBuilder ;
2526import javax .xml .parsers .DocumentBuilderFactory ;
2627import javax .xml .parsers .ParserConfigurationException ;
27- import javax .xml .stream .XMLInputFactory ;
28- import javax .xml .stream .XMLStreamException ;
29- import javax .xml .stream .XMLStreamReader ;
3028import javax .xml .transform .Result ;
3129import javax .xml .transform .Source ;
3230import javax .xml .transform .TransformerException ;
3331import javax .xml .transform .TransformerFactory ;
34- import javax .xml .transform .dom .DOMResult ;
3532import javax .xml .transform .dom .DOMSource ;
3633import javax .xml .transform .sax .SAXSource ;
3734import javax .xml .transform .stream .StreamResult ;
4340import org .xml .sax .XMLReader ;
4441import org .xml .sax .helpers .XMLReaderFactory ;
4542
46- import org .springframework .http .HttpHeaders ;
4743import org .springframework .http .HttpInputMessage ;
4844import org .springframework .http .HttpOutputMessage ;
4945import org .springframework .http .MediaType ;
5248import org .springframework .http .converter .HttpMessageNotReadableException ;
5349import org .springframework .http .converter .HttpMessageNotWritableException ;
5450import org .springframework .util .StreamUtils ;
55- import org .springframework .util .xml .StaxUtils ;
5651
5752/**
5853 * Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
6358 */
6459public class SourceHttpMessageConverter <T extends Source > extends AbstractHttpMessageConverter <T > {
6560
66- private final TransformerFactory transformerFactory = TransformerFactory . newInstance ( );
61+ private static final Set < Class <?>> SUPPORTED_CLASSES = new HashSet < Class <?>>( 4 );
6762
68- private boolean processExternalEntities = false ;
63+ static {
64+ SUPPORTED_CLASSES .add (DOMSource .class );
65+ SUPPORTED_CLASSES .add (SAXSource .class );
66+ SUPPORTED_CLASSES .add (StreamSource .class );
67+ SUPPORTED_CLASSES .add (Source .class );
68+ }
69+
70+
71+ private final TransformerFactory transformerFactory = TransformerFactory .newInstance ();
72+
73+ private boolean processExternalEntities = false ;
6974
70- /**
71- * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes}
72- * to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}.
73- */
74- public SourceHttpMessageConverter () {
75- super (MediaType .APPLICATION_XML , MediaType .TEXT_XML , new MediaType ("application" , "*+xml" ));
76- }
7775
76+ /**
77+ * Sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes}
78+ * to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}.
79+ */
80+ public SourceHttpMessageConverter () {
81+ super (MediaType .APPLICATION_XML , MediaType .TEXT_XML , new MediaType ("application" , "*+xml" ));
82+ }
83+
84+
85+ /**
86+ * Indicates whether external XML entities are processed when converting to a Source.
87+ * <p>Default is {@code false}, meaning that external entities are not resolved.
88+ */
89+ public void setProcessExternalEntities (boolean processExternalEntities ) {
90+ this .processExternalEntities = processExternalEntities ;
91+ }
7892
79- /**
80- * Indicates whether external XML entities are processed when converting
81- * to a Source.
82- * <p>Default is {@code false}, meaning that external entities are not resolved.
83- */
84- public void setProcessExternalEntities (boolean processExternalEntities ) {
85- this .processExternalEntities = processExternalEntities ;
86- }
8793
88- @ Override
94+ @ Override
8995 public boolean supports (Class <?> clazz ) {
90- return DOMSource .class .equals (clazz ) || SAXSource .class .equals (clazz )
91- || StreamSource .class .equals (clazz ) || Source .class .equals (clazz );
96+ return SUPPORTED_CLASSES .contains (clazz );
9297 }
9398
94- @ Override
95- protected T readInternal (Class <? extends T > clazz , HttpInputMessage inputMessage )
96- throws IOException , HttpMessageNotReadableException {
97-
98- InputStream body = inputMessage .getBody ();
99- if (DOMSource .class .equals (clazz )) {
100- return (T ) readDOMSource (body );
101- }
102- else if (StaxUtils .isStaxSourceClass (clazz )) {
103- return (T ) readStAXSource (body );
104- }
105- else if (SAXSource .class .equals (clazz )) {
106- return (T ) readSAXSource (body );
107- }
108- else if (StreamSource .class .equals (clazz ) || Source .class .equals (clazz )) {
109- return (T ) readStreamSource (body );
110- }
111- else {
112- throw new HttpMessageConversionException ("Could not read class [" + clazz +
113- "]. Only DOMSource, SAXSource, and StreamSource are supported." );
114- }
115- }
116-
117- private DOMSource readDOMSource (InputStream body ) throws IOException {
118- try {
119- DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory .newInstance ();
120- documentBuilderFactory .setNamespaceAware (true );
121- documentBuilderFactory .setFeature ("http://xml.org/sax/features/external-general-entities" , processExternalEntities );
122- DocumentBuilder documentBuilder = documentBuilderFactory .newDocumentBuilder ();
123- Document document = documentBuilder .parse (body );
124- return new DOMSource (document );
125- }
126- catch (ParserConfigurationException ex ) {
127- throw new HttpMessageNotReadableException ("Could not set feature: " + ex .getMessage (), ex );
128- }
129- catch (SAXException ex ) {
130- throw new HttpMessageNotReadableException ("Could not parse document: " + ex .getMessage (), ex );
131- }
132- }
133-
134- private SAXSource readSAXSource (InputStream body ) throws IOException {
135- try {
136- XMLReader reader = XMLReaderFactory .createXMLReader ();
137- reader .setFeature ("http://xml.org/sax/features/external-general-entities" , processExternalEntities );
138- byte [] bytes = StreamUtils .copyToByteArray (body );
139- return new SAXSource (reader , new InputSource (new ByteArrayInputStream (bytes )));
140- }
141- catch (SAXException ex ) {
142- throw new HttpMessageNotReadableException ("Could not parse document: " + ex .getMessage (), ex );
143- }
144- }
145-
146- private Source readStAXSource (InputStream body ) {
147- try {
148- XMLInputFactory inputFactory = XMLInputFactory .newFactory ();
149- inputFactory .setProperty ("javax.xml.stream.isSupportingExternalEntities" , processExternalEntities );
150- XMLStreamReader streamReader = inputFactory .createXMLStreamReader (body );
151- return StaxUtils .createStaxSource (streamReader );
152- }
153- catch (XMLStreamException ex ) {
154- throw new HttpMessageNotReadableException ("Could not parse document: " + ex .getMessage (), ex );
155- }
156- }
157-
158- private StreamSource readStreamSource (InputStream body ) throws IOException {
159- byte [] bytes = StreamUtils .copyToByteArray (body );
160- return new StreamSource (new ByteArrayInputStream (bytes ));
161- }
99+ @ Override
100+ @ SuppressWarnings ("unchecked" )
101+ protected T readInternal (Class <? extends T > clazz , HttpInputMessage inputMessage )
102+ throws IOException , HttpMessageNotReadableException {
103+
104+ InputStream body = inputMessage .getBody ();
105+ if (DOMSource .class .equals (clazz )) {
106+ return (T ) readDOMSource (body );
107+ }
108+ else if (SAXSource .class .equals (clazz )) {
109+ return (T ) readSAXSource (body );
110+ }
111+ else if (StreamSource .class .equals (clazz ) || Source .class .equals (clazz )) {
112+ return (T ) readStreamSource (body );
113+ }
114+ else {
115+ throw new HttpMessageConversionException ("Could not read class [" + clazz +
116+ "]. Only DOMSource, SAXSource, and StreamSource are supported." );
117+ }
118+ }
119+
120+ private DOMSource readDOMSource (InputStream body ) throws IOException {
121+ try {
122+ DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory .newInstance ();
123+ documentBuilderFactory .setNamespaceAware (true );
124+ documentBuilderFactory .setFeature (
125+ "http://xml.org/sax/features/external-general-entities" , this .processExternalEntities );
126+ DocumentBuilder documentBuilder = documentBuilderFactory .newDocumentBuilder ();
127+ Document document = documentBuilder .parse (body );
128+ return new DOMSource (document );
129+ }
130+ catch (ParserConfigurationException ex ) {
131+ throw new HttpMessageNotReadableException ("Could not set feature: " + ex .getMessage (), ex );
132+ }
133+ catch (SAXException ex ) {
134+ throw new HttpMessageNotReadableException ("Could not parse document: " + ex .getMessage (), ex );
135+ }
136+ }
137+
138+ private SAXSource readSAXSource (InputStream body ) throws IOException {
139+ try {
140+ XMLReader reader = XMLReaderFactory .createXMLReader ();
141+ reader .setFeature (
142+ "http://xml.org/sax/features/external-general-entities" , this .processExternalEntities );
143+ byte [] bytes = StreamUtils .copyToByteArray (body );
144+ return new SAXSource (reader , new InputSource (new ByteArrayInputStream (bytes )));
145+ }
146+ catch (SAXException ex ) {
147+ throw new HttpMessageNotReadableException ("Could not parse document: " + ex .getMessage (), ex );
148+ }
149+ }
150+
151+ private StreamSource readStreamSource (InputStream body ) throws IOException {
152+ byte [] bytes = StreamUtils .copyToByteArray (body );
153+ return new StreamSource (new ByteArrayInputStream (bytes ));
154+ }
162155
163156 @ Override
164157 protected Long getContentLength (T t , MediaType contentType ) {
@@ -175,40 +168,40 @@ protected Long getContentLength(T t, MediaType contentType) {
175168 return null ;
176169 }
177170
178- @ Override
179- protected void writeInternal (T t , HttpOutputMessage outputMessage )
180- throws IOException , HttpMessageNotWritableException {
171+ @ Override
172+ protected void writeInternal (T t , HttpOutputMessage outputMessage )
173+ throws IOException , HttpMessageNotWritableException {
181174 try {
182- Result result = new StreamResult (outputMessage .getBody ());
175+ Result result = new StreamResult (outputMessage .getBody ());
183176 transform (t , result );
184177 }
185178 catch (TransformerException ex ) {
186179 throw new HttpMessageNotWritableException ("Could not transform [" + t + "] to output message" , ex );
187180 }
188181 }
189182
190- private void transform (Source source , Result result ) throws TransformerException {
191- this .transformerFactory .newTransformer ().transform (source , result );
192- }
183+ private void transform (Source source , Result result ) throws TransformerException {
184+ this .transformerFactory .newTransformer ().transform (source , result );
185+ }
193186
194187
195- private static class CountingOutputStream extends OutputStream {
188+ private static class CountingOutputStream extends OutputStream {
196189
197- private long count = 0 ;
190+ long count = 0 ;
198191
199192 @ Override
200193 public void write (int b ) throws IOException {
201- count ++;
194+ this . count ++;
202195 }
203196
204197 @ Override
205198 public void write (byte [] b ) throws IOException {
206- count += b .length ;
199+ this . count += b .length ;
207200 }
208201
209202 @ Override
210203 public void write (byte [] b , int off , int len ) throws IOException {
211- count += len ;
204+ this . count += len ;
212205 }
213206 }
214207
0 commit comments