HttpEntityMethodProcessor supports custom HttpEntity subclasses again

Issue: SPR-12242
This commit is contained in:
Juergen Hoeller 2014-09-24 17:56:07 +02:00
parent 5b1cbf0306
commit 281b243b88
3 changed files with 53 additions and 36 deletions

View File

@ -75,8 +75,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
@Override @Override
public boolean supportsReturnType(MethodParameter returnType) { public boolean supportsReturnType(MethodParameter returnType) {
return HttpEntity.class.equals(returnType.getParameterType()) || return HttpEntity.class.isAssignableFrom(returnType.getParameterType()) &&
ResponseEntity.class.equals(returnType.getParameterType()); !RequestEntity.class.isAssignableFrom(returnType.getParameterType());
} }
@Override @Override
@ -94,7 +94,6 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
} }
else { else {
return new HttpEntity<Object>(body, inputMessage.getHeaders()); return new HttpEntity<Object>(body, inputMessage.getHeaders());
} }
} }
@ -152,4 +151,5 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
return ResolvableType.forMethodParameter(returnType, type).resolve(Object.class); return ResolvableType.forMethodParameter(returnType, type).resolve(Object.class);
} }
} }
} }

View File

@ -20,11 +20,11 @@ import java.lang.reflect.Method;
import java.net.URI; import java.net.URI;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@ -41,7 +41,6 @@ import org.springframework.mock.web.test.MockHttpServletResponse;
import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException; import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
@ -66,21 +65,22 @@ public class HttpEntityMethodProcessorMockTests {
private HttpMessageConverter<String> messageConverter; private HttpMessageConverter<String> messageConverter;
private MethodParameter paramHttpEntity; private MethodParameter paramHttpEntity;
private MethodParameter paramRequestEntity;
private MethodParameter paramResponseEntity; private MethodParameter paramResponseEntity;
private MethodParameter paramInt; private MethodParameter paramInt;
private MethodParameter returnTypeResponseEntity; private MethodParameter returnTypeResponseEntity;
private MethodParameter returnTypeHttpEntity;
private MethodParameter returnTypeInt;
private MethodParameter paramRequestEntity;
private MethodParameter returnTypeResponseEntityProduces; private MethodParameter returnTypeResponseEntityProduces;
private MethodParameter returnTypeHttpEntity;
private MethodParameter returnTypeHttpEntitySubclass;
private MethodParameter returnTypeInt;
private ModelAndViewContainer mavContainer; private ModelAndViewContainer mavContainer;
private ServletWebRequest webRequest; private MockHttpServletRequest servletRequest;
private MockHttpServletResponse servletResponse; private MockHttpServletResponse servletResponse;
private MockHttpServletRequest servletRequest; private ServletWebRequest webRequest;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@ -92,27 +92,24 @@ public class HttpEntityMethodProcessorMockTests {
processor = new HttpEntityMethodProcessor(Collections.<HttpMessageConverter<?>>singletonList(messageConverter)); processor = new HttpEntityMethodProcessor(Collections.<HttpMessageConverter<?>>singletonList(messageConverter));
reset(messageConverter); reset(messageConverter);
Method handle1 = getClass().getMethod("handle1", HttpEntity.class, ResponseEntity.class, Integer.TYPE, RequestEntity.class); Method handle1 = getClass().getMethod("handle1", HttpEntity.class, ResponseEntity.class, Integer.TYPE, RequestEntity.class);
paramHttpEntity = new MethodParameter(handle1, 0); paramHttpEntity = new MethodParameter(handle1, 0);
paramRequestEntity = new MethodParameter(handle1, 3);
paramResponseEntity = new MethodParameter(handle1, 1); paramResponseEntity = new MethodParameter(handle1, 1);
paramInt = new MethodParameter(handle1, 2); paramInt = new MethodParameter(handle1, 2);
paramRequestEntity = new MethodParameter(handle1, 3);
returnTypeResponseEntity = new MethodParameter(handle1, -1); returnTypeResponseEntity = new MethodParameter(handle1, -1);
returnTypeResponseEntityProduces = new MethodParameter(getClass().getMethod("handle4"), -1);
returnTypeHttpEntity = new MethodParameter(getClass().getMethod("handle2", HttpEntity.class), -1); returnTypeHttpEntity = new MethodParameter(getClass().getMethod("handle2", HttpEntity.class), -1);
returnTypeHttpEntitySubclass = new MethodParameter(getClass().getMethod("handle2x", HttpEntity.class), -1);
returnTypeInt = new MethodParameter(getClass().getMethod("handle3"), -1); returnTypeInt = new MethodParameter(getClass().getMethod("handle3"), -1);
returnTypeResponseEntityProduces = new MethodParameter(getClass().getMethod("handle4"), -1);
mavContainer = new ModelAndViewContainer(); mavContainer = new ModelAndViewContainer();
servletRequest = new MockHttpServletRequest(); servletRequest = new MockHttpServletRequest();
servletResponse = new MockHttpServletResponse(); servletResponse = new MockHttpServletResponse();
webRequest = new ServletWebRequest(servletRequest, servletResponse); webRequest = new ServletWebRequest(servletRequest, servletResponse);
} }
@Test @Test
public void supportsParameter() { public void supportsParameter() {
assertTrue("HttpEntity parameter not supported", processor.supportsParameter(paramHttpEntity)); assertTrue("HttpEntity parameter not supported", processor.supportsParameter(paramHttpEntity));
@ -125,6 +122,7 @@ public class HttpEntityMethodProcessorMockTests {
public void supportsReturnType() { public void supportsReturnType() {
assertTrue("ResponseEntity return type not supported", processor.supportsReturnType(returnTypeResponseEntity)); assertTrue("ResponseEntity return type not supported", processor.supportsReturnType(returnTypeResponseEntity));
assertTrue("HttpEntity return type not supported", processor.supportsReturnType(returnTypeHttpEntity)); assertTrue("HttpEntity return type not supported", processor.supportsReturnType(returnTypeHttpEntity));
assertTrue("Custom HttpEntity subclass not supported", processor.supportsReturnType(returnTypeHttpEntitySubclass));
assertFalse("RequestEntity parameter supported", assertFalse("RequestEntity parameter supported",
processor.supportsReturnType(paramRequestEntity)); processor.supportsReturnType(paramRequestEntity));
assertFalse("non-ResponseBody return type supported", processor.supportsReturnType(returnTypeInt)); assertFalse("non-ResponseBody return type supported", processor.supportsReturnType(returnTypeInt));
@ -328,6 +326,10 @@ public class HttpEntityMethodProcessorMockTests {
return entity; return entity;
} }
public CustomHttpEntity handle2x(HttpEntity<?> entity) {
return new CustomHttpEntity();
}
public int handle3() { public int handle3() {
return 42; return 42;
} }
@ -338,4 +340,7 @@ public class HttpEntityMethodProcessorMockTests {
} }
public static class CustomHttpEntity extends HttpEntity<Object> {
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2014 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,8 +15,6 @@
*/ */
package org.springframework.web.servlet.mvc.method.annotation; package org.springframework.web.servlet.mvc.method.annotation;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.Serializable; import java.io.Serializable;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -25,6 +23,7 @@ import java.util.List;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
@ -40,6 +39,8 @@ import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
import static org.junit.Assert.*;
/** /**
* Test fixture with {@link HttpEntityMethodProcessor} delegating to * Test fixture with {@link HttpEntityMethodProcessor} delegating to
* actual {@link HttpMessageConverter} instances. * actual {@link HttpMessageConverter} instances.
@ -51,32 +52,31 @@ import org.springframework.web.method.support.ModelAndViewContainer;
public class HttpEntityMethodProcessorTests { public class HttpEntityMethodProcessorTests {
private MethodParameter paramList; private MethodParameter paramList;
private MethodParameter paramSimpleBean; private MethodParameter paramSimpleBean;
private ModelAndViewContainer mavContainer; private ModelAndViewContainer mavContainer;
private ServletWebRequest webRequest; private WebDataBinderFactory binderFactory;
private MockHttpServletResponse servletResponse;
private MockHttpServletRequest servletRequest; private MockHttpServletRequest servletRequest;
private WebDataBinderFactory binderFactory; private MockHttpServletResponse servletResponse;
private ServletWebRequest webRequest;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
Method method = getClass().getMethod("handle", HttpEntity.class, HttpEntity.class); Method method = getClass().getMethod("handle", HttpEntity.class, HttpEntity.class);
paramList = new MethodParameter(method, 0); paramList = new MethodParameter(method, 0);
paramSimpleBean = new MethodParameter(method, 1); paramSimpleBean = new MethodParameter(method, 1);
mavContainer = new ModelAndViewContainer(); mavContainer = new ModelAndViewContainer();
binderFactory = new ValidatingBinderFactory();
servletRequest = new MockHttpServletRequest(); servletRequest = new MockHttpServletRequest();
servletResponse = new MockHttpServletResponse(); servletResponse = new MockHttpServletResponse();
webRequest = new ServletWebRequest(servletRequest, servletResponse); webRequest = new ServletWebRequest(servletRequest, servletResponse);
binderFactory = new ValidatingBinderFactory();
} }
@Test @Test
@ -118,7 +118,6 @@ public class HttpEntityMethodProcessorTests {
@Test @Test
public void resolveArgumentTypeVariable() throws Exception { public void resolveArgumentTypeVariable() throws Exception {
Method method = MySimpleParameterizedController.class.getMethod("handleDto", HttpEntity.class); Method method = MySimpleParameterizedController.class.getMethod("handleDto", HttpEntity.class);
HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedController(), method); HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedController(), method);
MethodParameter methodParam = handlerMethod.getMethodParameters()[0]; MethodParameter methodParam = handlerMethod.getMethodParameters()[0];
@ -132,31 +131,42 @@ public class HttpEntityMethodProcessorTests {
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(converters); HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(converters);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
HttpEntity<SimpleBean> result = (HttpEntity<SimpleBean>) processor.resolveArgument(methodParam, mavContainer, webRequest, binderFactory); HttpEntity<SimpleBean> result = (HttpEntity<SimpleBean>)
processor.resolveArgument(methodParam, mavContainer, webRequest, binderFactory);
assertNotNull(result); assertNotNull(result);
assertEquals("Jad", result.getBody().getName()); assertEquals("Jad", result.getBody().getName());
} }
public void handle(HttpEntity<List<SimpleBean>> arg1, HttpEntity<SimpleBean> arg2) { public void handle(HttpEntity<List<SimpleBean>> arg1, HttpEntity<SimpleBean> arg2) {
} }
private static abstract class MyParameterizedController<DTO extends Identifiable> { private static abstract class MyParameterizedController<DTO extends Identifiable> {
@SuppressWarnings("unused")
public void handleDto(HttpEntity<DTO> dto) {} public void handleDto(HttpEntity<DTO> dto) {
}
}
private static class MySimpleParameterizedController extends MyParameterizedController<SimpleBean> {
} }
private static class MySimpleParameterizedController extends MyParameterizedController<SimpleBean> { }
private interface Identifiable extends Serializable { private interface Identifiable extends Serializable {
public Long getId(); public Long getId();
public void setId(Long id); public void setId(Long id);
} }
@SuppressWarnings({ "serial" }) @SuppressWarnings({ "serial" })
private static class SimpleBean implements Identifiable { private static class SimpleBean implements Identifiable {
private Long id; private Long id;
private String name; private String name;
@Override @Override
@ -179,9 +189,11 @@ public class HttpEntityMethodProcessorTests {
} }
} }
private final class ValidatingBinderFactory implements WebDataBinderFactory { private final class ValidatingBinderFactory implements WebDataBinderFactory {
@Override @Override
public WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception { public WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.afterPropertiesSet(); validator.afterPropertiesSet();
WebDataBinder dataBinder = new WebDataBinder(target, objectName); WebDataBinder dataBinder = new WebDataBinder(target, objectName);