Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cannot be cast to org.springframework.core.io.WritableResource on Spring AWS example

I'm reading this documentation:

http://cloud.spring.io/spring-cloud-aws/spring-cloud-aws.html

on using AWS from a Spring application. I'm particularly interested in S3, so, I set up the application and copied this snippet of code to make sure the set up is working correctly:

Resource resource = this.resourceLoader.getResource("s3://myBucket/rootFile.log");
WritableResource writableResource = (WritableResource) resource;
try (OutputStream outputStream = writableResource.getOutputStream()) {
  outputStream.write("test".getBytes());
}

but when I run it, I get this error:

java.lang.ClassCastException: org.springframework.web.context.support.ServletContextResource cannot be cast to org.springframework.core.io.WritableResource

Any ideas what's wrong? is that a setup problem? It doesn't look like to me, but I'm new to this.

like image 861
pupeno Avatar asked Nov 06 '17 10:11

pupeno


2 Answers

I had to remove

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
</dependency>

from my dependencies.

When devtools is included, inside the GenericApplicationContext.getResources() method it executes the if block, but without devtools it calls the super.getResource():

public Resource getResource(String location) {
    if (this.resourceLoader != null) {
        return this.resourceLoader.getResource(location);
    }
    return super.getResource(location);
}

This will use the s3 protocol handler and give you a different type of Resource that does implement WritableResource.

like image 75
accresse Avatar answered Oct 16 '22 16:10

accresse


I've tried to follow the solution proposed by @accresse, but without success. My only way of solving it was declaring a new SimpleStorageProtocolResolver and adding it as a ProtocolResolver to the DefaultResourceLoader. Using Spring Boot 2.1.7 e Spring Cloud Aws 2.1.4.

@Autowired
public void configureResourceLoader(AmazonS3 amazonS3, DefaultResourceLoader resourceLoader) {
    SimpleStorageProtocolResolver simpleStorageProtocolResolver = new SimpleStorageProtocolResolver(amazonS3);
    // As we are calling it by hand, we must initialize it properly.
    simpleStorageProtocolResolver.afterPropertiesSet();
    resourceLoader.addProtocolResolver(simpleStorageProtocolResolver);
}

Links to follow:

  • https://github.com/spring-cloud/spring-cloud-aws/issues/348
  • https://github.com/spring-cloud/spring-cloud-aws/issues/384
  • https://github.com/spring-projects/spring-boot/issues/9331
like image 26
Felipe Desiderati Avatar answered Oct 16 '22 16:10

Felipe Desiderati