INT-3516: Allow Optional<> in POJO Method Args
JIRA: https://jira.spring.io/browse/INT-3516 * Add `Optional<>` support for `@Header` in the `MessagingMethodInvokerHelper` * Add `Optional<>` test-case * Change `sourceCompatibility` for test to the Java 8 INT-3516: Revert SF version to 4.1.1 Add Docs on the matter Fix WS Tests; Revert StubJavaMailSender
This commit is contained in:
committed by
Gary Russell
parent
c84b16e2b5
commit
a3d8776b5c
12
build.gradle
12
build.gradle
@@ -63,8 +63,14 @@ subprojects { subproject ->
|
||||
}
|
||||
}
|
||||
|
||||
sourceCompatibility=1.6
|
||||
targetCompatibility=1.6
|
||||
compileJava {
|
||||
sourceCompatibility = 1.6
|
||||
targetCompatibility = 1.6
|
||||
}
|
||||
|
||||
compileTestJava {
|
||||
sourceCompatibility = 1.8
|
||||
}
|
||||
|
||||
ext {
|
||||
activeMqVersion = '5.10.0'
|
||||
@@ -118,7 +124,7 @@ subprojects { subproject ->
|
||||
springSecurityVersion = '3.2.5.RELEASE'
|
||||
springSocialTwitterVersion = '1.1.0.RELEASE'
|
||||
springRetryVersion = '1.1.1.RELEASE'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.1.2.BUILD-SNAPSHOT'
|
||||
springVersion = project.hasProperty('springVersion') ? project.springVersion : '4.1.1.RELEASE'
|
||||
springWsVersion = '2.2.0.RELEASE'
|
||||
xmlUnitVersion = '1.5'
|
||||
xstreamVersion = '1.4.7'
|
||||
|
||||
@@ -34,7 +34,7 @@ def customizePom(pom, gradleProject) {
|
||||
url = linkHomepage
|
||||
organization {
|
||||
name = 'SpringIO'
|
||||
url = 'https://spring.io'
|
||||
url = 'http://spring.io'
|
||||
}
|
||||
licenses {
|
||||
license {
|
||||
@@ -59,24 +59,24 @@ def customizePom(pom, gradleProject) {
|
||||
developer {
|
||||
id = 'garyrussell'
|
||||
name = 'Gary Russell'
|
||||
email = 'grussell@gopivotal.com'
|
||||
email = 'grussell@pivotal.io'
|
||||
roles = ["project lead"]
|
||||
}
|
||||
developer {
|
||||
id = 'markfisher'
|
||||
name = 'Mark Fisher'
|
||||
email = 'mfisher@gopivotal.com'
|
||||
email = 'mfisher@pivotal.io'
|
||||
roles = ["project founder and lead emeritus"]
|
||||
}
|
||||
developer {
|
||||
id = 'ghillert'
|
||||
name = 'Gunnar Hillert'
|
||||
email = 'ghillert@gopivotal.com'
|
||||
email = 'ghillert@pivotal.io'
|
||||
}
|
||||
developer {
|
||||
id = 'abilan'
|
||||
name = 'Artem Bilan'
|
||||
email = 'abilan@gopivotal.com'
|
||||
email = 'abilan@pivotal.io'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,7 +738,8 @@ public class MessagingMethodInvokerHelper<T> extends AbstractExpressionEvaluator
|
||||
+ "disabled or header name is not explicitly provided via @Header annotation.");
|
||||
String headerRetrievalExpression = "headers['" + headerName + "']";
|
||||
String fullHeaderExpression = headerRetrievalExpression + relativeExpression;
|
||||
String fallbackExpression = (annotationAttributes.getBoolean("required"))
|
||||
String fallbackExpression = (annotationAttributes.getBoolean("required")
|
||||
&& !methodParameter.getParameterType().getName().equals("java.util.Optional"))
|
||||
? "T(org.springframework.util.Assert).isTrue(false, 'required header not available: "
|
||||
+ headerName + "')"
|
||||
: "null";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2014 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,6 +32,7 @@ import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.integration.handler.LoggingHandler.Level;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
@@ -41,6 +42,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
* @author Artem Bilan
|
||||
* @since 2.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@@ -90,12 +92,12 @@ public class LoggingHandlerTests {
|
||||
expression = spy(expression);
|
||||
accessor.setPropertyValue("expression", expression);
|
||||
when(log.isInfoEnabled()).thenReturn(false);
|
||||
loggingHandler.handleMessage(new GenericMessage<String>("foo"));
|
||||
verify(expression, never()).getValue(Mockito.any(EvaluationContext.class), Mockito.any());
|
||||
loggingHandler.handleMessage(new GenericMessage<>("foo"));
|
||||
verify(expression, never()).getValue(Mockito.any(EvaluationContext.class), Mockito.any(Message.class));
|
||||
|
||||
when(log.isInfoEnabled()).thenReturn(true);
|
||||
loggingHandler.handleMessage(new GenericMessage<String>("foo"));
|
||||
verify(expression, times(1)).getValue(Mockito.any(EvaluationContext.class), Mockito.any());
|
||||
loggingHandler.handleMessage(new GenericMessage<>("foo"));
|
||||
verify(expression, times(1)).getValue(Mockito.any(EvaluationContext.class), Mockito.any(Message.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -106,12 +108,12 @@ public class LoggingHandlerTests {
|
||||
log = spy(log);
|
||||
accessor.setPropertyValue("messageLogger", log);
|
||||
when(log.isInfoEnabled()).thenReturn(true);
|
||||
loggingHandler.handleMessage(new GenericMessage<String>("foo"));
|
||||
loggingHandler.handleMessage(new GenericMessage<>("foo"));
|
||||
verify(log, times(1)).info(Mockito.anyString());
|
||||
verify(log, never()).warn(Mockito.anyString());
|
||||
|
||||
loggingHandler.setLevel(Level.WARN);
|
||||
loggingHandler.handleMessage(new GenericMessage<String>("foo"));
|
||||
loggingHandler.handleMessage(new GenericMessage<>("foo"));
|
||||
verify(log, times(1)).info(Mockito.anyString());
|
||||
verify(log, times(1)).warn(Mockito.anyString());
|
||||
}
|
||||
@@ -134,6 +136,7 @@ public class LoggingHandlerTests {
|
||||
public int getAge() {
|
||||
return this.age;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,7 +26,9 @@ import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -40,7 +42,6 @@ import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.expression.spel.SpelEvaluationException;
|
||||
import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.gateway.GatewayProxyFactoryBean;
|
||||
import org.springframework.integration.gateway.RequestReplyExchanger;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.util.MessagingMethodInvokerHelper;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandlingException;
|
||||
import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
|
||||
|
||||
@@ -58,6 +60,7 @@ import org.springframework.messaging.support.GenericMessage;
|
||||
* @author Dave Syer
|
||||
* @author Gary Russell
|
||||
* @author Gunnar Hillert
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class MethodInvokingMessageProcessorTests {
|
||||
@@ -517,6 +520,36 @@ public class MethodInvokingMessageProcessorTests {
|
||||
assertEquals("true", bean.lastArg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOptionalArgs() throws Exception {
|
||||
class Foo {
|
||||
|
||||
private final Map<String, Object> arguments = new LinkedHashMap<String, Object>();
|
||||
|
||||
public void optionalHeaders(Optional<String> foo, @Header(value="foo", required=false) String foo1,
|
||||
@Header(value="foo") Optional<String> foo2) {
|
||||
this.arguments.put("foo", (foo.isPresent() ? foo.get() : null));
|
||||
this.arguments.put("foo1", foo1);
|
||||
this.arguments.put("foo2", (foo2.isPresent() ? foo2.get() : null));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Foo targetObject = new Foo();
|
||||
|
||||
MessagingMethodInvokerHelper helper = new MessagingMethodInvokerHelper(targetObject, (String) null, false);
|
||||
|
||||
helper.process(new GenericMessage<>(Optional.empty()));
|
||||
assertNull(targetObject.arguments.get("foo"));
|
||||
assertNull(targetObject.arguments.get("foo1"));
|
||||
assertNull(targetObject.arguments.get("foo2"));
|
||||
|
||||
helper.process(MessageBuilder.withPayload("foo").setHeader("foo", "FOO").build());
|
||||
assertEquals("foo", targetObject.arguments.get("foo"));
|
||||
assertEquals("FOO", targetObject.arguments.get("foo1"));
|
||||
assertEquals("FOO", targetObject.arguments.get("foo2"));
|
||||
}
|
||||
|
||||
private static class ExceptionCauseMatcher extends TypeSafeMatcher<Exception> {
|
||||
private Throwable cause;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2007 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.
|
||||
@@ -30,11 +30,10 @@ import org.springframework.mail.javamail.MimeMessagePreparator;
|
||||
|
||||
/**
|
||||
* @author Marius Bogoevici
|
||||
* @author Gary Russell
|
||||
*/
|
||||
public class StubJavaMailSender implements JavaMailSender {
|
||||
|
||||
private final MimeMessage uniqueMessage;
|
||||
private MimeMessage uniqueMessage;
|
||||
|
||||
private final List<MimeMessage> sentMimeMessages = new ArrayList<MimeMessage>();
|
||||
|
||||
@@ -54,43 +53,35 @@ public class StubJavaMailSender implements JavaMailSender {
|
||||
return this.sentSimpleMailMessages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeMessage createMimeMessage() {
|
||||
return this.uniqueMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MimeMessage createMimeMessage(InputStream contentStream) throws MailException {
|
||||
return this.uniqueMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessage mimeMessage) throws MailException {
|
||||
this.sentMimeMessages.add(mimeMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessage... mimeMessages) throws MailException {
|
||||
public void send(MimeMessage[] mimeMessages) throws MailException {
|
||||
this.sentMimeMessages.addAll(Arrays.asList(mimeMessages));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessagePreparator mimeMessagePreparator) throws MailException {
|
||||
throw new UnsupportedOperationException("MimeMessagePreparator not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(MimeMessagePreparator... mimeMessagePreparators) throws MailException {
|
||||
public void send(MimeMessagePreparator[] mimeMessagePreparators) throws MailException {
|
||||
throw new UnsupportedOperationException("MimeMessagePreparator not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(SimpleMailMessage simpleMessage) throws MailException {
|
||||
this.sentSimpleMailMessages.add(simpleMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(SimpleMailMessage... simpleMessages) throws MailException {
|
||||
public void send(SimpleMailMessage[] simpleMessages) throws MailException {
|
||||
this.sentSimpleMailMessages.addAll(Arrays.asList(simpleMessages));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,20 @@
|
||||
|
||||
package org.springframework.integration.ws.config;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Matchers;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
@@ -412,7 +420,7 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
|
||||
doReturn(null).when(webServiceTemplate).sendAndReceive(anyString(),
|
||||
any(WebServiceMessageCallback.class),
|
||||
any(WebServiceMessageExtractor.class));
|
||||
Matchers.<WebServiceMessageExtractor<Object>>any());
|
||||
|
||||
new DirectFieldAccessor(handler).setPropertyValue("webServiceTemplate", webServiceTemplate);
|
||||
|
||||
@@ -420,7 +428,7 @@ public class WebServiceOutboundGatewayParserTests {
|
||||
|
||||
verify(webServiceTemplate).sendAndReceive(eq("jms:wsQueue"),
|
||||
any(WebServiceMessageCallback.class),
|
||||
any(WebServiceMessageExtractor.class));
|
||||
Matchers.<WebServiceMessageExtractor<Object>>any());
|
||||
}
|
||||
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
|
||||
@@ -53,7 +53,26 @@
|
||||
not worrying about the contents of the message. Think of it as a NULL JMS message. An example use-case for such an
|
||||
implementation could be a simple counter/monitor of messages deposited on the input channel.
|
||||
</note>
|
||||
<para>
|
||||
<para>
|
||||
Starting with <emphasis>version 4.1</emphasis> the framework correct converts Message properties
|
||||
(<code>payload</code> and <code>headers</code>) to the Java 8 <classname>Optional</classname> POJO method
|
||||
parameters:
|
||||
<programlisting language="java"><![CDATA[public class MyBean {
|
||||
public String computeValue(Optional<String> payload,
|
||||
@Header(value="foo", required=false) String foo1,
|
||||
@Header(value="foo") Optional<String> foo2) {
|
||||
if (payload.isPresent()) {
|
||||
String value = payload.get();
|
||||
...
|
||||
}
|
||||
else {
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
}]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Using a "ref" attribute is generally recommended if the custom Service Activator handler implementation can be reused
|
||||
in other <code><service-activator></code> definitions. However if the custom Service Activator handler implementation
|
||||
is only used within a single definition of the <code><service-activator></code>, you can provide an inner bean definition:
|
||||
|
||||
@@ -230,5 +230,12 @@
|
||||
See <xref linkend="resequencer"/>.
|
||||
</para>
|
||||
</section>
|
||||
<section id="4.1-Optional-Parameter">
|
||||
<title>Optional POJO method parameter</title>
|
||||
<para>
|
||||
Now Spring Integration consistently handles the Java 8's <classname>Optional</classname> type.
|
||||
See <xref linkend="service-activator-namespace"/>.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user