Merge pull request #685 from garyrussell/INT-2837a

* INT-2837a:
  INT-2837 Fix Accept Hdr for Serializable Response
This commit is contained in:
Mark Fisher
2012-11-30 13:58:49 -05:00
10 changed files with 179 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2010 the original author or authors.
* Copyright 2002-2012 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.
@@ -31,8 +31,9 @@ import org.springframework.util.FileCopyUtils;
/**
* An {@link HttpMessageConverter} implementation for {@link Serializable} instances.
*
*
* @author Mark Fisher
* @author Gary Russell
* @since 2.0
*/
public class SerializingHttpMessageConverter extends AbstractHttpMessageConverter<Serializable> {
@@ -51,11 +52,6 @@ public class SerializingHttpMessageConverter extends AbstractHttpMessageConverte
return Serializable.class.isAssignableFrom(clazz);
}
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return (Serializable.class.isAssignableFrom(clazz) && APPLICATION_JAVA_SERIALIZED_OBJECT.includes(mediaType));
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return (Serializable.class.isAssignableFrom(clazz) && APPLICATION_JAVA_SERIALIZED_OBJECT.includes(mediaType));

View File

@@ -54,7 +54,6 @@ import org.springframework.integration.context.OrderlyShutdownCapable;
import org.springframework.integration.expression.ExpressionUtils;
import org.springframework.integration.gateway.MessagingGatewaySupport;
import org.springframework.integration.http.converter.MultipartAwareFormHttpMessageConverter;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.http.multipart.MultipartHttpInputMessage;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
@@ -147,7 +146,6 @@ public abstract class HttpRequestHandlingEndpointSupport extends MessagingGatewa
public HttpRequestHandlingEndpointSupport(boolean expectReply) {
this.expectReply = expectReply;
this.messageConverters.add(new MultipartAwareFormHttpMessageConverter());
this.messageConverters.add(new SerializingHttpMessageConverter());
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());

View File

@@ -51,7 +51,6 @@ import org.springframework.integration.MessageHandlingException;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.mapping.HeaderMapper;
import org.springframework.integration.support.MessageBuilder;
@@ -152,7 +151,6 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
public HttpRequestExecutingMessageHandler(Expression uriExpression, RestTemplate restTemplate) {
Assert.notNull(uriExpression, "URI Expression is required");
this.restTemplate = (restTemplate == null ? new RestTemplate() : restTemplate);
this.restTemplate.getMessageConverters().add(0, new SerializingHttpMessageConverter());
this.uriExpression = uriExpression;
StandardEvaluationContext sec = new StandardEvaluationContext();
sec.addPropertyAccessor(new MapAccessor());

View File

@@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
@@ -40,16 +41,19 @@ import org.springframework.expression.Expression;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.history.MessageHistory;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.http.inbound.HttpRequestHandlingController;
import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.MultiValueMap;
@@ -60,6 +64,7 @@ import org.springframework.util.MultiValueMap;
* @author Gary Russell
* @author Gunnar Hillert
* @author Artem Bilan
* @author Gary Russell
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@@ -239,7 +244,7 @@ public class HttpInboundChannelAdapterParserTests {
assertEquals("test", message.getPayload());
}
@Test
@Test @DirtiesContext
public void postRequestWithSerializedObjectContentOk() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("POST");
@@ -253,6 +258,11 @@ public class HttpInboundChannelAdapterParserTests {
request.addHeader("Content-Type", "application/x-java-serialized-object");
MockHttpServletResponse response = new MockHttpServletResponse();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
postOnlyAdapter.setMessageConverters(converters);
postOnlyAdapter.handleRequest(request, response);
assertEquals(HttpServletResponse.SC_OK, response.getStatus());
Message<?> message = requests.receive(0);

View File

@@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import static org.springframework.integration.test.util.TestUtils.getPropertyValue;
import static org.springframework.integration.test.util.TestUtils.handlerExpecting;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -40,17 +41,20 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.http.HttpHeaders;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.integration.Message;
import org.springframework.integration.MessageHeaders;
import org.springframework.integration.core.MessagingTemplate;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.core.SubscribableChannel;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.http.inbound.HttpRequestHandlingController;
import org.springframework.integration.http.inbound.HttpRequestHandlingMessagingGateway;
import org.springframework.integration.http.support.DefaultHttpHeaderMapper;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -103,7 +107,7 @@ public class HttpInboundGatewayParserTests {
assertEquals(Long.valueOf(4567), TestUtils.getPropertyValue(messagingTemplate, "receiveTimeout"));
}
@Test(timeout=1000)
@Test(timeout=1000) @DirtiesContext
public void checkFlow() throws Exception {
requests.subscribe(handlerExpecting(any(Message.class)));
MockHttpServletRequest request = new MockHttpServletRequest();
@@ -112,6 +116,10 @@ public class HttpInboundGatewayParserTests {
request.setParameter("foo", "bar");
MockHttpServletResponse response = new MockHttpServletResponse();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
gateway.setMessageConverters(converters);
gateway.handleRequest(request, response);
assertThat(response.getStatus(), is(HttpServletResponse.SC_OK));

View File

@@ -3,9 +3,11 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-http="http://www.springframework.org/schema/integration/http"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd">
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<int-http:outbound-gateway url="http://localhost:51235/testApps/outboundResponse"
@@ -27,6 +29,17 @@
reply-channel="replyChannel"
expected-response-type-expression="payload"/>
<int-http:outbound-gateway url="http://localhost:51235/testApps/outboundResponse"
request-channel="resTypeExpressionSetSerializationChannel"
reply-channel="replyChannel"
message-converters="stringAndSerializingConverters"
expected-response-type-expression="payload"/>
<util:list id="stringAndSerializingConverters">
<bean class="org.springframework.integration.http.converter.SerializingHttpMessageConverter" />
<bean class="org.springframework.http.converter.StringHttpMessageConverter" />
</util:list>
<int:channel id="replyChannel">
<int:queue/>
</int:channel>

View File

@@ -26,11 +26,9 @@ import java.net.InetSocketAddress;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.http.MediaType;
@@ -39,6 +37,7 @@ import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.message.GenericMessage;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.sun.net.httpserver.HttpExchange;
@@ -48,6 +47,7 @@ import com.sun.net.httpserver.HttpServer;
/**
* @author Oleg Zhurakousky
* @author Artem Bilan
* @author Gary Russell
* @since 2.2
*
* <p/>
@@ -76,6 +76,9 @@ public class OutboundResponseTypeTests {
@Autowired
private MessageChannel resTypeExpressionSetChannel;
@Autowired
private MessageChannel resTypeExpressionSetSerializationChannel;
@BeforeClass
public static void createServer() throws Exception {
httpHandler = new MyHandler();
@@ -115,7 +118,7 @@ public class OutboundResponseTypeTests {
@Test
public void testWithResponseTypeExpressionSetAsClass() throws Exception {
this.resTypeExpressionSetChannel.send(new GenericMessage<Class<?>>(String.class));
this.resTypeExpressionSetSerializationChannel.send(new GenericMessage<Class<?>>(String.class));
Message<?> message = this.replyChannel.receive(5000);
assertNotNull(message);
assertTrue(message.getPayload() instanceof String);

View File

@@ -39,6 +39,7 @@ import org.springframework.integration.Message;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
@@ -198,6 +199,11 @@ public class HttpRequestHandlingMessagingGatewayTests {
HttpRequestHandlingMessagingGateway gateway = new HttpRequestHandlingMessagingGateway(false);
gateway.setRequestPayloadType(TestBean.class);
gateway.setRequestChannel(channel);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
gateway.setMessageConverters(converters);
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test");
//request.setContentType("application/x-java-serialized-object"); //Works in Spring 3.1.2.RELEASE but NOT in 3.0.7.RELEASE

View File

@@ -21,9 +21,13 @@ import static junit.framework.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -47,14 +51,21 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.ConverterRegistry;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.QueueChannel;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.http.converter.SerializingHttpMessageConverter;
import org.springframework.integration.message.GenericMessage;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.util.MultiValueMap;
@@ -735,6 +746,96 @@ public class HttpRequestExecutingMessageHandlerTests {
assertSame(mockConversionService, TestUtils.getPropertyValue(handler, "conversionService"));
}
@Test
public void acceptHeaderForSerializableResponse() throws Exception {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://www.springsource.org/spring-integration");
handler.setHttpMethod(HttpMethod.GET);
handler.setExpectedResponseType(Foo.class);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
handler.setMessageConverters(converters);
handler.afterPropertiesSet();
RestTemplate restTemplate = TestUtils.getPropertyValue(handler, "restTemplate", RestTemplate.class);
HttpHeaders requestHeaders = setUpMocksToCaptureSentHeaders(restTemplate);
Message<?> message = MessageBuilder.withPayload("foo").build();
Exception exception = null;
try {
handler.handleMessage(message);
}
catch (Exception e) {
exception = e;
}
assertTrue(requestHeaders.getAccept() != null);
assertTrue(requestHeaders.getAccept().size() > 0);
assertEquals("404 null", exception.getCause().getMessage());
List<MediaType> accept = requestHeaders.getAccept();
assertTrue(accept != null && accept.size() > 0);
assertEquals("application", accept.get(0).getType());
assertEquals("x-java-serialized-object", accept.get(0).getSubtype());
}
@Test
public void acceptHeaderForSerializableResponseMessageExchange() throws Exception {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://www.springsource.org/spring-integration");
handler.setHttpMethod(HttpMethod.GET);
handler.setExtractPayload(false);
handler.setExpectedResponseType(GenericMessage.class);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new SerializingHttpMessageConverter());
handler.setMessageConverters(converters);
handler.afterPropertiesSet();
RestTemplate restTemplate = TestUtils.getPropertyValue(handler, "restTemplate", RestTemplate.class);
HttpHeaders requestHeaders = setUpMocksToCaptureSentHeaders(restTemplate);
Message<?> message = MessageBuilder.withPayload("foo").build();
Exception exception = null;
try {
handler.handleMessage(message);
}
catch (Exception e) {
exception = e;
}
assertTrue(requestHeaders.getAccept() != null);
assertTrue(requestHeaders.getAccept().size() > 0);
assertEquals("404 null", exception.getCause().getMessage());
List<MediaType> accept = requestHeaders.getAccept();
assertTrue(accept != null && accept.size() > 0);
assertEquals("application", accept.get(0).getType());
assertEquals("x-java-serialized-object", accept.get(0).getSubtype());
}
private HttpHeaders setUpMocksToCaptureSentHeaders(RestTemplate restTemplate) throws IOException {
HttpHeaders headers = new HttpHeaders();
ClientHttpRequestFactory requestFactory = mock(ClientHttpRequestFactory.class);
ClientHttpRequest clientRequest = mock(ClientHttpRequest.class);
when(clientRequest.getHeaders()).thenReturn(headers);
when(requestFactory.createRequest(any(URI.class), any(HttpMethod.class)))
.thenReturn(clientRequest );
ClientHttpResponse response = mock(ClientHttpResponse.class);
when(response.getStatusCode()).thenReturn(HttpStatus.NOT_FOUND);
HttpHeaders responseHeaders = new HttpHeaders();
when(response.getHeaders()).thenReturn(responseHeaders);
when(clientRequest.execute()).thenReturn(response);
restTemplate.setRequestFactory(requestFactory);
return headers;
}
public static class City{
private final String name;
public City(String name){
@@ -770,4 +871,9 @@ public class HttpRequestExecutingMessageHandlerTests {
}
}
private static class Foo implements Serializable {
private static final long serialVersionUID = 1L;
}
}

View File

@@ -190,6 +190,28 @@
by default. For more information see <xref linkend="transformer"/>.
</para>
</section>
<section id="httpChanges">
<title>Http Support</title>
<para>
Java serialization over http is no longer enabled by default. Previously, when
setting a <code>expected-response-type</code> to a <code>Serializable</code>
object, the <code>Accept</code> header was not properly set up. The
<classname>SerializingHttpMessageConverter</classname> has now been updated
to set the Accept header to <code>application/x-java-serialized-object</code>.
However, because this could cause incompatibility with existing applications,
it was decided to no longer automatically add this converter to the http endpoints.
</para>
<para>
If you wish to use Java serialization, you will need to add the
<classname>SerializingHttpMessageConverter</classname> to the appropriate
endpoints, using the <code>message-converters</code> attribute, when using
XML configuration, or using the <code>setMessageConverters()</code> method.
</para>
<para>
Alternatively, you may wish to consider using JSON instead which is enabled
by simply having <code>Jackson</code> on the classpath.
</para>
</section>
</section>
<section id="2.2-new-components">