Fix NPEs in DSL Specs (#8597)
* Fix NPEs in DSL Specs The `BaseWsInboundGatewaySpec` and `TailAdapterSpec` don't override super methods and when we call them we fail with NPE since `target` was not populated. * Fix `BaseWsInboundGatewaySpec` and its inheritors to populate the `target` from their ctors. * Remove redundant methods from `BaseWsInboundGatewaySpec` hierarchy * Propagate `AbstractWebServiceInboundGateway` properties directly to the target from the `BaseWsInboundGatewaySpec` inheritors * Override `MessageProducerSpec` methods in the `TailAdapterSpec` to populate respective option into the `FileTailInboundChannelAdapterFactoryBean` * Expose more missed options for producer endpoint in the `FileTailInboundChannelAdapterFactoryBean` **Cherry-pick to `6.0.x` & `5.5.x`** * * `acceptIfNotNull()` for `errorMessageStrategy` in the `FileTailInboundChannelAdapterFactoryBean` * * Fix `Unmarshaller` population logic in the `MarshallingWsInboundGatewaySpec`
This commit is contained in:
committed by
Gary Russell
parent
863795c11f
commit
a45c3c5396
@@ -29,6 +29,7 @@ import org.springframework.integration.JavaUtils;
|
||||
import org.springframework.integration.file.tail.ApacheCommonsFileTailingMessageProducer;
|
||||
import org.springframework.integration.file.tail.FileTailingMessageProducerSupport;
|
||||
import org.springframework.integration.file.tail.OSDelegatingFileTailingMessageProducer;
|
||||
import org.springframework.integration.support.ErrorMessageStrategy;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -83,6 +84,12 @@ public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBea
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
private long sendTimeout;
|
||||
|
||||
private boolean shouldTrack;
|
||||
|
||||
private ErrorMessageStrategy errorMessageStrategy;
|
||||
|
||||
public void setNativeOptions(String nativeOptions) {
|
||||
if (StringUtils.hasText(nativeOptions)) {
|
||||
this.nativeOptions = nativeOptions;
|
||||
@@ -165,6 +172,18 @@ public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBea
|
||||
this.phase = phase;
|
||||
}
|
||||
|
||||
public void setSendTimeout(long sendTimeout) {
|
||||
this.sendTimeout = sendTimeout;
|
||||
}
|
||||
|
||||
public void setShouldTrack(boolean shouldTrack) {
|
||||
this.shouldTrack = shouldTrack;
|
||||
}
|
||||
|
||||
public void setErrorMessageStrategy(ErrorMessageStrategy errorMessageStrategy) {
|
||||
this.errorMessageStrategy = errorMessageStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
@@ -241,6 +260,8 @@ public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBea
|
||||
adapter.setOutputChannel(this.outputChannel);
|
||||
adapter.setErrorChannel(this.errorChannel);
|
||||
adapter.setBeanName(this.beanName);
|
||||
adapter.setSendTimeout(this.sendTimeout);
|
||||
adapter.setShouldTrack(this.shouldTrack);
|
||||
BeanFactory beanFactory = getBeanFactory();
|
||||
JavaUtils.INSTANCE
|
||||
.acceptIfNotNull(this.taskExecutor, adapter::setTaskExecutor)
|
||||
@@ -252,6 +273,7 @@ public class FileTailInboundChannelAdapterFactoryBean extends AbstractFactoryBea
|
||||
.acceptIfNotNull(this.applicationEventPublisher, adapter::setApplicationEventPublisher)
|
||||
.acceptIfNotNull(this.outputChannelName, adapter::setOutputChannelName)
|
||||
.acceptIfNotNull(this.errorChannelName, adapter::setErrorChannelName)
|
||||
.acceptIfNotNull(this.errorMessageStrategy, adapter::setErrorMessageStrategy)
|
||||
.acceptIfNotNull(beanFactory, adapter::setBeanFactory);
|
||||
adapter.afterPropertiesSet();
|
||||
this.tailAdapter = adapter;
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.integration.dsl.MessageProducerSpec;
|
||||
import org.springframework.integration.file.config.FileTailInboundChannelAdapterFactoryBean;
|
||||
import org.springframework.integration.file.tail.FileTailingMessageProducerSupport;
|
||||
import org.springframework.integration.support.ErrorMessageStrategy;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -39,10 +40,6 @@ public class TailAdapterSpec extends MessageProducerSpec<TailAdapterSpec, FileTa
|
||||
|
||||
private final FileTailInboundChannelAdapterFactoryBean factoryBean = new FileTailInboundChannelAdapterFactoryBean();
|
||||
|
||||
private MessageChannel outputChannel;
|
||||
|
||||
private MessageChannel errorChannel;
|
||||
|
||||
protected TailAdapterSpec() {
|
||||
super(null);
|
||||
this.factoryBean.setBeanFactory(new DefaultListableBeanFactory());
|
||||
@@ -53,7 +50,6 @@ public class TailAdapterSpec extends MessageProducerSpec<TailAdapterSpec, FileTa
|
||||
this.factoryBean.setFile(file);
|
||||
return _this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the options string for native {@code tail} command.
|
||||
* @param nativeOptions the nativeOptions.
|
||||
@@ -145,7 +141,7 @@ public class TailAdapterSpec extends MessageProducerSpec<TailAdapterSpec, FileTa
|
||||
/**
|
||||
* If {@code true}, close and reopen the file between reading chunks.
|
||||
* Default {@code false}.
|
||||
* @param reopen the reopen.
|
||||
* @param reopen the 'reopen' option.
|
||||
* @return the spec.
|
||||
* @see org.springframework.integration.file.tail.ApacheCommonsFileTailingMessageProducer#setReopen(boolean)
|
||||
*/
|
||||
@@ -174,13 +170,43 @@ public class TailAdapterSpec extends MessageProducerSpec<TailAdapterSpec, FileTa
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec outputChannel(MessageChannel outputChannel) {
|
||||
this.outputChannel = outputChannel;
|
||||
this.factoryBean.setOutputChannel(outputChannel);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec errorChannel(MessageChannel errorChannel) {
|
||||
this.errorChannel = errorChannel;
|
||||
this.factoryBean.setErrorChannel(errorChannel);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec outputChannel(String outputChannel) {
|
||||
this.factoryBean.setOutputChannelName(outputChannel);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec errorChannel(String errorChannel) {
|
||||
this.factoryBean.setErrorChannelName(errorChannel);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec sendTimeout(long sendTimeout) {
|
||||
this.factoryBean.setSendTimeout(sendTimeout);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec shouldTrack(boolean shouldTrack) {
|
||||
this.factoryBean.setShouldTrack(shouldTrack);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TailAdapterSpec errorMessageStrategy(ErrorMessageStrategy errorMessageStrategy) {
|
||||
this.factoryBean.setErrorMessageStrategy(errorMessageStrategy);
|
||||
return _this();
|
||||
}
|
||||
|
||||
@@ -194,10 +220,8 @@ public class TailAdapterSpec extends MessageProducerSpec<TailAdapterSpec, FileTa
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
if (this.errorChannel != null) {
|
||||
tailingMessageProducerSupport.setErrorChannel(this.errorChannel);
|
||||
}
|
||||
tailingMessageProducerSupport.setOutputChannel(this.outputChannel);
|
||||
Assert.notNull(tailingMessageProducerSupport,
|
||||
"The 'FileTailInboundChannelAdapterFactoryBean' must not produce null");
|
||||
return tailingMessageProducerSupport;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2022 the original author or authors.
|
||||
* Copyright 2016-2023 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.
|
||||
@@ -65,6 +65,7 @@ import org.springframework.integration.file.splitter.FileSplitter;
|
||||
import org.springframework.integration.file.support.FileExistsMode;
|
||||
import org.springframework.integration.file.support.FileUtils;
|
||||
import org.springframework.integration.file.tail.ApacheCommonsFileTailingMessageProducer;
|
||||
import org.springframework.integration.support.DefaultErrorMessageStrategy;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.messaging.Message;
|
||||
@@ -355,9 +356,12 @@ public class FileTests {
|
||||
return IntegrationFlow
|
||||
.from(Files.tailAdapter(new File(tmpDir, "TailTest"))
|
||||
.delay(500)
|
||||
.errorMessageStrategy(new DefaultErrorMessageStrategy())
|
||||
.end(false)
|
||||
.id("tailer")
|
||||
.autoStartup(false))
|
||||
.autoStartup(false)
|
||||
.shouldTrack(true)
|
||||
.sendTimeout(30_000))
|
||||
.transform("hello "::concat)
|
||||
.channel(MessageChannels.queue("tailChannel"))
|
||||
.get();
|
||||
|
||||
@@ -27,6 +27,8 @@ import org.springframework.integration.ws.SoapHeaderMapper;
|
||||
* @param <E> the target {@link AbstractWebServiceInboundGateway} implementation type.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.3
|
||||
*
|
||||
*/
|
||||
@@ -35,10 +37,10 @@ public abstract class BaseWsInboundGatewaySpec<
|
||||
extends MessagingGatewaySpec<S, E> {
|
||||
|
||||
/**
|
||||
* Construct an instance.
|
||||
* Construct an instance based on the provided {@link AbstractWebServiceInboundGateway}.
|
||||
*/
|
||||
protected BaseWsInboundGatewaySpec() {
|
||||
super(null);
|
||||
protected BaseWsInboundGatewaySpec(E gateway) {
|
||||
super(gateway);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,15 +53,4 @@ public abstract class BaseWsInboundGatewaySpec<
|
||||
return _this();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected E doGet() {
|
||||
return assemble(create());
|
||||
}
|
||||
|
||||
protected abstract E create();
|
||||
|
||||
protected E assemble(E gateway) {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,15 +24,18 @@ import org.springframework.oxm.Unmarshaller;
|
||||
* The spec for a {@link MarshallingWebServiceInboundGateway}.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.3
|
||||
*
|
||||
*/
|
||||
public class MarshallingWsInboundGatewaySpec extends BaseWsInboundGatewaySpec<MarshallingWsInboundGatewaySpec,
|
||||
MarshallingWebServiceInboundGateway> {
|
||||
public class MarshallingWsInboundGatewaySpec
|
||||
extends BaseWsInboundGatewaySpec<MarshallingWsInboundGatewaySpec, MarshallingWebServiceInboundGateway> {
|
||||
|
||||
protected Marshaller gatewayMarshaller; // NOSONAR
|
||||
|
||||
protected Unmarshaller gatewayUnmarshaller; // NOSONAR
|
||||
protected MarshallingWsInboundGatewaySpec() {
|
||||
super(new MarshallingWebServiceInboundGateway());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify a marshaller to use.
|
||||
@@ -40,29 +43,22 @@ public class MarshallingWsInboundGatewaySpec extends BaseWsInboundGatewaySpec<Ma
|
||||
* @return the spec.
|
||||
*/
|
||||
public MarshallingWsInboundGatewaySpec marshaller(Marshaller marshaller) {
|
||||
this.gatewayMarshaller = marshaller;
|
||||
this.target.setMarshaller(marshaller);
|
||||
if (marshaller instanceof Unmarshaller unmarshaller) {
|
||||
return unmarshaller(unmarshaller);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an unmarshaller to use. Required if the {@link #gatewayMarshaller} is not also
|
||||
* Specify an unmarshaller to use. Required if the {@link #marshaller} is not also
|
||||
* an {@link Unmarshaller}.
|
||||
* @param unmarshaller the unmarshaller.
|
||||
* @return the spec.
|
||||
*/
|
||||
public MarshallingWsInboundGatewaySpec unmarshaller(Unmarshaller unmarshaller) {
|
||||
this.gatewayUnmarshaller = unmarshaller;
|
||||
this.target.setUnmarshaller(unmarshaller);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MarshallingWebServiceInboundGateway create() {
|
||||
if (this.gatewayUnmarshaller != null) {
|
||||
return new MarshallingWebServiceInboundGateway(this.gatewayMarshaller, this.gatewayUnmarshaller);
|
||||
}
|
||||
else {
|
||||
return new MarshallingWebServiceInboundGateway(this.gatewayMarshaller);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,30 +22,27 @@ import org.springframework.integration.ws.SimpleWebServiceInboundGateway;
|
||||
* The spec for a {@link SimpleWebServiceInboundGateway}.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @since 5.3
|
||||
* @author Artem Bilan
|
||||
*
|
||||
* @since 5.3
|
||||
*/
|
||||
public class SimpleWsInboundGatewaySpec extends BaseWsInboundGatewaySpec<SimpleWsInboundGatewaySpec,
|
||||
SimpleWebServiceInboundGateway> {
|
||||
public class SimpleWsInboundGatewaySpec
|
||||
extends BaseWsInboundGatewaySpec<SimpleWsInboundGatewaySpec, SimpleWebServiceInboundGateway> {
|
||||
|
||||
protected boolean extractPayload = true; // NOSONAR
|
||||
protected SimpleWsInboundGatewaySpec() {
|
||||
super(new SimpleWebServiceInboundGateway());
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify true to extract the payloadSource from the request or use
|
||||
* the entire request as the payload; default true.
|
||||
*
|
||||
* @param extract true to extract.
|
||||
* @return the spec.
|
||||
*/
|
||||
public SimpleWsInboundGatewaySpec extractPayload(boolean extract) {
|
||||
this.extractPayload = extract;
|
||||
this.target.setExtractPayload(extract);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SimpleWebServiceInboundGateway create() {
|
||||
SimpleWebServiceInboundGateway gateway = new SimpleWebServiceInboundGateway();
|
||||
gateway.setExtractPayload(this.extractPayload);
|
||||
return gateway;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.LiteralExpression;
|
||||
import org.springframework.integration.test.util.TestUtils;
|
||||
import org.springframework.integration.ws.DefaultSoapHeaderMapper;
|
||||
import org.springframework.integration.ws.MarshallingWebServiceInboundGateway;
|
||||
import org.springframework.integration.ws.MarshallingWebServiceOutboundGateway;
|
||||
import org.springframework.integration.ws.SimpleWebServiceInboundGateway;
|
||||
@@ -71,10 +72,16 @@ public class WsDslTests {
|
||||
|
||||
@Test
|
||||
void simpleInbound() {
|
||||
SimpleWebServiceInboundGateway gateway = Ws.simpleInboundGateway()
|
||||
.extractPayload(false)
|
||||
.get();
|
||||
DefaultSoapHeaderMapper testHeaderMapper = new DefaultSoapHeaderMapper();
|
||||
SimpleWebServiceInboundGateway gateway =
|
||||
Ws.simpleInboundGateway()
|
||||
.extractPayload(false)
|
||||
.headerMapper(testHeaderMapper)
|
||||
.errorChannel("myErrorChannel")
|
||||
.get();
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "extractPayload", Boolean.class)).isFalse();
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "headerMapper")).isSameAs(testHeaderMapper);
|
||||
assertThat(TestUtils.getPropertyValue(gateway, "errorChannelName")).isEqualTo("myErrorChannel");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user