Browse Source
This commit adds canWrite() and write() methods to the GenericHttpMessageConverter interface. These are type aware variants of the methods available in HttpMessageConverter, in order to keep parametrized type information when serializing objects. AbstractMessageConverterMethodProcessor now calls those type aware methods when the message converter implements GenericHttpMessageConverter. AbstractJackson2HttpMessageConverter and GsonHttpMessageConverter uses these new methods to make @ResponseBody method return type available for type resolution instead of just letting the JSON serializer trying to guess the type to use from the object to serialize. Issue: SPR-12811pull/825/head
12 changed files with 442 additions and 76 deletions
@ -0,0 +1,118 @@
@@ -0,0 +1,118 @@
|
||||
/* |
||||
* Copyright 2002-2015 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.http.converter; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.lang.reflect.Type; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpOutputMessage; |
||||
import org.springframework.http.MediaType; |
||||
import org.springframework.http.StreamingHttpOutputMessage; |
||||
|
||||
/** |
||||
* Abstract base class for most {@link GenericHttpMessageConverter} implementations. |
||||
* |
||||
* @author Sebastien Deleuze |
||||
* @since 4.2 |
||||
*/ |
||||
public abstract class AbstractGenericHttpMessageConverter<T> extends AbstractHttpMessageConverter<T> |
||||
implements GenericHttpMessageConverter<T> { |
||||
|
||||
/** |
||||
* Construct an {@code AbstractGenericHttpMessageConverter} with no supported media types. |
||||
* @see #setSupportedMediaTypes |
||||
*/ |
||||
protected AbstractGenericHttpMessageConverter() { |
||||
} |
||||
|
||||
/** |
||||
* Construct an {@code AbstractGenericHttpMessageConverter} with one supported media type. |
||||
* @param supportedMediaType the supported media type |
||||
*/ |
||||
protected AbstractGenericHttpMessageConverter(MediaType supportedMediaType) { |
||||
super(supportedMediaType); |
||||
} |
||||
|
||||
/** |
||||
* Construct an {@code AbstractGenericHttpMessageConverter} with multiple supported media type. |
||||
* @param supportedMediaTypes the supported media types |
||||
*/ |
||||
protected AbstractGenericHttpMessageConverter(MediaType... supportedMediaTypes) { |
||||
super(supportedMediaTypes); |
||||
} |
||||
|
||||
@Override |
||||
public boolean canWrite(Class<?> contextClass, MediaType mediaType) { |
||||
return canWrite(null, contextClass, mediaType); |
||||
} |
||||
|
||||
/** |
||||
* This implementation sets the default headers by calling {@link #addDefaultHeaders}, |
||||
* and then calls {@link #writeInternal}. |
||||
*/ |
||||
public final void write(final T t, final Type type, MediaType contentType, HttpOutputMessage outputMessage) |
||||
throws IOException, HttpMessageNotWritableException { |
||||
|
||||
final HttpHeaders headers = outputMessage.getHeaders(); |
||||
addDefaultHeaders(headers, t, contentType); |
||||
|
||||
if (outputMessage instanceof StreamingHttpOutputMessage) { |
||||
StreamingHttpOutputMessage streamingOutputMessage = |
||||
(StreamingHttpOutputMessage) outputMessage; |
||||
streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() { |
||||
@Override |
||||
public void writeTo(final OutputStream outputStream) throws IOException { |
||||
writeInternal(t, type, new HttpOutputMessage() { |
||||
@Override |
||||
public OutputStream getBody() throws IOException { |
||||
return outputStream; |
||||
} |
||||
@Override |
||||
public HttpHeaders getHeaders() { |
||||
return headers; |
||||
} |
||||
}); |
||||
} |
||||
}); |
||||
} |
||||
else { |
||||
writeInternal(t, type, outputMessage); |
||||
outputMessage.getBody().flush(); |
||||
} |
||||
} |
||||
|
||||
|
||||
@Override |
||||
protected void writeInternal(T t, HttpOutputMessage outputMessage) |
||||
throws IOException, HttpMessageNotWritableException { |
||||
writeInternal(t, null, outputMessage); |
||||
} |
||||
|
||||
/** |
||||
* Abstract template method that writes the actual body. Invoked from {@link #write}. |
||||
* @param t the object to write to the output message |
||||
* @param type the type of object to write, can be {@code null} if not specified. |
||||
* @param outputMessage the HTTP output message to write to |
||||
* @throws IOException in case of I/O errors |
||||
* @throws HttpMessageNotWritableException in case of conversion errors |
||||
*/ |
||||
protected abstract void writeInternal(T t, Type type, HttpOutputMessage outputMessage) |
||||
throws IOException, HttpMessageNotWritableException; |
||||
|
||||
} |
||||
Loading…
Reference in new issue