Search code examples
javaspringamazon-s3vaadinvaadin24

How to connect Vaadin UI to Amazon S3 Service in Spring?


I am building a web interface using Vaadin that displays the list of objects that I have in my Amazon S3 Bucket in a Vaadin Grid component. My service works fine but I get a NullPointerException every time I try to add the list of objects from my S3 Service to the grid.

Here is the S3 Service: S3 Service

I tested my service using the spring CommandLineRunner interface on a test class. Here is the test class: Test Class

Whenever I run the application, I see the list of items in my S3 Bucket listed on the console: Console Output

But the same service throws a NullPointerException on the browser whenever i try to add the list items to the Vaadin Grid and a BeanCreationException gets logged on the console:

BeanCreationException NullPointerException

Here is S3Service.java

@Service
public class S3Service {
    @Autowired
    private AmazonS3 s3Client;
    @Value("${aws.s3.bucket.name}")
    private String bucketName;
    public List<String> listObjects() {
        ObjectListing objectListing=s3Client.listObjects(bucketName);
        return objectListing.getObjectSummaries()
                .stream()
                .map(S3ObjectSummary::getKey)
                .collect(Collectors.toList());
    }
}

TestFeatureClass.java

@Component
public class TestFeatureClass implements CommandLineRunner {
    @Autowired
    private S3Service s3Service;
    @Override
    public void run(String... args) throws Exception {
        System.out.println(s3Service.listObjects());
    }
}

DocumentManagementSystemView.java

@PageTitle("Documents")
@Route(value = "api/v1/files/list",layout = MainLayout.class)
@Uses(Icon.class)
public class DocumentManagementSystemView extends VerticalLayout {
    @Autowired
    public S3Service s3Service;
    Grid<String> grid;
    public DocumentManagementSystemView() {

        this.grid=new Grid<>(String.class,false);
        configureGrid();

        add(grid);
        updateList();

    }
    private void configureGrid() {
        grid.setColumns("Filename");
    }
    private void updateList() {
        grid.setItems(s3Service.listObjects());
    }
}

Solution

  • First issue I see is that you should use constructor-injection instead of field-injection, if you intend to use the injected bean during constructor. This should fix your NullPointerException.

    @PageTitle("Documents")
    @Route(value = "api/v1/files/list",layout = MainLayout.class)
    @Uses(Icon.class)
    public class DocumentManagementSystemView extends VerticalLayout {
        
        private S3Service s3Service;
        private Grid<String> grid;
        
        public DocumentManagementSystemView(S3Service s3Service) {
            this.s3Service = s3Service;
            ...
        }
    }
    

    Second issue I see is that you use grid.setColumns("Filename") on a Grid of type String. This will try to find a property called 'Filename' in the String class and render that in the column. I assume you wanted a column with the header "Filename". Since the Grid is of Type String, and you want to display that string in this column, you should provide a valueprovider that returns the whole item/string: str -> str or Function.identity() they are basically the same thing, you choose whichever is more readable to you. more info

    grid.addColumn(str -> str).setHeader("Filename");