Issue
I am creating a Spring application where in it calls information from the AWS API and converts it to JSON for a front end application to digest and display. I am currently trying to return a list out all of the current S3 buckets on an account but am running into an issue where the JSON response is:
status": 500, "error": "Internal Server Error", "message": "Type definition error: [simple type, class software.amazon.awssdk.services.s3.model.Bucket]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class software.amazon.awssdk.services.s3.model.Bucket and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.landsend.clouddashboard.data.Class.S3[\"bucketList\"]-java.util.Collections$UnmodifiableRandomAccessList[0])", "path": "/api/s3/buckets"
I have created a class called S3 that has private variables. One of them being a List type with the name bucketList. This class has the representative getters and setters as well associated with those variables.
I have also tried adding this to the applications.properties file:
spring.jackson.serialization.FAIL_ON_EMPTY_BEANS=false
This did result in the error disappearing but I ended up with an empty JSON file.
Controller Class
@RestController
@RequestMapping(value="/api")
public class S3Controller {
@Autowired
private S3Service s3Service;
@RequestMapping(method= RequestMethod.GET, value="/s3/buckets")
public S3 ListBuckets(){
return s3Service.listBucket();
}
}
Service Class
@Service
public class S3Service {
private S3Access s3Access;
@Autowired
public S3Service(S3Access s3Access){
this.s3Access = s3Access;
}
public S3 listBucket(){
//Any Additional business logic would go here
return s3Access.listBucket();
}
}
Access Class
@Repository
public class S3Access implements S3Repository {
@Autowired
private S3 s3Instance;
private Region region = Region.US_EAST_1;
private S3Client s3Client =
S3Client.builder().region(region).build();
@Override
public S3 listBucket() {
ListBucketsRequest listBucketsRequest = ListBucketsRequest.builder().build();
ListBucketsResponse listBucketsResponse = s3Client.listBuckets(listBucketsRequest);
s3Instance.setBucketList(listBucketsResponse.buckets());
return s3Instance;
}
}
S3 Constructor Class
@Component
public class S3 {
private String fileName;
private String bucketName;
private int bucketSize;
private List<Bucket> bucketList;
public List<Bucket> getBucketList() {
return bucketList;
}
public void setBucketList(List<Bucket> bucketList) {
this.bucketList = bucketList;
}
}
Any thoughts on why this isn't working is appreciated.
Solution
Problem is with Bucket class. Jackson
by default treats all provided objects like POJO
-s. Each POJO
should have list of getters
/setters
. In case, class does not have them object is treated as empty. If you want to serialise classes like this you can:
- Create extra
POJO
class withgetters
and map it from rawAWS
class to thisPOJO
. - Implement and register serialiser for this class.
- Convert
AWS
model toMap
-s andList
-s manually and serialise them.
See also:
Answered By - MichaĆ Ziober
Answer Checked By - David Marino (JavaFixing Volunteer)