Search code examples
javaspringspring-integrationspring-integration-dslspring-integration-sftp

Error creating bean: SourcePollingChannelAdapter in functional tests when adding a new IntegrationFlow (expected single matching bean but found 2)


I have an app that uses spring-integration-sftp to perform some actions on files on sftp server.

In my Configuration class I have the following bean:

@Bean
  public IntegrationFlow readingFilesAndPrintContent(
      SessionFactory<ChannelSftp.LsEntry> sessionFactory,
      FileValidator fileValidator) {
    return IntegrationFlows.from(
                        Sftp.inboundStreamingAdapter(new
             RemoteFileTemplate<>(sessionFactory))
                .maxFetchSize(5)
                .remoteDirectory("/uploaded"),
            e -> e.poller(Pollers.cron("* * * * * *")))
        .filter(Message.class, fileValidator::isFileValid)
        .handle(
            message -> {
              printingHandle(message);
              log.info("done printing valid file");
            })
        .get();
  }

Now I want to add a new IntegrationFlow to remove some of the files, using different poller and remotelike this:

@Bean
  public IntegrationFlow readingFilesAndRemoving(
      SessionFactory<ChannelSftp.LsEntry> sessionFactory,
      FileValidator fileValidator) {
    return IntegrationFlows.from(
                        Sftp.inboundStreamingAdapter(new
             RemoteFileTemplate<>(sessionFactory))
                .maxFetchSize(3)
                .remoteDirectory("/uploaded/sub1"),
            e -> e.poller(Pollers.cron("0 0 0 * *")))
        .filter(Message.class, fileValidator::isFileForDeletion)
        .handle(
            message -> {
              removingHandle(message);
              log.info("done removing file");
            })
        .get();
  }

In my functional specs, I have this bean: @Autowired protected SourcePollingChannelAdapter sourcePollingChannelAdapter to start polling for files (sourcePollingChannelAdapter.start()), and stop polling for files (sourcePollingChannelAdapter.stop()).

But after I added the second IntegrationFlow, I get this error:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.springframework.integration.endpoint.SourcePollingChannelAdapter' available: expected single matching bean but found 2: readingFilesAndPrintContent.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0,readingFilesAndRemoving.org.springframework.integration.config.SourcePollingChannelAdapterFactoryBean#0

I have tried to add an id in the IntegrationFlow I had before:

@Bean
  public IntegrationFlow readingFilesAndPrintContent(
      SessionFactory<ChannelSftp.LsEntry> sessionFactory,
      FileValidator fileValidator) {
    return IntegrationFlows.from(
                        Sftp.inboundStreamingAdapter(new
             RemoteFileTemplate<>(sessionFactory))
                .maxFetchSize(5)
                .remoteDirectory("/uploaded"),
            e -> e.poller(Pollers.cron("* * * * * *"))
        .id("printing"))
        .filter(Message.class, fileValidator::isFileValid)
        .handle(
            message -> {
              printingHandle(message);
              log.info("done printing valid file");
            })
        .get();
  }

and a @Qualifier in the SourcePollingChannelAdapter like this: @Qualifier("printing") @Autowired protected SourcePollingChannelAdapter sourcePollingChannelAdapter

but then I got: Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'printing': Requested bean is currently in creation: Is there an unresolvable circular reference?

Is there any alternative for the SourcePollingChannelAdapter to start and stop polling files in my functional tests?

I am using spring-integration 5.5.15


Solution

  • The id() option of the SourcePollingChannelAdapterSpec is the best way to fix your problem. That is play the same role as regular bean name for anything else you define in your application context. Therefore something unique (even different from its IntegrationFlow bean definition) should work for you. And then you use that id in the @Qualifier to precisely inject a bean you would expect in the target service.