Spring Integration: Error by using subFlowMapping: failed to look up MessageChannel with name 'true' - spring-integration

I have got this error in my 'normal' code and was able to reproduce it in one simple junit test.
This error is thrown by using .route(...)..subFlowMapping(...)
If I comment .route(..) code out then test runs successful.
Could please someone explain why does Spring Integration try to find 'true' channel instead to route to true subflow?
#Test
public void testDynaSubFlowCreation() {
Flux<Message<?>> messageFlux = Flux.just("1,2,3,4").map(v -> v.split(",")).flatMapIterable(Arrays::asList)
.map(Integer::parseInt).map(GenericMessage<Integer>::new);
QueueChannel resultChannel = new QueueChannel();
IntegrationFlow integrationFlow = IntegrationFlows
.from(messageFlux)
.<Integer, Boolean>route(p->p % 2 == 0, m->m
.subFlowMapping(true, sf-> sf.<Integer, String>transform(em->{return "even:"+em;}).log())
.subFlowMapping(false, sf-> sf.<Integer, String>transform(em->{return "odd:"+em;}).log())
.defaultOutputToParentFlow()
)
.log(l -> "!!!!!!!!!!!!!!!!!!!!!!! end int="+l)
.channel(resultChannel)
.get();
this.flowContext.registration(integrationFlow).register();
int queueSize = resultChannel.getQueueSize();
assertThat(queueSize).as("queueSize").isEqualTo(4);
}
2018-02-21 17:33:27,541 [main] DEBUG reactor.util.Loggers$LoggerFactory - Using Slf4j logging framework
2018-02-21 17:33:28,184 [main] DEBUG o.s.i.handler.LoggingHandler - _org.springframework.integration.errorLogger.handler received message: ErrorMessage [payload=org.springframework.messaging.MessagingException: failed to resolve channel name 'false'; nested exception is org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available, failedMessage=GenericMessage [payload=1, headers={id=684db1df-ee6e-f35e-8332-168cee2a1681, timestamp=1519230808175}], headers={id=621649c0-b8a0-4573-9220-c38891544043, timestamp=1519230808181}]
2018-02-21 17:33:28,188 [main] ERROR o.s.i.handler.LoggingHandler - org.springframework.messaging.MessagingException: failed to resolve channel name 'false'; nested exception is org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available, failedMessage=GenericMessage [payload=1, headers={id=684db1df-ee6e-f35e-8332-168cee2a1681, timestamp=1519230808175}]
at org.springframework.integration.router.AbstractMappingMessageRouter.resolveChannelForName(AbstractMappingMessageRouter.java:227)
at org.springframework.integration.router.AbstractMappingMessageRouter.addChannelFromString(AbstractMappingMessageRouter.java:258)
at org.springframework.integration.router.AbstractMappingMessageRouter.addToCollection(AbstractMappingMessageRouter.java:296)
at org.springframework.integration.router.AbstractMappingMessageRouter.determineTargetChannels(AbstractMappingMessageRouter.java:186)
at org.springframework.integration.router.AbstractMessageRouter.handleMessageInternal(AbstractMessageRouter.java:171)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:141)
at org.springframework.integration.handler.AbstractMessageHandler.onNext(AbstractMessageHandler.java:165)
at org.springframework.integration.handler.AbstractMessageHandler.onNext(AbstractMessageHandler.java:51)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer$1.hookOnNext(ReactiveStreamsConsumer.java:138)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer$1.hookOnNext(ReactiveStreamsConsumer.java:127)
at reactor.core.publisher.BaseSubscriber.onNext(BaseSubscriber.java:158)
at reactor.core.publisher.FluxRetry$RetrySubscriber.onNext(FluxRetry.java:79)
at reactor.core.publisher.FluxPeek$PeekSubscriber.onNext(FluxPeek.java:185)
at reactor.core.publisher.FluxPublish$PublishSubscriber.drain(FluxPublish.java:457)
at reactor.core.publisher.FluxPublish$PublishSubscriber.onNext(FluxPublish.java:263)
at reactor.core.publisher.FluxCreate$IgnoreSink.next(FluxCreate.java:571)
at reactor.core.publisher.FluxCreate$SerializedSink.next(FluxCreate.java:146)
at org.springframework.integration.channel.FluxMessageChannel.doSend(FluxMessageChannel.java:65)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:438)
at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:388)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.poll(FluxPeekFuseable.java:310)
at reactor.core.publisher.FluxPublish$PublishSubscriber.drain(FluxPublish.java:411)
at reactor.core.publisher.FluxPublish$PublishSubscriber.onSubscribe(FluxPublish.java:224)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxFlattenIterable$FlattenIterableSubscriber.onSubscribe(FluxFlattenIterable.java:206)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxJust.subscribe(FluxJust.java:68)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxFlattenIterable.subscribe(FluxFlattenIterable.java:107)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxMapFuseable.subscribe(FluxMapFuseable.java:63)
at reactor.core.publisher.FluxPeekFuseable.subscribe(FluxPeekFuseable.java:86)
at reactor.core.publisher.FluxPeekFuseable.subscribe(FluxPeekFuseable.java:86)
at reactor.core.publisher.FluxPublish.connect(FluxPublish.java:99)
at reactor.core.publisher.ConnectableFlux.connect(ConnectableFlux.java:99)
at java.util.concurrent.ConcurrentHashMap$ValuesView.forEach(ConcurrentHashMap.java:4707)
at org.springframework.integration.channel.FluxMessageChannel.subscribe(FluxMessageChannel.java:77)
at org.springframework.integration.endpoint.ReactiveStreamsConsumer.doStart(ReactiveStreamsConsumer.java:127)
at org.springframework.integration.endpoint.AbstractEndpoint.start(AbstractEndpoint.java:162)
at org.springframework.integration.config.ConsumerEndpointFactoryBean.start(ConsumerEndpointFactoryBean.java:349)
at org.springframework.integration.dsl.StandardIntegrationFlow.start(StandardIntegrationFlow.java:102)
at org.springframework.integration.dsl.context.IntegrationFlowRegistration.start(IntegrationFlowRegistration.java:136)
at org.springframework.integration.dsl.context.IntegrationFlowContext.register(IntegrationFlowContext.java:108)
at org.springframework.integration.dsl.context.IntegrationFlowContext.access$500(IntegrationFlowContext.java:66)
at org.springframework.integration.dsl.context.IntegrationFlowContext$IntegrationFlowRegistrationBuilder.register(IntegrationFlowContext.java:238)
at com.lr.m3integration.DynaFlowTests.testDynaSubFlowCreation(DynaFlowTests.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:538)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:760)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by: org.springframework.messaging.core.DestinationResolutionException: failed to look up MessageChannel with name 'false' in the BeanFactory.; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:117)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:46)
at org.springframework.integration.router.AbstractMappingMessageRouter.resolveChannelForName(AbstractMappingMessageRouter.java:223)
... 80 more
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'false' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1205)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:89)
... 82 more
#artem-bilan:
I'm not completely sure that dynamically registration is a root of a problem.
I configured the same flow statically, like this:
#EnableIntegration
#Configuration
public class IntegrationTestConfig {
#Bean
public QueueChannel resultChannel() {
return new QueueChannel();
}
#Bean
public Flux<Message<?>> messageFlux(){
return Flux.just("1,2,3,4").map(v -> v.split(",")).flatMapIterable(Arrays::asList)
.map(Integer::parseInt).map(GenericMessage<Integer>::new);
}
#Bean
public MessageChannel inputChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow withSubFlows() {
return IntegrationFlows
// .from(inputChannel())
.from(messageFlux())
.<Integer, Boolean>route(p->p % 2 == 0, m->m
.subFlowMapping(true, sf-> sf.<Integer, String>transform(em->{return "even:"+em;}).log().bridge())
.subFlowMapping(false, sf-> sf.<Integer, String>transform(em->{return "odd:"+em;}).log().bridge())
.defaultOutputToParentFlow()
)
.log(l -> "!!!!!!!!!!!!!!!!!!!!!!! end int="+l)
.channel(resultChannel())
.get();
}
}
#RunWith(SpringRunner.class)
#SpringIntegrationTest
#SpringBootTest
#Autowired
public QueueChannel resultChannel;
#Autowired
public MessageChannel inputChannel;
#Test
public void testSubFlowCreation() {
// fill input channel
IntStream.range(0,4).forEach(i-> inputChannel.send(MessageBuilder.withPayload(i).build()));
// receive results after flow processing
assertThat(resultChannel.getReceiveCount()).as("receiveCount").isEqualTo(0);
assertThat(resultChannel.receive(1000)).as("message").isNotNull();
assertThat(resultChannel.getQueueSize()).as("queueSize").isEqualTo(3);
}
}
By executing with input=messageFlux() you will get the same error.
By executing with input=inputChannel() junit test runs green.

Confirmed. This is a bug in the RouterSpec. We can't use subFlowMapping() for dynamically registered flows for now. Just because the logic there is based on the ContextRefreshedEvent, which happens only once in the application context startup: https://jira.spring.io/browse/INT-4411

Related

Numerous Kafka Producer Network Thread generated during data publishing, Null Pointer Exception Spring Kafka

I am writing a Kafka Producer using Spring Kafka 2.3.9 that suppose to publish around 200000 messages to a topic. For example, I have a list of 200000 objects that I fetched from a database and I want to publish json messages of those objects to a topic.
The producer that I have written is working fine for publishing, let's say, 1000 messages. Then it is creating some null pointer error(I have included the screen shot below).
During debugging, I found that the number of Kafka Producer Network Thread is very high. I could not count them but they are definitely more than 500.
I have read the thread Kafka Producer Thread, huge amound of threads even when no message is send and did a similar configuration by making producerPerConsumerPartition property false on DefaultKafkaProducerFactory. But still it is not decreasing the Kafka Producer Network Thread count.
Below are my code snippets, error and picture of those threads. I can't post all of the code segments since it is from a real project.
Code segments
public DefaultKafkaProducerFactory<String, String> getProducerFactory() throws IOException, IllegalStateException {
Map<String, Object> configProps = getProducerConfigMap();
DefaultKafkaProducerFactory<String, String> defaultKafkaProducerFactory = new DefaultKafkaProducerFactory<>(configProps);
//defaultKafkaProducerFactory.transactionCapable();
defaultKafkaProducerFactory.setProducerPerConsumerPartition(false);
defaultKafkaProducerFactory.setProducerPerThread(false);
return defaultKafkaProducerFactory;
}
public Map<String, Object> getProducerConfigMap() throws IOException, IllegalStateException {
Map<String, Object> configProps = new HashMap<>();
configProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaProperties.getBootstrapAddress());
configProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
configProps.put(ProducerConfig.RETRIES_CONFIG, kafkaProperties.getKafkaRetryConfig());
configProps.put(ProducerConfig.ACKS_CONFIG, kafkaProperties.getKafkaAcknowledgementConfig());
configProps.put(ProducerConfig.CLIENT_ID_CONFIG, kafkaProperties.getKafkaClientId());
configProps.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 512 * 1024 * 1024);
configProps.put(ProducerConfig.MAX_BLOCK_MS_CONFIG, 10 * 1000);
configProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
//updateSSLConfig(configProps);
return configProps;
}
#Bean
public KafkaTemplate<String, String> kafkaTemplate() {
ProducerFactory<String, String> producerFactory = getProducerFactory();
KafkaTemplate<String, String> kt = new KafkaTemplate<String, String>(stringProducerFactory, true);
kt.setCloseTimeout(java.time.Duration.ofSeconds(5));
return kt;
}
Error
2020-12-07 18:14:19.249 INFO 26651 --- [onPool-worker-1] o.a.k.clients.producer.KafkaProducer : [Producer clientId=kafka-client-09f48ec8-7a69-4b76-a4f4-a418e96ff68e-1] Closing the Kafka producer with timeoutMillis = 0 ms.
2020-12-07 18:14:19.254 ERROR 26651 --- [onPool-worker-1] c.w.p.r.g.xxxxxxxx.xxx.KafkaPublisher : Exception happened publishing to topic. Failed to construct kafka producer
2020-12-07 18:14:19.273 INFO 26651 --- [ main] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-12-07 18:14:19.281 ERROR 26651 --- [ main] o.s.boot.SpringApplication : Application run failed
java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:787) [spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:768) [spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:322) [spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) [spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) [spring-boot-2.2.8.RELEASE.jar:2.2.8.RELEASE]
at xxx.xxx.xxx.Application.main(Application.java:46) [classes/:na]
Caused by: java.util.concurrent.CompletionException: java.lang.NullPointerException
at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273) ~[na:1.8.0_144]
at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280) ~[na:1.8.0_144]
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592) ~[na:1.8.0_144]
at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582) ~[na:1.8.0_144]
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289) ~[na:1.8.0_144]
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056) ~[na:1.8.0_144]
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692) ~[na:1.8.0_144]
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157) ~[na:1.8.0_144]
Caused by: java.lang.NullPointerException: null
at com.xxx.xxx.xxx.xxx.KafkaPublisher.publishData(KafkaPublisher.java:124) ~[classes/:na]
at com.xxx.xxx.xxx.xxx.lambda$0(Publisher.java:39) ~[classes/:na]
at java.util.ArrayList.forEach(ArrayList.java:1249) ~[na:1.8.0_144]
at com.xxx.xxx.xxx.xxx.publishData(Publisher.java:38) ~[classes/:na]
at com.xxx.xxx.xxx.xxx.Application.lambda$0(Application.java:75) [classes/:na]
at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1590) ~[na:1.8.0_144]
... 5 common frames omitted
Following is the code for publishing the message - line number 124 is when we actually call KafkaTemplate
public void publishData(Object object) {
ListenableFuture<SendResult<String, String>> future = null;
// Convert the Object to JSON
String json = convertObjectToJson(object);
// Generate unique key for the message
String key = UUID.randomUUID().toString();
// Post the JSON to Kafka
try {
future = kafkaConfig.kafkaTemplate().send(kafkaProperties.getTopicName(), key, json);
} catch (Exception e) {
logger.error("Exception happened publishing to topic. {}", e.getMessage());
}
future.addCallback(new ListenableFutureCallback<SendResult<String, String>>() {
#Override
public void onSuccess(SendResult<String, String> result) {
logger.info("Sent message with key=[" + key + "]");
}
#Override
public void onFailure(Throwable ex) {
logger.error("Unable to send message=[ {} due to {}", json, ex.getMessage());
}
});
kafkaConfig.kafkaTemplate().flush();
}
============================
I am not sure if this error is causing by those many network threads.
After posting the data, I have called KafkaTemplate flush method. It did not work.
I also called ProducerFactory closeThreadBoundProducer, reset, destroy methods. None of them seems working.
Am I missing any configuration?
The null pointer issue was not actually related to Spring Kafka. We were reading the topic name from a different location connected by a network. That network connection was failing for few cases and that caused null pointer issue which ultimately caused the above error.

NPE on FilePart mock in Spring WebFlux at reactor.core.publisher.MonoWhen$WhenCoordinator

I would appreciate any hints on the following problem I've encountered. While unit testing multipart file upload service method in Spring Reactive WebFlux app, I am getting NPE for reactor.core.publisher.MonoWhen$WhenCoordinator as follows
java.lang.NullPointerException
at reactor.core.publisher.MonoWhen$WhenCoordinator.subscribe(MonoWhen.java:149)
Complete log is listed below as well.
Test :
#RunWith(SpringRunner.class)
#SpringBootTest
public class FileServiceTest2 {
#MockBean
private UploadedImageRepository uploadedImageRepository;
...
#Test
public void assembleImageTest() {
UploadedImage ui1 = new UploadedImage("1", "ui1.png");
UploadedImage ui2 = new UploadedImage("2", "ui2.png");
FilePart filePart1 = mock(FilePart.class);
FilePart filePart2 = mock(FilePart.class);
given(this.uploadedImageRepository.save(ui1))
.willReturn(Mono.just(ui1));
given(this.uploadedImageRepository.save(ui2))
.willReturn(Mono.just(ui2));
given(this.uploadedImageRepository.findAll())
.willReturn(Flux.just(ui1, ui2));
given(filePart1.filename())
.willReturn(ui1.getImageName());
given(filePart1.transferTo(any()))
.willReturn(Mono.empty());
given(filePart2.filename())
.willReturn(ui2.getImageName());
given(filePart2.transferTo(any()))
.willReturn(Mono.empty());
Flux<FilePart> files = Flux.just(filePart1, filePart2);
StepVerifier.create(this.uploadService.createFile(files))
.verifyComplete();
}
Under test :
#Service
public class UploadService {
Mono<Void> createFile(Flux<FilePart> fileParts) {
return fileParts.flatMap(part -> {
Mono<UploadedImage> savedToDBImage = this.uploadedImageRepository.save(
new UploadedImage(UUID.randomUUID().toString(), part.filename()))
.log("createFile-fileSavedToDB"); // NPE!
Mono<Void> copiedFile = Mono.just(Paths.get(UPLOAD_URL, part.filename()).toFile())
.log("createFile-pathAssembled")
.doOnNext(destinationFile -> {
try {
destinationFile.createNewFile();
} catch (IOException e) {
throw new RuntimeException(e);
}
})
.log("createFile-fileAssembled")
.flatMap(part::transferTo)
.log("createFile-fileCopied");
return Mono.when(savedToDBImage, copiedFile)
.log("createFile-monoWhen");
})
.log("createFile-flatMap")
.then()
.log("createFile-done");
}
UploadedImage class (w Lombok) :
#Data
#RequiredArgsConstructor
#NoArgsConstructor
public class UploadedImage {
#NonNull private String id;
#NonNull private String imageName;
}
SpringData Reactive Repository:
#Repository
public interface UploadedImageRepository extends ReactiveCrudRepository<UploadedImage, String> {
}
Logs are as follows:
java.lang.NullPointerException
at reactor.core.publisher.MonoWhen$WhenCoordinator.subscribe(MonoWhen.java:149)
at reactor.core.publisher.MonoWhen.subscribe(MonoWhen.java:99)
at reactor.core.publisher.MonoOnAssembly.subscribe(MonoOnAssembly.java:76)
at reactor.core.publisher.MonoLogFuseable.subscribe(MonoLogFuseable.java:53)
at reactor.core.publisher.Mono.subscribe(Mono.java:3080)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onNext(FluxFlatMap.java:372)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:198)
at reactor.core.publisher.FluxArray$ArraySubscription.slowPath(FluxArray.java:118)
at reactor.core.publisher.FluxArray$ArraySubscription.request(FluxArray.java:91)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.request(FluxPeekFuseable.java:138)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:332)
at reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onSubscribe(FluxPeekFuseable.java:172)
at reactor.core.publisher.FluxArray.subscribe(FluxArray.java:53)
at reactor.core.publisher.FluxArray.subscribe(FluxArray.java:59)
at reactor.core.publisher.FluxLogFuseable.subscribe(FluxLogFuseable.java:53)
at reactor.core.publisher.FluxFlatMap.subscribe(FluxFlatMap.java:97)
at reactor.core.publisher.FluxLog.subscribe(FluxLog.java:50)
at reactor.core.publisher.MonoIgnoreElements.subscribe(MonoIgnoreElements.java:37)
at reactor.core.publisher.MonoLog.subscribe(MonoLog.java:51)
at reactor.core.publisher.Mono.subscribe(Mono.java:3080)
at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:728)
at reactor.test.DefaultStepVerifierBuilder$DefaultStepVerifier.verify(DefaultStepVerifierBuilder.java:700)
at reactor.test.DefaultStepVerifierBuilder.verifyComplete(DefaultStepVerifierBuilder.java:566)
at pb.sl.UploadService.createFile(FileServiceTest2.java:112)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Looking more closely, I think you're not mocking your repository as expected, and in your test the repository call returns null.
You're not using a Mockito argument matcher but a concrete instance for the argument. Later in your service implementation, this method is called, but with a different instance. My guess is Mockito is using equals to check if the given matches that mock call - maybe your UploadedImage could be improved in that regard?
given(this.uploadedImageRepository.save(ui1)) should be:
given(this.uploadedImageRepository.save(any()))
.willAnswer(invocation -> Mono.just(invocation.getArgument(0)))

Trying to integrate Spring Batch with spring integration getting error

The below class is used to poll for a file in a directory and trigger the spring batch once a file is received in a directory. I am getting some error, which I am not able to figure out. please advice.
Also, if there is some sample code example to do the same, please refer me to that location.
#Configuration
class FilePollingIntegrationFlow {
#Autowired
private ApplicationContext applicationContext;
// this is the integration flow that foirst polls for messages and then trigger the spring batch job
#Bean
public IntegrationFlow inboundFileIntegration(#Value("${inbound.file.poller.fixed.delay}") long period,
#Value("${inbound.file.poller.max.messages.per.poll}") int maxMessagesPerPoll,
TaskExecutor taskExecutor,
MessageSource<File> fileReadingMessageSource,
JobLaunchingGateway jobLaunchingGateway) {
return IntegrationFlows.from(fileReadingMessageSource,
c -> c.poller(Pollers.fixedDelay(period)
.taskExecutor(taskExecutor)
.maxMessagesPerPoll(maxMessagesPerPoll)))
.transform(Transformers.fileToString())
.channel(ApplicationConfiguration.INBOUND_CHANNEL)
.handle((p, h) -> {
System.out.println("Testing:::::"+p);
return p;
})
.handle(fileMessageToJobRequest())
.handle(jobLaunchingGateway(),"toRequest")
.channel(MessageChannels.queue())
.get();
}
#Bean
public FileMessageToJobRequest fileMessageToJobRequest() {
FileMessageToJobRequest fileMessageToJobRequest = new FileMessageToJobRequest();
fileMessageToJobRequest.setFileParameterName("input.file.name");
// fileMessageToJobRequest.setJob(personJob());
System.out.println("FilePollingIntegrationFlow::fileMessageToJobRequest::::Job launched successfully!!!");
return fileMessageToJobRequest;
}
#Bean
public JobLaunchingGateway jobLaunchingGateway() {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
// simpleJobLauncher.setJobRepository(jobRepository);
simpleJobLauncher.setTaskExecutor(new SyncTaskExecutor());
JobLaunchingGateway jobLaunchingGateway = new JobLaunchingGateway(simpleJobLauncher);
System.out.println("FilePollingIntegrationFlow::jobLaunchingGateway::::Job launched successfully!!!");
return jobLaunchingGateway;
}
//This is another class used for batch job trigger
public class FileMessageToJobRequest {
private Job job;
private String fileParameterName;
public void setFileParameterName(String fileParameterName) {
this.fileParameterName = fileParameterName;
}
public void setJob(Job job) {
this.job = job;
}
#Transformer
public JobLaunchRequest toRequest(Message<File> message) {
JobParametersBuilder jobParametersBuilder =
new JobParametersBuilder();
jobParametersBuilder.addString(fileParameterName,
message.getPayload().getAbsolutePath());
return new JobLaunchRequest(job, jobParametersBuilder.toJobParameters());
}
}
I am getting the below error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'inboundFileIntegration' defined in class path resource [com/porterhead/integration/file/FilePollingIntegrationFlow.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766)
at org.springframework.boot.SpringApplication.createAndRefreshContext(SpringApplication.java:361)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:134)
at com.porterhead.Application.main(Application.java:23)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'inboundFileIntegration' threw exception; nested exception is java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 16 common frames omitted
Caused by: java.lang.IllegalArgumentException: Target object of type [class org.springframework.batch.integration.launch.JobLaunchingGateway] has no eligible methods for handling Messages.
at org.springframework.integration.util.MessagingMethodInvokerHelper.findHandlerMethodsForTarget(MessagingMethodInvokerHelper.java:494)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:226)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:135)
at org.springframework.integration.util.MessagingMethodInvokerHelper.<init>(MessagingMethodInvokerHelper.java:139)
at org.springframework.integration.handler.MethodInvokingMessageProcessor.<init>(MethodInvokingMessageProcessor.java:52)
at org.springframework.integration.handler.ServiceActivatingHandler.<init>(ServiceActivatingHandler.java:45)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:982)
at org.springframework.integration.dsl.IntegrationFlowDefinition.handle(IntegrationFlowDefinition.java:964)
at com.porterhead.integration.file.FilePollingIntegrationFlow.inboundFileIntegration(FilePollingIntegrationFlow.java:85)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.CGLIB$inboundFileIntegration$1(<generated>)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9$$FastClassBySpringCGLIB$$4ce6110e.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:356)
at com.porterhead.integration.file.FilePollingIntegrationFlow$$EnhancerBySpringCGLIB$$c1cfa1e9.inboundFileIntegration(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 17 common frames omitted
Please advice.
Since your FileMessageToJobRequest.toRequest() is marked with the #Transformer you should consider to use .transform() instead.
Also I see that you use that toRequest method name for the JobLaunchingGateway what is definitely wrong. So, the proper way to go is like this:
.transform(fileMessageToJobRequest())
.handle(jobLaunchingGateway())
The sample you are looking for is in the Spring Batch Reference Manual.

Spring-Integration UnableToRegisterMBeanException: InstanceAlreadyExistsException

I am getting InstanceAlreadyExistsException while trying to deploy in tomcat 8 in linux server the code with Spring Integration having 2 separate flows. I referred several forums and still not able to find a solution for this. But am not getting this exception while testing in my local tomcat 8 in windows platform. Any input is appreciated.
Stacktrace -
2016-08-30 14:27:40 ERROR SpringApplication:838 - Application startup failed
org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [getCities.channel#0] with key 'org.springframework.integration:type=MessageChannel,name=getCities.channel#0'; nested exception is javax.management.InstanceAlreadyExistsException: org.springframework.integration:type=MessageChannel,name=getCities.channel#0
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.integration.monitor.IntegrationMBeanExporter.registerChannels(IntegrationMBeanExporter.java:675) ~[spring-integration-jmx-4.3.1.RELEASE.jar:4.3.1.RELEASE]
at org.springframework.integration.monitor.IntegrationMBeanExporter.afterSingletonsInstantiated(IntegrationMBeanExporter.java:271) ~[spring-integration-jmx-4.3.1.RELEASE.jar:4.3.1.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:796) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122) ~[spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:369) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:313) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:150) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:130) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.boot.web.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:86) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:169) [spring-web-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5261) [catalina.jar:8.0.35]
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147) [catalina.jar:8.0.35]
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:725) [catalina.jar:8.0.35]
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:701) [catalina.jar:8.0.35]
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:717) [catalina.jar:8.0.35]
at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:940) [catalina.jar:8.0.35]
at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1816) [catalina.jar:8.0.35]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [?:1.8.0_91]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_91]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_91]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_91]
Caused by: javax.management.InstanceAlreadyExistsException: org.springframework.integration:type=MessageChannel,name=getCities.channel#0
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900) ~[?:1.8.0_91]
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324) ~[?:1.8.0_91]
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[?:1.8.0_91]
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:678) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615) ~[spring-context-4.3.2.RELEASE.jar:4.3.2.RELEASE]
The configuration is given below -
#Configuration
#EnableAutoConfiguration(exclude = JmxAutoConfiguration.class)
#EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
#EnableAspectJAutoProxy
#EnableAsync
#EnableWebMvc
#ComponentScan(basePackages = "foobar")
#PropertySource("classpath:environments/dev.properties")
#Import({SecurityConfig.class, IntegrationConfig.class})
public class AppConfig extends WebMvcConfigurerAdapter {
#Autowired
Environment environment;
#Bean
#Scope(BeanScopes.SINGLETON)
public Logger getLogger() {
return LoggerFactory.getLogger("SampleService");
}
#Bean
public LoggerAspect loggerAspect() {
return new LoggerAspect(getLogger(), jsonMapper());
}
}
#EnableIntegration
#IntegrationComponentScan(basePackages = "fooBar")
#Import({FirstConfig.class, SecondConfig.class})
public class IntegrationConfig {
}
#MessagingGateway
public interface FirstGateway {
#Gateway(requestChannel = "getCitiesChannel")
CityModel[] getCities(Message<FirstPayload> message);
}
public class FirstConfig {
#Bean
public MessageChannel getCitiesChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow sdsGetCities() {
return IntegrationFlows
.from("input")
.channel("getCitiesChannel")
.handle(foobar)
.get();
}
}
#MessagingGateway
public interface SecondGateway {
#Gateway(requestChannel = "getProductDetailsChannel")
ProductModel getProductDetails(Message<SecondPayload> message);
}
public class SecondConfig {
#Bean
public MessageChannel getProductDetailsChannel() {
return MessageChannels.direct().get();
}
#Bean
public IntegrationFlow getProductDetails() {
return IntegrationFlows
.from("input")
.channel("getProductDetailsChannel")
.handle(foobar)
.get();
}
}
You don't show your #EnableIntegrationMBeanExport; if you are deploying 2 apps with similar flows, you need to put each app in a different domain #EnableIntegrationMBeanExport(defaultDomain="foo") and #EnableIntegrationMBeanExport(defaultDomain="bar"), so
org.springframework.integration:type=MessageChannel,name=getCities.channel#0
becomes
foo:type=MessageChannel,name=getCities.channel#0
and
bar:type=MessageChannel,name=getCities.channel#0
If it's only one app (which it looks like) then it means the previous deployment didn't shut down properly.
try this
<context:mbean-export registration="replaceExisting"/>
I got this error when using an abstract base class for my integration tests.
I added #DirtiesContext to my base class, so that the application context would be flushed between each test.

ftp/sftp spring integration - localDirectory must not be null

I am trying to poll ftp server for file and process them. I want to do it without xml configuration. I am using spring boot(1.2.5) and spring integration ftp (4.1.5)
I created a bean for session factory
#Bean
public DefaultFtpSessionFactory ftpSessionFactory() {
DefaultFtpSessionFactory ftpSessionFactory = new DefaultFtpSessionFactory();
ftpSessionFactory.setHost(ftpProperties.ftpHost);
ftpSessionFactory.setPort(Integer.parseInt(ftpProperties.ftpPort));
ftpSessionFactory.setUsername(ftpProperties.ftpUser);
ftpSessionFactory.setPassword(ftpProperties .ftpPassword);
return ftpSessionFactory;
}
I am trying to configure ftp server polling as follows.
#Bean
#InboundChannelAdapter(value = "receiveChannel", poller = #Poller(fixedRate="1000"))
public MessageSource pollFtpForFiles() {
File localDirectory = new File(sftpProperties.localDirectory);
System.err.println("LocalDirectory::"+localDirectory.getAbsolutePath()+"::exists::"+localDirectory.isDirectory());
FtpInboundFileSynchronizer ftpInboundFileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
ftpInboundFileSynchronizer.setRemoteDirectory(sftpProperties.remoteDirectory);
ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
return new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer);
}
But I am getting following exception when I run the app.
Not sure what I am doing wrong. Can somebody help me. (I tried with sftp also with same result)
LocalDirectory::localDirForSftpTransfer::exists::true
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sftpInboundSetup' defined in file [/Users/rsamban/Documents/workspace/Second/target/classes/com/yesVin/integration/sftp/SftpInboundSetup.class]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pollFtpForFiles' defined in class path resource [com/yesVin/integration/sftp/SftpInboundSetup.class]: **Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:755)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at com.yesVin.integration.SecondApplication.main(SecondApplication.java:16)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'pollFtpForFiles' defined in class path resource [com/yesVin/integration/sftp/SftpInboundSetup.class]: **Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.integration.config.annotation.AbstractMethodAnnotationPostProcessor.resolveTargetBeanFromMethodWithBeanAnnotation(AbstractMethodAnnotationPostProcessor.java:362)
at org.springframework.integration.config.annotation.InboundChannelAdapterAnnotationPostProcessor.createMessageSource(InboundChannelAdapterAnnotationPostProcessor.java:76)
at org.springframework.integration.config.annotation.InboundChannelAdapterAnnotationPostProcessor.postProcess(InboundChannelAdapterAnnotationPostProcessor.java:62)
at org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor$1.doWith(MessagingAnnotationPostProcessor.java:151)
at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:495)
at org.springframework.integration.config.annotation.MessagingAnnotationPostProcessor.postProcessAfterInitialization(MessagingAnnotationPostProcessor.java:131)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:422)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1579)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
... 13 more
**Caused by: java.lang.IllegalArgumentException: localDirectory must not be null**
at org.springframework.util.Assert.notNull(Assert.java:112)
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizingMessageSource.afterPropertiesSet(AbstractInboundFileSynchronizingMessageSource.java:132)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1633)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1570)
... 28 more
thanks
-Ramesh
The operation:
ftpInboundFileSynchronizer.synchronizeToLocalDirectory(localDirectory);
isn't for your responsibility.
I'm sure you meant exactly this setter:
FtpInboundFileSynchronizingMessageSource.setLocalDirectory(localDirectory);
In other words your #InboundChannelAdapter should look like this:
#Bean
#InboundChannelAdapter(value = "receiveChannel", poller = #Poller(fixedRate="1000"))
public MessageSource pollFtpForFiles() {
File localDirectory = new File(sftpProperties.localDirectory);
System.err.println("LocalDirectory::"+localDirectory.getAbsolutePath()+"::exists::"+localDirectory.isDirectory());
FtpInboundFileSynchronizer ftpInboundFileSynchronizer = new FtpInboundFileSynchronizer(ftpSessionFactory());
ftpInboundFileSynchronizer.setRemoteDirectory(sftpProperties.remoteDirectory);
FtpInboundFileSynchronizingMessageSource messageSource = new FtpInboundFileSynchronizingMessageSource(ftpInboundFileSynchronizer);
messageSource.setLocalDirectory(localDirectory);
return messageSource;
}

Resources