From 97ebfe9556788a68e27e66a08b0a30081e7d91b5 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:07:15 -0500 Subject: [PATCH 01/11] feat(s3): added new method in LegacyJackson2JsonS3ObjectConverter Added a new method to read S3 objects using TypeReference. --- .../LegacyJackson2JsonS3ObjectConverter.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java index 3afe3a39a..8a1573458 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java @@ -16,6 +16,7 @@ package io.awspring.cloud.s3; import com.fasterxml.jackson.core.JacksonException; +import com.fasterxml.jackson.core..type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; @@ -60,6 +61,24 @@ public T read(InputStream is, Class clazz) { } } + /** + * Reads S3 object from the input stream into a Java object. + * @param is - the input stream + * @param valueTypeRef - the type reference + * @param - the the type of the object + * @return deserialized object + */ + public T read(InputStream is, TypeReference valueTypeRef) { + Assert.notNull(is, "InputStream is required"); + Assert.notNull(valueTypeRef, "ValueTypeRef is required"); + try { + return objectMapper.readValue(is, valueTypeRef); + } + catch (IOException e) { + throw new S3Exception("Failed to deserialize object from JSON", e); + } + } + @Override public String contentType() { return "application/json"; From 3dddaa466a5cd32f1b2e19ec5bb4e0a29de62ef1 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:08:59 -0500 Subject: [PATCH 02/11] feat(s3): added new method in Jackson2JsonS3ObjectConverter Added a new method to read S3 objects from an InputStream using a TypeReference. --- .../s3/Jackson2JsonS3ObjectConverter.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java index c04671ac2..76001511e 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java @@ -19,6 +19,7 @@ import org.springframework.util.Assert; import software.amazon.awssdk.core.sync.RequestBody; import tools.jackson.core.JacksonException; +import tools.jackson.core.type.TypeReference; import tools.jackson.databind.json.JsonMapper; /** @@ -58,6 +59,25 @@ public T read(InputStream is, Class clazz) { } } + /** + * Reads S3 object from the input stream into a Java object. + * @param is - the input stream + * @param valueTypeRef - the type reference + * @param - the the type of the object + * @return deserialized object + */ + public T read(InputStream is, TypeReference valueTypeRef) { + Assert.notNull(is, "InputStream is required"); + Assert.notNull(valueTypeRef, "ValueTypeRef is required"); + try { + return jsonMapper.readValue(is, valueTypeRef); + } + catch (IOException e) { + throw new S3Exception("Failed to deserialize object from JSON", e); + } + } + + @Override public String contentType() { return "application/json"; From bb98a89c94bcdb3ecb039a2a939f63d52fc4daa8 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:28:59 -0500 Subject: [PATCH 03/11] feat(s3): Add read method with ParameterizedTypeReference support Added a new method to read objects using ParameterizedTypeReference. --- .../main/java/io/awspring/cloud/s3/S3Operations.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java index 0fca61e3e..288914336 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java @@ -132,6 +132,17 @@ public interface S3Operations { */ T read(String bucketName, String key, Class clazz); + /** + * Reads a Java object from a S3 bucket. Uses {@link S3ObjectConverter} for deserialization. + * + * @param bucketName - the bucket name + * @param key - the object key + * @param valueTypeRef - the parameterized type reference of the read object + * @param - the type of the read object + * @return an object + */ + T read(String bucketName, String key, ParameterizedTypeReference valueTypeRef); + /** * Uploads data from an input stream to a S3 bucket. * From 7c9d3cca49cb979f1cfc6f12e3ed459c9abad7da Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:31:39 -0500 Subject: [PATCH 04/11] feat(s3): Implement ParameterizedTypeReference read method for S3 object retrieval Add a read method to retrieve typed objects from S3 --- .../java/io/awspring/cloud/s3/S3Template.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Template.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Template.java index 92194bc14..0de9942cf 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Template.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Template.java @@ -21,6 +21,7 @@ import java.time.Duration; import java.util.List; import org.jspecify.annotations.Nullable; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.util.Assert; import org.springframework.util.StreamUtils; import software.amazon.awssdk.services.s3.S3Client; @@ -165,6 +166,21 @@ public T read(String bucketName, String key, Class clazz) { } } + @Override + public T read(String bucketName, String key, ParameterizedTypeReference valueTypeRef) { + Assert.notNull(bucketName, "bucketName is required"); + Assert.notNull(key, "key is required"); + Assert.notNull(valueTypeRef, "valueTypeRef is required"); + + try (InputStream is = s3Client.getObject(r -> r.bucket(bucketName).key(key))) { + return s3ObjectConverter.read(is, valueTypeRef); + } + catch (Exception e) { + throw new S3Exception( + String.format("Failed to read object with a key '%s' from bucket '%s'", key, bucketName), e); + } + } + @Override public S3Resource upload(String bucketName, String key, InputStream inputStream, @Nullable ObjectMetadata objectMetadata) { From 951da1569c768b0a59a0a64b2db883e3aad0a18b Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:32:20 -0500 Subject: [PATCH 05/11] fix: Added import for ParameterizedTypeReference --- .../src/main/java/io/awspring/cloud/s3/S3Operations.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java index 288914336..ecb60bc30 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3Operations.java @@ -20,6 +20,7 @@ import java.time.Duration; import java.util.List; import org.jspecify.annotations.Nullable; +import org.springframework.core.ParameterizedTypeReference; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.CreateBucketResponse; From 075a495a300d19be32b9ad8f9b22fc1ca0f0e4db Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:34:25 -0500 Subject: [PATCH 06/11] feat(s3): Add read method definition with ParameterizedTypeReference Added a method definition to convert S3 objects using ParameterizedTypeReference. --- .../java/io/awspring/cloud/s3/S3ObjectConverter.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3ObjectConverter.java index ed4b3ebe3..aece7873f 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/S3ObjectConverter.java @@ -16,6 +16,7 @@ package io.awspring.cloud.s3; import java.io.InputStream; +import org.springframework.core.ParameterizedTypeReference; import software.amazon.awssdk.core.sync.RequestBody; /** @@ -43,6 +44,15 @@ public interface S3ObjectConverter { */ T read(InputStream is, Class clazz); + /** + * Reads S3 object from the input stream into a Java object. + * @param is - the input stream + * @param valueTypeRef - the type reference of the object + * @param - the the type of the object + * @return deserialized object + */ + T read(InputStream is, ParameterizedTypeReference valueTypeRef); + /** * Supported content type. * From f2756f0bde4806a4e03e35bb9553fd04864c0de9 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:37:07 -0500 Subject: [PATCH 07/11] Refactor read method to use ParametrizedTypeReference --- .../cloud/s3/Jackson2JsonS3ObjectConverter.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java index 76001511e..43f12c8c0 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java @@ -17,6 +17,7 @@ import java.io.InputStream; import org.springframework.util.Assert; +import org.springframework.core.ParametrizedTypeReference; import software.amazon.awssdk.core.sync.RequestBody; import tools.jackson.core.JacksonException; import tools.jackson.core.type.TypeReference; @@ -59,18 +60,12 @@ public T read(InputStream is, Class clazz) { } } - /** - * Reads S3 object from the input stream into a Java object. - * @param is - the input stream - * @param valueTypeRef - the type reference - * @param - the the type of the object - * @return deserialized object - */ - public T read(InputStream is, TypeReference valueTypeRef) { + @Override + public T read(InputStream is, ParametrizedTypeReference valueTypeRef) { Assert.notNull(is, "InputStream is required"); - Assert.notNull(valueTypeRef, "ValueTypeRef is required"); + Assert.notNull(valueTypeRef, "valueTypeRef is required"); try { - return jsonMapper.readValue(is, valueTypeRef); + return jsonMapper.readValue(is, jsonMapper.constructType(valueTypeRef.getType())); } catch (IOException e) { throw new S3Exception("Failed to deserialize object from JSON", e); From 1e4c05ac80bfb9025d688721514b749c1870f93c Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:38:02 -0500 Subject: [PATCH 08/11] Refactor read method to use ParameterizedTypeReference --- .../s3/LegacyJackson2JsonS3ObjectConverter.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java index 8a1573458..bea5de8cc 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/LegacyJackson2JsonS3ObjectConverter.java @@ -16,11 +16,11 @@ package io.awspring.cloud.s3; import com.fasterxml.jackson.core.JacksonException; -import com.fasterxml.jackson.core..type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; import org.springframework.util.Assert; +import org.springframework.core.ParameterizedTypeReference; import software.amazon.awssdk.core.sync.RequestBody; /** @@ -61,18 +61,12 @@ public T read(InputStream is, Class clazz) { } } - /** - * Reads S3 object from the input stream into a Java object. - * @param is - the input stream - * @param valueTypeRef - the type reference - * @param - the the type of the object - * @return deserialized object - */ - public T read(InputStream is, TypeReference valueTypeRef) { + @Override + public T read(InputStream is, ParametrizedTypeReference valueTypeRef) { Assert.notNull(is, "InputStream is required"); - Assert.notNull(valueTypeRef, "ValueTypeRef is required"); + Assert.notNull(valueTypeRef, "valueTypeRef is required"); try { - return objectMapper.readValue(is, valueTypeRef); + return objectMapper.readValue(is, objectMapper.constructType(valueTypeRef.getType())); } catch (IOException e) { throw new S3Exception("Failed to deserialize object from JSON", e); From dba0eba6a95b184079a7287cad7550a25b0cd86a Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 17:59:34 -0500 Subject: [PATCH 09/11] Updated S3TemplateIntegrationTests.java --- .../cloud/s3/S3TemplateIntegrationTests.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java index 6517a15ef..41b35f21d 100644 --- a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java +++ b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java @@ -232,6 +232,20 @@ void readsObject() { assertThat(person.lastName).isEqualTo("Doe"); } + @Test + void readsParameterizedTypeObject() { + client.putObject(r -> r.bucket(BUCKET_NAME).key("persons.json"), + RequestBody.fromString("[{\"firstName\":\"John\",\"lastName\":\"Doe\"}]")); + + List persons = s3Template.read(BUCKET_NAME, "persons.json", new ParamaterizedTypeReference>(){}); + + assertThat(persons.size()).isEqualTo(1); + + Person person = persons.get(0); + assertThat(person.firstName).isEqualTo("John"); + assertThat(person.lastName).isEqualTo("Doe"); + } + @Test void uploadsFile() throws IOException { try (InputStream is = new ByteArrayInputStream("hello".getBytes(StandardCharsets.UTF_8))) { From 2354a40a696273f752bcad378e9f743188d986c0 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:00:12 -0500 Subject: [PATCH 10/11] Update S3TemplateIntegrationTests.java --- .../java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java | 1 + 1 file changed, 1 insertion(+) diff --git a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java index 41b35f21d..fff53ccbc 100644 --- a/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java +++ b/spring-cloud-aws-s3/src/test/java/io/awspring/cloud/s3/S3TemplateIntegrationTests.java @@ -41,6 +41,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.util.StreamUtils; +import org.springframework.core.ParameterizedTypeReference; import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.http.HttpStatusCode; From bf2a53556f9aa3f237e15a1cdecbeec4420f6c82 Mon Sep 17 00:00:00 2001 From: Hayden <55563292+Hayden-J-C@users.noreply.github.com> Date: Mon, 26 Jan 2026 18:17:17 -0500 Subject: [PATCH 11/11] Remove unused TypeReference import Removed unused import for TypeReference. --- .../java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java index 43f12c8c0..e4e08558d 100644 --- a/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java +++ b/spring-cloud-aws-s3/src/main/java/io/awspring/cloud/s3/Jackson2JsonS3ObjectConverter.java @@ -20,7 +20,6 @@ import org.springframework.core.ParametrizedTypeReference; import software.amazon.awssdk.core.sync.RequestBody; import tools.jackson.core.JacksonException; -import tools.jackson.core.type.TypeReference; import tools.jackson.databind.json.JsonMapper; /**