Make @ResponseBody method return type available for message converters
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-12811
This commit is contained in:
parent
04a7ed5f91
commit
31a5434ea4
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
@ -160,34 +160,15 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
|
|||
}
|
||||
|
||||
/**
|
||||
* This implementation delegates to {@link #getDefaultContentType(Object)} if a content
|
||||
* type was not provided, calls {@link #getContentLength}, and sets the corresponding headers
|
||||
* on the output message. It then calls {@link #writeInternal}.
|
||||
* This implementation sets the default headers by calling {@link #addDefaultHeaders},
|
||||
* and then calls {@link #writeInternal}.
|
||||
*/
|
||||
@Override
|
||||
public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
final HttpHeaders headers = outputMessage.getHeaders();
|
||||
if (headers.getContentType() == null) {
|
||||
MediaType contentTypeToUse = contentType;
|
||||
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
|
||||
contentTypeToUse = getDefaultContentType(t);
|
||||
}
|
||||
else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
|
||||
MediaType type = getDefaultContentType(t);
|
||||
contentTypeToUse = (type != null ? type : contentTypeToUse);
|
||||
}
|
||||
if (contentTypeToUse != null) {
|
||||
headers.setContentType(contentTypeToUse);
|
||||
}
|
||||
}
|
||||
if (headers.getContentLength() == -1) {
|
||||
Long contentLength = getContentLength(t, headers.getContentType());
|
||||
if (contentLength != null) {
|
||||
headers.setContentLength(contentLength);
|
||||
}
|
||||
}
|
||||
addDefaultHeaders(headers, t, contentType);
|
||||
|
||||
if (outputMessage instanceof StreamingHttpOutputMessage) {
|
||||
StreamingHttpOutputMessage streamingOutputMessage =
|
||||
|
|
@ -214,6 +195,36 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default headers to the output message.
|
||||
* <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content
|
||||
* type was not provided, calls {@link #getContentLength}, and sets the corresponding headers
|
||||
* @since 4.2
|
||||
*/
|
||||
protected void addDefaultHeaders(final HttpHeaders headers, final T t, MediaType contentType)
|
||||
throws IOException{
|
||||
|
||||
if (headers.getContentType() == null) {
|
||||
MediaType contentTypeToUse = contentType;
|
||||
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
|
||||
contentTypeToUse = getDefaultContentType(t);
|
||||
}
|
||||
else if (MediaType.APPLICATION_OCTET_STREAM.equals(contentType)) {
|
||||
MediaType mediaType = getDefaultContentType(t);
|
||||
contentTypeToUse = (mediaType != null ? mediaType : contentTypeToUse);
|
||||
}
|
||||
if (contentTypeToUse != null) {
|
||||
headers.setContentType(contentTypeToUse);
|
||||
}
|
||||
}
|
||||
if (headers.getContentLength() == -1) {
|
||||
Long contentLength = getContentLength(t, headers.getContentType());
|
||||
if (contentLength != null) {
|
||||
headers.setContentLength(contentLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default content type for the given type. Called when {@link #write}
|
||||
* is invoked without a specified content type parameter.
|
||||
|
|
|
|||
|
|
@ -20,14 +20,17 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Type;
|
||||
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
|
||||
/**
|
||||
* A specialization of {@link HttpMessageConverter} that can convert an HTTP
|
||||
* request into a target object of a specified generic type.
|
||||
* A specialization of {@link HttpMessageConverter} that can convert an HTTP request
|
||||
* into a target object of a specified generic type and a source object of a specified
|
||||
* generic type into an HTTP response.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Sebastien Deleuze
|
||||
* @since 3.2
|
||||
* @see org.springframework.core.ParameterizedTypeReference
|
||||
*/
|
||||
|
|
@ -59,4 +62,34 @@ public interface GenericHttpMessageConverter<T> extends HttpMessageConverter<T>
|
|||
T read(Type type, Class<?> contextClass, HttpInputMessage inputMessage)
|
||||
throws IOException, HttpMessageNotReadableException;
|
||||
|
||||
/**
|
||||
* Indicates whether the given class can be written by this converter.
|
||||
* @param type the type to test for writability, can be {@code null} if not specified.
|
||||
* @param contextClass the class to test for writability
|
||||
* @param mediaType the media type to write, can be {@code null} if not specified.
|
||||
* Typically the value of an {@code Accept} header.
|
||||
* @return {@code true} if writable; {@code false} otherwise
|
||||
* @since 4.2
|
||||
*/
|
||||
boolean canWrite(Type type, Class<?> contextClass, MediaType mediaType);
|
||||
|
||||
/**
|
||||
* Write an given object to the given output message.
|
||||
* @param t the object to write to the output message. The type of this object must have previously been
|
||||
* passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
|
||||
* @param type the type of object to write. This type must have previously
|
||||
* been passed to the {@link #canWrite canWrite} method of this interface,
|
||||
* which must have returned {@code true}. Can be {@code null} if not specified.
|
||||
* @param contentType the content type to use when writing. May be {@code null} to indicate that the
|
||||
* default content type of the converter must be used. If not {@code null}, this media type must have
|
||||
* previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
|
||||
* returned {@code true}.
|
||||
* @param outputMessage the message to write to
|
||||
* @throws IOException in case of I/O errors
|
||||
* @throws HttpMessageNotWritableException in case of conversion errors
|
||||
* @since 4.2
|
||||
*/
|
||||
void write(T t, Type type, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,19 +27,21 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter;
|
||||
import com.fasterxml.jackson.databind.JavaType;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.databind.ser.FilterProvider;
|
||||
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.TypeUtils;
|
||||
|
||||
/**
|
||||
* Abstract base class for Jackson based and content type independent
|
||||
|
|
@ -54,7 +56,7 @@ import org.springframework.util.ClassUtils;
|
|||
* @author Sebastien Deleuze
|
||||
* @since 4.1
|
||||
*/
|
||||
public abstract class AbstractJackson2HttpMessageConverter extends AbstractHttpMessageConverter<Object>
|
||||
public abstract class AbstractJackson2HttpMessageConverter extends AbstractGenericHttpMessageConverter<Object>
|
||||
implements GenericHttpMessageConverter<Object> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
|
@ -158,7 +160,7 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractHttpM
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
||||
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
|
||||
if (!jackson23Available || !logger.isWarnEnabled()) {
|
||||
return (this.objectMapper.canSerialize(clazz) && canWrite(mediaType));
|
||||
}
|
||||
|
|
@ -218,31 +220,43 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractHttpM
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
|
||||
@SuppressWarnings("deprecation")
|
||||
protected void writeInternal(Object object, Type type, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
|
||||
JsonGenerator generator = this.objectMapper.getFactory().createGenerator(outputMessage.getBody(), encoding);
|
||||
try {
|
||||
writePrefix(generator, object);
|
||||
|
||||
Class<?> serializationView = null;
|
||||
FilterProvider filters = null;
|
||||
Object value = object;
|
||||
if (value instanceof MappingJacksonValue) {
|
||||
JavaType javaType = null;
|
||||
if (type != null) {
|
||||
javaType = getJavaType(type, null);
|
||||
}
|
||||
if (object instanceof MappingJacksonValue) {
|
||||
MappingJacksonValue container = (MappingJacksonValue) object;
|
||||
value = container.getValue();
|
||||
serializationView = container.getSerializationView();
|
||||
filters = container.getFilters();
|
||||
}
|
||||
ObjectWriter objectWriter;
|
||||
if (serializationView != null) {
|
||||
this.objectMapper.writerWithView(serializationView).writeValue(generator, value);
|
||||
objectWriter = this.objectMapper.writerWithView(serializationView);
|
||||
}
|
||||
else if (filters != null) {
|
||||
this.objectMapper.writer(filters).writeValue(generator, value);
|
||||
objectWriter = this.objectMapper.writer(filters);
|
||||
}
|
||||
else {
|
||||
this.objectMapper.writeValue(generator, value);
|
||||
objectWriter = this.objectMapper.writer();
|
||||
}
|
||||
if (javaType != null && value != null && TypeUtils.isAssignable(type, value.getClass())) {
|
||||
objectWriter = objectWriter.withType(javaType);
|
||||
}
|
||||
objectWriter.writeValue(generator, value);
|
||||
|
||||
writeSuffix(generator, object);
|
||||
generator.flush();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -32,7 +32,7 @@ import org.springframework.http.HttpHeaders;
|
|||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
|
|
@ -54,7 +54,7 @@ import org.springframework.util.Assert;
|
|||
* @see #setGson
|
||||
* @see #setSupportedMediaTypes
|
||||
*/
|
||||
public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Object>
|
||||
public class GsonHttpMessageConverter extends AbstractGenericHttpMessageConverter<Object>
|
||||
implements GenericHttpMessageConverter<Object> {
|
||||
|
||||
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
|
||||
|
|
@ -125,7 +125,7 @@ public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Objec
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
||||
public boolean canWrite(Type type, Class<?> clazz, MediaType mediaType) {
|
||||
return canWrite(mediaType);
|
||||
}
|
||||
|
||||
|
|
@ -191,7 +191,7 @@ public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Objec
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void writeInternal(Object o, HttpOutputMessage outputMessage)
|
||||
protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
|
||||
Charset charset = getCharset(outputMessage.getHeaders());
|
||||
|
|
@ -200,7 +200,12 @@ public class GsonHttpMessageConverter extends AbstractHttpMessageConverter<Objec
|
|||
if (this.jsonPrefix != null) {
|
||||
writer.append(this.jsonPrefix);
|
||||
}
|
||||
this.gson.toJson(o, writer);
|
||||
if (type != null) {
|
||||
this.gson.toJson(o, type, writer);
|
||||
}
|
||||
else {
|
||||
this.gson.toJson(o, writer);
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
catch (JsonIOException ex) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -40,10 +40,12 @@ import javax.xml.transform.Source;
|
|||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConversionException;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
|
||||
/**
|
||||
* An {@code HttpMessageConverter} that can read XML collections using JAXB2.
|
||||
|
|
@ -112,6 +114,15 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns {@code false} since Jaxb2CollectionHttpMessageConverter
|
||||
* does not convert collections to XML.
|
||||
*/
|
||||
@Override
|
||||
public boolean canWrite(Type type, Class<?> contextClass, MediaType mediaType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean supports(Class<?> clazz) {
|
||||
// should not be called, since we override canRead/Write
|
||||
|
|
@ -216,6 +227,12 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
|
|||
return event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(T t, Type type, MediaType contentType, HttpOutputMessage outputMessage)
|
||||
throws IOException, HttpMessageNotWritableException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -209,7 +209,7 @@ public class GsonHttpMessageConverterTests {
|
|||
public void prefixJson() throws Exception {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.converter.setPrefixJson(true);
|
||||
this.converter.writeInternal("foo", outputMessage);
|
||||
this.converter.writeInternal("foo", null, outputMessage);
|
||||
assertEquals(")]}', \"foo\"", outputMessage.getBodyAsString(UTF8));
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +217,7 @@ public class GsonHttpMessageConverterTests {
|
|||
public void prefixJsonCustom() throws Exception {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.converter.setJsonPrefix(")))");
|
||||
this.converter.writeInternal("foo", outputMessage);
|
||||
this.converter.writeInternal("foo", null, outputMessage);
|
||||
assertEquals(")))\"foo\"", outputMessage.getBodyAsString(UTF8));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
bean.setName("Jason");
|
||||
|
||||
this.converter.setPrettyPrint(true);
|
||||
this.converter.writeInternal(bean, outputMessage);
|
||||
this.converter.writeInternal(bean, null, outputMessage);
|
||||
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
|
||||
|
||||
assertEquals("{" + NEWLINE_SYSTEM_PROPERTY + " \"name\" : \"Jason\"" + NEWLINE_SYSTEM_PROPERTY + "}", result);
|
||||
|
|
@ -231,7 +231,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
public void prefixJson() throws Exception {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.converter.setPrefixJson(true);
|
||||
this.converter.writeInternal("foo", outputMessage);
|
||||
this.converter.writeInternal("foo", null, outputMessage);
|
||||
|
||||
assertEquals(")]}', \"foo\"", outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
|
@ -240,7 +240,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
public void prefixJsonCustom() throws Exception {
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.converter.setJsonPrefix(")))");
|
||||
this.converter.writeInternal("foo", outputMessage);
|
||||
this.converter.writeInternal("foo", null, outputMessage);
|
||||
|
||||
assertEquals(")))\"foo\"", outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
|
@ -255,7 +255,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
|
||||
MappingJacksonValue jacksonValue = new MappingJacksonValue(bean);
|
||||
jacksonValue.setSerializationView(MyJacksonView1.class);
|
||||
this.converter.writeInternal(jacksonValue, outputMessage);
|
||||
this.converter.writeInternal(jacksonValue, null, outputMessage);
|
||||
|
||||
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
|
||||
assertThat(result, containsString("\"withView1\":\"with\""));
|
||||
|
|
@ -274,7 +274,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
FilterProvider filters = new SimpleFilterProvider().addFilter("myJacksonFilter",
|
||||
SimpleBeanPropertyFilter.serializeAllExcept("property2"));
|
||||
jacksonValue.setFilters(filters);
|
||||
this.converter.writeInternal(jacksonValue, outputMessage);
|
||||
this.converter.writeInternal(jacksonValue, null, outputMessage);
|
||||
|
||||
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
|
||||
assertThat(result, containsString("\"property1\":\"value\""));
|
||||
|
|
@ -288,7 +288,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
jacksonValue.setJsonpFunction("callback");
|
||||
|
||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||
this.converter.writeInternal(jacksonValue, outputMessage);
|
||||
this.converter.writeInternal(jacksonValue, null, outputMessage);
|
||||
|
||||
assertEquals("callback(\"foo\");", outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||
}
|
||||
|
|
@ -304,7 +304,7 @@ public class MappingJackson2HttpMessageConverterTests {
|
|||
MappingJacksonValue jacksonValue = new MappingJacksonValue(bean);
|
||||
jacksonValue.setSerializationView(MyJacksonView1.class);
|
||||
jacksonValue.setJsonpFunction("callback");
|
||||
this.converter.writeInternal(jacksonValue, outputMessage);
|
||||
this.converter.writeInternal(jacksonValue, null, outputMessage);
|
||||
|
||||
String result = outputMessage.getBodyAsString(Charset.forName("UTF-8"));
|
||||
assertThat(result, startsWith("callback("));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -29,8 +29,8 @@ import org.springframework.http.HttpOutputMessage;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.MockHttpInputMessage;
|
||||
import org.springframework.http.MockHttpOutputMessage;
|
||||
import org.springframework.http.converter.AbstractHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
|
||||
import org.springframework.http.converter.json.MappingJacksonValue;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
|
|
@ -142,7 +142,7 @@ public class MappingJackson2XmlHttpMessageConverterTests {
|
|||
private void writeInternal(Object object, HttpOutputMessage outputMessage)
|
||||
throws NoSuchMethodException, InvocationTargetException,
|
||||
IllegalAccessException {
|
||||
Method method = AbstractJackson2HttpMessageConverter.class.getDeclaredMethod(
|
||||
Method method = AbstractHttpMessageConverter.class.getDeclaredMethod(
|
||||
"writeInternal", Object.class, HttpOutputMessage.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(this.converter, object, outputMessage);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
|
|
@ -27,8 +28,10 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.GenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.server.ServletServerHttpRequest;
|
||||
import org.springframework.http.server.ServletServerHttpResponse;
|
||||
|
|
@ -158,7 +161,20 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
|
|||
(Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(),
|
||||
inputMessage, outputMessage);
|
||||
if (returnValue != null) {
|
||||
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
|
||||
if (messageConverter instanceof GenericHttpMessageConverter) {
|
||||
Type type;
|
||||
if (HttpEntity.class.isAssignableFrom(returnType.getParameterType())) {
|
||||
returnType.increaseNestingLevel();
|
||||
type = returnType.getNestedGenericParameterType();
|
||||
}
|
||||
else {
|
||||
type = returnType.getGenericParameterType();
|
||||
}
|
||||
((GenericHttpMessageConverter<T>) messageConverter).write(returnValue, type, selectedMediaType, outputMessage);
|
||||
}
|
||||
else {
|
||||
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Written [" + returnValue + "] as \"" +
|
||||
selectedMediaType + "\" using [" + messageConverter + "]");
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.springframework.web.servlet.mvc.method.annotation;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
|
@ -36,6 +38,8 @@ import org.springframework.mock.web.test.MockHttpServletRequest;
|
|||
import org.springframework.mock.web.test.MockHttpServletResponse;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.ServletWebRequest;
|
||||
|
|
@ -64,6 +68,8 @@ public class HttpEntityMethodProcessorTests {
|
|||
|
||||
private ServletWebRequest webRequest;
|
||||
|
||||
private MockHttpServletResponse servletResponse;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
|
@ -74,7 +80,8 @@ public class HttpEntityMethodProcessorTests {
|
|||
mavContainer = new ModelAndViewContainer();
|
||||
binderFactory = new ValidatingBinderFactory();
|
||||
servletRequest = new MockHttpServletRequest();
|
||||
webRequest = new ServletWebRequest(servletRequest, new MockHttpServletResponse());
|
||||
servletResponse = new MockHttpServletResponse();
|
||||
webRequest = new ServletWebRequest(servletRequest, servletResponse);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -153,6 +160,24 @@ public class HttpEntityMethodProcessorTests {
|
|||
assertEquals("Jad", result.getBody().getName());
|
||||
}
|
||||
|
||||
@Test // SPR-12811
|
||||
public void jacksonTypeInfoList() throws Exception {
|
||||
Method method = JacksonController.class.getMethod("handleList");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
converters.add(new MappingJackson2HttpMessageConverter());
|
||||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(converters);
|
||||
|
||||
Object returnValue = new JacksonController().handleList();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
assertTrue(content.contains("\"type\":\"foo\""));
|
||||
assertTrue(content.contains("\"type\":\"bar\""));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void handle(HttpEntity<List<SimpleBean>> arg1, HttpEntity<SimpleBean> arg2) {
|
||||
|
|
@ -217,4 +242,59 @@ public class HttpEntityMethodProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
|
||||
private static class ParentClass {
|
||||
|
||||
private String parentProperty;
|
||||
|
||||
public ParentClass() {
|
||||
}
|
||||
|
||||
public ParentClass(String parentProperty) {
|
||||
this.parentProperty = parentProperty;
|
||||
}
|
||||
|
||||
public String getParentProperty() {
|
||||
return parentProperty;
|
||||
}
|
||||
|
||||
public void setParentProperty(String parentProperty) {
|
||||
this.parentProperty = parentProperty;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("foo")
|
||||
private static class Foo extends ParentClass {
|
||||
|
||||
public Foo() {
|
||||
}
|
||||
|
||||
public Foo(String parentProperty) {
|
||||
super(parentProperty);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("bar")
|
||||
private static class Bar extends ParentClass {
|
||||
|
||||
public Bar() {
|
||||
}
|
||||
|
||||
public Bar(String parentProperty) {
|
||||
super(parentProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JacksonController {
|
||||
|
||||
@RequestMapping
|
||||
@ResponseBody
|
||||
public HttpEntity<List<ParentClass>> handleList() {
|
||||
List<ParentClass> list = new ArrayList<>();
|
||||
list.add(new Foo("foo"));
|
||||
list.add(new Bar("bar"));
|
||||
return new HttpEntity<>(list);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeName;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
|
@ -349,8 +351,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
|
||||
@Test
|
||||
public void jacksonJsonViewWithResponseBodyAndJsonMessageConverter() throws Exception {
|
||||
Method method = JacksonViewController.class.getMethod("handleResponseBody");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleResponseBody");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -359,7 +361,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
|
||||
converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice()));
|
||||
|
||||
Object returnValue = new JacksonViewController().handleResponseBody();
|
||||
Object returnValue = new JacksonController().handleResponseBody();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
|
|
@ -370,8 +372,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
|
||||
@Test
|
||||
public void jacksonJsonViewWithResponseEntityAndJsonMessageConverter() throws Exception {
|
||||
Method method = JacksonViewController.class.getMethod("handleResponseEntity");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleResponseEntity");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -380,7 +382,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
|
||||
converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice()));
|
||||
|
||||
Object returnValue = new JacksonViewController().handleResponseEntity();
|
||||
Object returnValue = new JacksonController().handleResponseEntity();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
|
|
@ -391,8 +393,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
|
||||
@Test // SPR-12149
|
||||
public void jacksonJsonViewWithResponseBodyAndXmlMessageConverter() throws Exception {
|
||||
Method method = JacksonViewController.class.getMethod("handleResponseBody");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleResponseBody");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -401,7 +403,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
|
||||
converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice()));
|
||||
|
||||
Object returnValue = new JacksonViewController().handleResponseBody();
|
||||
Object returnValue = new JacksonController().handleResponseBody();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
|
|
@ -412,8 +414,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
|
||||
@Test // SPR-12149
|
||||
public void jacksonJsonViewWithResponseEntityAndXmlMessageConverter() throws Exception {
|
||||
Method method = JacksonViewController.class.getMethod("handleResponseEntity");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleResponseEntity");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -422,7 +424,7 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
|
||||
converters, null, Collections.singletonList(new JsonViewResponseBodyAdvice()));
|
||||
|
||||
Object returnValue = new JacksonViewController().handleResponseEntity();
|
||||
Object returnValue = new JacksonController().handleResponseEntity();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
|
|
@ -437,8 +439,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
this.servletRequest.setContent(content.getBytes("UTF-8"));
|
||||
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
Method method = JacksonViewController.class.getMethod("handleRequestBody", JacksonViewBean.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleRequestBody", JacksonViewBean.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -463,8 +465,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
this.servletRequest.setContent(content.getBytes("UTF-8"));
|
||||
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
Method method = JacksonViewController.class.getMethod("handleHttpEntity", HttpEntity.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleHttpEntity", HttpEntity.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -490,8 +492,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
this.servletRequest.setContent(content.getBytes("UTF-8"));
|
||||
this.servletRequest.setContentType(MediaType.APPLICATION_XML_VALUE);
|
||||
|
||||
Method method = JacksonViewController.class.getMethod("handleRequestBody", JacksonViewBean.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleRequestBody", JacksonViewBean.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -516,8 +518,8 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
this.servletRequest.setContent(content.getBytes("UTF-8"));
|
||||
this.servletRequest.setContentType(MediaType.APPLICATION_XML_VALUE);
|
||||
|
||||
Method method = JacksonViewController.class.getMethod("handleHttpEntity", HttpEntity.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonViewController(), method);
|
||||
Method method = JacksonController.class.getMethod("handleHttpEntity", HttpEntity.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodParameter = handlerMethod.getMethodParameters()[0];
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
|
|
@ -537,6 +539,24 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
assertNull(result.getBody().getWithoutView());
|
||||
}
|
||||
|
||||
@Test // SPR-12811
|
||||
public void jacksonTypeInfoList() throws Exception {
|
||||
Method method = JacksonController.class.getMethod("handleList");
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method);
|
||||
MethodParameter methodReturnType = handlerMethod.getReturnType();
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
|
||||
converters.add(new MappingJackson2HttpMessageConverter());
|
||||
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
|
||||
|
||||
Object returnValue = new JacksonController().handleList();
|
||||
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
|
||||
|
||||
String content = this.servletResponse.getContentAsString();
|
||||
assertTrue(content.contains("\"type\":\"foo\""));
|
||||
assertTrue(content.contains("\"type\":\"bar\""));
|
||||
}
|
||||
|
||||
|
||||
String handle(
|
||||
@RequestBody List<SimpleBean> list,
|
||||
|
|
@ -670,7 +690,50 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
}
|
||||
}
|
||||
|
||||
private static class JacksonViewController {
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
|
||||
public static class ParentClass {
|
||||
|
||||
private String parentProperty;
|
||||
|
||||
public ParentClass() {
|
||||
}
|
||||
|
||||
public ParentClass(String parentProperty) {
|
||||
this.parentProperty = parentProperty;
|
||||
}
|
||||
|
||||
public String getParentProperty() {
|
||||
return parentProperty;
|
||||
}
|
||||
|
||||
public void setParentProperty(String parentProperty) {
|
||||
this.parentProperty = parentProperty;
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("foo")
|
||||
public static class Foo extends ParentClass {
|
||||
|
||||
public Foo() {
|
||||
}
|
||||
|
||||
public Foo(String parentProperty) {
|
||||
super(parentProperty);
|
||||
}
|
||||
}
|
||||
|
||||
@JsonTypeName("bar")
|
||||
public static class Bar extends ParentClass {
|
||||
|
||||
public Bar() {
|
||||
}
|
||||
|
||||
public Bar(String parentProperty) {
|
||||
super(parentProperty);
|
||||
}
|
||||
}
|
||||
|
||||
private static class JacksonController {
|
||||
|
||||
@RequestMapping
|
||||
@ResponseBody
|
||||
|
|
@ -706,8 +769,17 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
public JacksonViewBean handleHttpEntity(@JsonView(MyJacksonView1.class) HttpEntity<JacksonViewBean> entity) {
|
||||
return entity.getBody();
|
||||
}
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@ResponseBody
|
||||
public List<ParentClass> handleList() {
|
||||
List<ParentClass> list = new ArrayList<>();
|
||||
list.add(new Foo("foo"));
|
||||
list.add(new Bar("bar"));
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
private static class EmptyRequestBodyAdvice implements RequestBodyAdvice {
|
||||
|
||||
@Override
|
||||
|
|
|
|||
Loading…
Reference in New Issue