001/*
002 * Copyright 2002-2017 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;
018
019import java.io.IOException;
020import java.io.OutputStream;
021import java.lang.reflect.Type;
022
023import org.springframework.http.HttpHeaders;
024import org.springframework.http.HttpOutputMessage;
025import org.springframework.http.MediaType;
026import org.springframework.http.StreamingHttpOutputMessage;
027
028/**
029 * Abstract base class for most {@link GenericHttpMessageConverter} implementations.
030 *
031 * @author Sebastien Deleuze
032 * @author Juergen Hoeller
033 * @since 4.2
034 */
035public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T>
036                implements GenericHttpMessageConverter<T> {
037
038        /**
039         * Construct an {@code AbstractGenericHttpMessageConverter} with no supported media types.
040         * @see #setSupportedMediaTypes
041         */
042        protected AbstractGenericHttpMessageConverter() {
043        }
044
045        /**
046         * Construct an {@code AbstractGenericHttpMessageConverter} with one supported media type.
047         * @param supportedMediaType the supported media type
048         */
049        protected AbstractGenericHttpMessageConverter(MediaType supportedMediaType) {
050                super(supportedMediaType);
051        }
052
053        /**
054         * Construct an {@code AbstractGenericHttpMessageConverter} with multiple supported media type.
055         * @param supportedMediaTypes the supported media types
056         */
057        protected AbstractGenericHttpMessageConverter(MediaType... supportedMediaTypes) {
058                super(supportedMediaTypes);
059        }
060
061
062        @Override
063        protected boolean supports(Class<?> clazz) {
064                return true;
065        }
066
067        @Override
068        public boolean canRead(Type type, Class<?> contextClass, MediaType mediaType) {
069                return (type instanceof Class ? canRead((Class<?>) type, mediaType) : canRead(mediaType));
070        }
071
072        @Override
073        public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
074                return canWrite(clazz, mediaType);
075        }
076
077        /**
078         * This implementation sets the default headers by calling {@link #addDefaultHeaders},
079         * and then calls {@link #writeInternal}.
080         */
081        public final void write(final T t, final Type type, MediaType contentType, HttpOutputMessage outputMessage)
082                        throws IOException, HttpMessageNotWritableException {
083
084                final HttpHeaders headers = outputMessage.getHeaders();
085                addDefaultHeaders(headers, t, contentType);
086
087                if (outputMessage instanceof StreamingHttpOutputMessage) {
088                        StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
089                        streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
090                                @Override
091                                public void writeTo(final OutputStream outputStream) throws IOException {
092                                        writeInternal(t, type, new HttpOutputMessage() {
093                                                @Override
094                                                public OutputStream getBody() throws IOException {
095                                                        return outputStream;
096                                                }
097                                                @Override
098                                                public HttpHeaders getHeaders() {
099                                                        return headers;
100                                                }
101                                        });
102                                }
103                        });
104                }
105                else {
106                        writeInternal(t, type, outputMessage);
107                        outputMessage.getBody().flush();
108                }
109        }
110
111        @Override
112        protected void writeInternal(T t, HttpOutputMessage outputMessage)
113                        throws IOException, HttpMessageNotWritableException {
114
115                writeInternal(t, null, outputMessage);
116        }
117
118        /**
119         * Abstract template method that writes the actual body. Invoked from {@link #write}.
120         * @param t the object to write to the output message
121         * @param type the type of object to write (may be {@code null})
122         * @param outputMessage the HTTP output message to write to
123         * @throws IOException in case of I/O errors
124         * @throws HttpMessageNotWritableException in case of conversion errors
125         */
126        protected abstract void writeInternal(T t, Type type, HttpOutputMessage outputMessage)
127                        throws IOException, HttpMessageNotWritableException;
128
129}