2

I'm trying to build a Spring XD (Spring Integration DSL based) sink module using the spring-integration-aws extension. My module looks like so:

@Configuration
@EnableIntegration
public class S3Module {

    @Value("${accessKey:myAccessKey}")
    private String accessKey;

    @Value("${secretKey:mySecretKey}")
    private String secretKey;

    @Value("${bucket:myBucket}")
    private String bucket;

    @Value("${remoteDirectoryExpression:dir}")
    private String remoteDirectoryExpression;

    @Bean
    public AmazonS3MessageHandler handle() {

        AWSCredentials credentials = new BasicAWSCredentials(this.accessKey, this.secretKey);

        AmazonS3MessageHandler handler = new AmazonS3MessageHandler(credentials, new DefaultAmazonS3Operations(credentials));
        handler.setBucket(bucket);
        handler.setRemoteDirectoryExpression(new LiteralExpression(remoteDirectoryExpression));
        return handler;
    }

    @Bean
    public IntegrationFlow flow() {
        return IntegrationFlows.from("input")
            .handle(handle())
            .get();
    }
}

I can successfully package up the module and deploy it. When trying to create the stream with:

xd:>stream create --name s3test --definition "file --outputType=text/plain --dir='/tmp/logs' | s3" --deploy

I get the following exception:

00:25:28,850 1.1.0.RC1  INFO DeploymentSupervisor-0 server.StreamDeploymentListener - Deployment status for stream 's3test': DeploymentStatus{state=failed,error(s)=org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flow' defined in com.test.xd.S3Module: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'flow' threw exception; nested exception is java.lang.ClassCastException: com.sun.proxy.$Proxy145 cannot be cast to org.springframework.integration.aws.s3.AmazonS3MessageHandler
...
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.integration.dsl.IntegrationFlow]: Factory method 'flow' threw exception; nested exception is java.lang.ClassCastException: com.sun.proxy.$Proxy145 cannot be cast to org.springframework.integration.aws.s3.AmazonS3MessageHandler
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 36 more
Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy145 cannot be cast to org.springframework.integration.aws.s3.AmazonS3MessageHandler
at com.test.xd.S3Module$$EnhancerBySpringCGLIB$$8623ddbe.handle(<generated>)
at com.test.xd.S3Module.flow(S3Module.java:49)
at com.test.xd.S3Module$$EnhancerBySpringCGLIB$$8623ddbe.CGLIB$flow$1(<generated>)
at com.test.xd.S3Module$$EnhancerBySpringCGLIB$$8623ddbe$$FastClassBySpringCGLIB$$3453fd21.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:309)
at com.test.xd.S3Module$$EnhancerBySpringCGLIB$$8623ddbe.flow(<generated>)
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:483)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 37 more

I'm fairly certain I'm missing something simple. Can someone point me in the right direction? Thanks in advance!

chadmaughan
  • 578
  • 1
  • 4
  • 12

1 Answers1

1

Thank you for doing such a work! Yes, definitely we'll introduce somedays out-of-the-box AWS modules to XD.

Your issue is similar to this one: https://github.com/spring-projects/spring-boot/issues/2441#issuecomment-72758919.

To overcome that you just should do:

@Bean
public MessageHandler handle() {

make return type as an interface not target class. That's because Spring Integration JMX exposing feature is switched on by default in XD.

Out of topic: we are going to break SI-AWS soon and make it based on the Spring Cloud AWS. And I think that that AWSCredentials stuff will be removed in favor of standard AWS CredentialsProvider. So, there will be a lot of breaking changes for the SI-AWS 1.0.0.

Artem Bilan
  • 113,505
  • 11
  • 91
  • 118
  • Thanks Artem, that was it! As a followup, I need to set the BeanFactory on the AmazonS3MessageHandler as well. In a Spring XD module (for integration adapters that require BeanFactory) how do I provide that? – chadmaughan Feb 04 '15 at 22:18
  • No need to do that manually! Since it is a `@Bean` Spring container takes of the infrastructure and invokes all those `ApplicationContextAware`, `BeanFactoryAware` etc. on the bean initialization phase. From other side you always can do `@Autowire` for any bean, including `BeanFactory`. – Artem Bilan Feb 05 '15 at 08:12