001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.http.converter.xml; 018 019import java.io.IOException; 020import javax.xml.transform.Result; 021import javax.xml.transform.Source; 022import javax.xml.transform.TransformerException; 023import javax.xml.transform.TransformerFactory; 024import javax.xml.transform.stream.StreamResult; 025import javax.xml.transform.stream.StreamSource; 026 027import org.springframework.http.HttpHeaders; 028import org.springframework.http.HttpInputMessage; 029import org.springframework.http.HttpOutputMessage; 030import org.springframework.http.MediaType; 031import org.springframework.http.converter.AbstractHttpMessageConverter; 032import org.springframework.http.converter.HttpMessageNotReadableException; 033import org.springframework.http.converter.HttpMessageNotWritableException; 034 035/** 036 * Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters} 037 * that convert from/to XML. 038 * 039 * <p>By default, subclasses of this converter support {@code text/xml}, {@code application/xml}, and {@code 040 * application/*-xml}. This can be overridden by setting the {@link #setSupportedMediaTypes(java.util.List) 041 * supportedMediaTypes} property. 042 * 043 * @author Arjen Poutsma 044 * @since 3.0 045 */ 046public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMessageConverter<T> { 047 048 private final TransformerFactory transformerFactory = TransformerFactory.newInstance(); 049 050 051 /** 052 * Protected constructor that sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} 053 * to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}. 054 */ 055 protected AbstractXmlHttpMessageConverter() { 056 super(MediaType.APPLICATION_XML, MediaType.TEXT_XML, new MediaType("application", "*+xml")); 057 } 058 059 060 @Override 061 public final T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage) 062 throws IOException, HttpMessageNotReadableException { 063 064 return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody())); 065 } 066 067 @Override 068 protected final void writeInternal(T t, HttpOutputMessage outputMessage) 069 throws IOException, HttpMessageNotWritableException { 070 071 writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody())); 072 } 073 074 /** 075 * Transforms the given {@code Source} to the {@code Result}. 076 * @param source the source to transform from 077 * @param result the result to transform to 078 * @throws TransformerException in case of transformation errors 079 */ 080 protected void transform(Source source, Result result) throws TransformerException { 081 this.transformerFactory.newTransformer().transform(source, result); 082 } 083 084 085 /** 086 * Abstract template method called from {@link #read(Class, HttpInputMessage)}. 087 * @param clazz the type of object to return 088 * @param headers the HTTP input headers 089 * @param source the HTTP input body 090 * @return the converted object 091 * @throws IOException in case of I/O errors 092 * @throws HttpMessageNotReadableException in case of conversion errors 093 */ 094 protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source) 095 throws IOException, HttpMessageNotReadableException; 096 097 /** 098 * Abstract template method called from {@link #writeInternal(Object, HttpOutputMessage)}. 099 * @param t the object to write to the output message 100 * @param headers the HTTP output headers 101 * @param result the HTTP output body 102 * @throws IOException in case of I/O errors 103 * @throws HttpMessageNotWritableException in case of conversion errors 104 */ 105 protected abstract void writeToResult(T t, HttpHeaders headers, Result result) 106 throws IOException, HttpMessageNotWritableException; 107 108}