Skip to content

Commit cc79f02

Browse files
authored
Fix NPE thrown from serializing/deserializing a structure that has map type with null values (#3138)
* Fix NPE thrown from serializing/deserializing a structure that has map type with null values * fix checkstyle
1 parent bbc1b3d commit cc79f02

File tree

9 files changed

+32
-14
lines changed

9 files changed

+32
-14
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"contributor": "",
4+
"type": "bugfix",
5+
"description": "Fix NPE thrown from serializing/deserializing a structure that has map type with null values"
6+
}

codegen/src/main/java/software/amazon/awssdk/codegen/poet/model/MemberCopierSpec.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,14 @@ private String copyMethodBody(CodeBlock.Builder code, BuilderTransform builderTr
245245
case BUILDER_TO_BUILDABLE:
246246
String buildableOutput = variableSource.getNew("member");
247247
TypeName buildableOutputType = typeName(inputMember, false, false, builderTransform, enumTransform);
248-
code.add("$T $N = $N.build();", buildableOutputType, buildableOutput, inputVariableName);
248+
code.add("$T $N = $N == null ? null : $N.build();", buildableOutputType, buildableOutput, inputVariableName,
249+
inputVariableName);
249250
return buildableOutput;
250251
case BUILDABLE_TO_BUILDER:
251252
String builderOutput = variableSource.getNew("member");
252253
TypeName builderOutputType = typeName(inputMember, false, false, builderTransform, enumTransform);
253-
code.add("$T $N = $N.toBuilder();", builderOutputType, builderOutput, inputVariableName);
254+
code.add("$T $N = $N == null ? null : $N.toBuilder();", builderOutputType, builderOutput, inputVariableName,
255+
inputVariableName);
254256
return builderOutput;
255257
default:
256258
throw new IllegalStateException();

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofmapofstringtostructcopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ static List<Map<String, SimpleStruct>> copyFromBuilder(
5555
} else {
5656
Map<String, SimpleStruct> modifiableMap = new LinkedHashMap<>();
5757
entry.forEach((key, value) -> {
58-
SimpleStruct member = value.build();
58+
SimpleStruct member = value == null ? null : value.build();
5959
modifiableMap.put(key, member);
6060
});
6161
map = Collections.unmodifiableMap(modifiableMap);
@@ -81,7 +81,7 @@ static List<Map<String, SimpleStruct.Builder>> copyToBuilder(
8181
} else {
8282
Map<String, SimpleStruct.Builder> modifiableMap = new LinkedHashMap<>();
8383
entry.forEach((key, value) -> {
84-
SimpleStruct.Builder member = value.toBuilder();
84+
SimpleStruct.Builder member = value == null ? null : value.toBuilder();
8585
modifiableMap.put(key, member);
8686
});
8787
map = Collections.unmodifiableMap(modifiableMap);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/listofsimplestructscopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static List<SimpleStruct> copyFromBuilder(Collection<? extends SimpleStruct.Buil
3333
} else {
3434
List<SimpleStruct> modifiableList = new ArrayList<>();
3535
listOfSimpleStructsParam.forEach(entry -> {
36-
SimpleStruct member = entry.build();
36+
SimpleStruct member = entry == null ? null : entry.build();
3737
modifiableList.add(member);
3838
});
3939
list = Collections.unmodifiableList(modifiableList);
@@ -48,7 +48,7 @@ static List<SimpleStruct.Builder> copyToBuilder(Collection<? extends SimpleStruc
4848
} else {
4949
List<SimpleStruct.Builder> modifiableList = new ArrayList<>();
5050
listOfSimpleStructsParam.forEach(entry -> {
51-
SimpleStruct.Builder member = entry.toBuilder();
51+
SimpleStruct.Builder member = entry == null ? null : entry.toBuilder();
5252
modifiableList.add(member);
5353
});
5454
list = Collections.unmodifiableList(modifiableList);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofenumtosimplestructcopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static Map<String, SimpleStruct> copyFromBuilder(Map<String, ? extends SimpleStr
3232
} else {
3333
Map<String, SimpleStruct> modifiableMap = new LinkedHashMap<>();
3434
mapOfEnumToSimpleStructParam.forEach((key, value) -> {
35-
SimpleStruct member = value.build();
35+
SimpleStruct member = value == null ? null : value.build();
3636
modifiableMap.put(key, member);
3737
});
3838
map = Collections.unmodifiableMap(modifiableMap);
@@ -47,7 +47,7 @@ static Map<String, SimpleStruct.Builder> copyToBuilder(Map<String, ? extends Sim
4747
} else {
4848
Map<String, SimpleStruct.Builder> modifiableMap = new LinkedHashMap<>();
4949
mapOfEnumToSimpleStructParam.forEach((key, value) -> {
50-
SimpleStruct.Builder member = value.toBuilder();
50+
SimpleStruct.Builder member = value == null ? null : value.toBuilder();
5151
modifiableMap.put(key, member);
5252
});
5353
map = Collections.unmodifiableMap(modifiableMap);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/mapofstringtosimplestructcopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ static Map<String, SimpleStruct> copyFromBuilder(Map<String, ? extends SimpleStr
3232
} else {
3333
Map<String, SimpleStruct> modifiableMap = new LinkedHashMap<>();
3434
mapOfStringToSimpleStructParam.forEach((key, value) -> {
35-
SimpleStruct member = value.build();
35+
SimpleStruct member = value == null ? null : value.build();
3636
modifiableMap.put(key, member);
3737
});
3838
map = Collections.unmodifiableMap(modifiableMap);
@@ -47,7 +47,7 @@ static Map<String, SimpleStruct.Builder> copyToBuilder(Map<String, ? extends Sim
4747
} else {
4848
Map<String, SimpleStruct.Builder> modifiableMap = new LinkedHashMap<>();
4949
mapOfStringToSimpleStructParam.forEach((key, value) -> {
50-
SimpleStruct.Builder member = value.toBuilder();
50+
SimpleStruct.Builder member = value == null ? null : value.toBuilder();
5151
modifiableMap.put(key, member);
5252
});
5353
map = Collections.unmodifiableMap(modifiableMap);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivelisttypecopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static List<RecursiveStructType> copyFromBuilder(Collection<? extends RecursiveS
3333
} else {
3434
List<RecursiveStructType> modifiableList = new ArrayList<>();
3535
recursiveListTypeParam.forEach(entry -> {
36-
RecursiveStructType member = entry.build();
36+
RecursiveStructType member = entry == null ? null : entry.build();
3737
modifiableList.add(member);
3838
});
3939
list = Collections.unmodifiableList(modifiableList);
@@ -48,7 +48,7 @@ static List<RecursiveStructType.Builder> copyToBuilder(Collection<? extends Recu
4848
} else {
4949
List<RecursiveStructType.Builder> modifiableList = new ArrayList<>();
5050
recursiveListTypeParam.forEach(entry -> {
51-
RecursiveStructType.Builder member = entry.toBuilder();
51+
RecursiveStructType.Builder member = entry == null ? null : entry.toBuilder();
5252
modifiableList.add(member);
5353
});
5454
list = Collections.unmodifiableList(modifiableList);

codegen/src/test/resources/software/amazon/awssdk/codegen/poet/model/recursivemaptypecopier.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static Map<String, RecursiveStructType> copyFromBuilder(
3333
} else {
3434
Map<String, RecursiveStructType> modifiableMap = new LinkedHashMap<>();
3535
recursiveMapTypeParam.forEach((key, value) -> {
36-
RecursiveStructType member = value.build();
36+
RecursiveStructType member = value == null ? null : value.build();
3737
modifiableMap.put(key, member);
3838
});
3939
map = Collections.unmodifiableMap(modifiableMap);
@@ -48,7 +48,7 @@ static Map<String, RecursiveStructType.Builder> copyToBuilder(Map<String, ? exte
4848
} else {
4949
Map<String, RecursiveStructType.Builder> modifiableMap = new LinkedHashMap<>();
5050
recursiveMapTypeParam.forEach((key, value) -> {
51-
RecursiveStructType.Builder member = value.toBuilder();
51+
RecursiveStructType.Builder member = value == null ? null : value.toBuilder();
5252
modifiableMap.put(key, member);
5353
});
5454
map = Collections.unmodifiableMap(modifiableMap);

test/codegen-generated-classes-test/src/test/java/software/amazon/awssdk/services/ModelSerializationTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import com.fasterxml.jackson.databind.module.SimpleModule;
3030
import java.io.IOException;
3131
import java.time.Instant;
32+
import java.util.HashMap;
33+
import java.util.Map;
3234
import org.junit.jupiter.api.Test;
3335
import software.amazon.awssdk.core.SdkBytes;
3436
import software.amazon.awssdk.services.protocolrestjson.model.AllTypesRequest;
@@ -48,6 +50,14 @@ public void jacksonSerializationWorksForEmptyRequestObjects() throws IOException
4850
validateJacksonSerialization(AllTypesRequest.builder().build());
4951
}
5052

53+
@Test
54+
public void jacksonSerialization_mapWithNullValue_shouldWork() throws IOException {
55+
Map<String, SimpleStruct> mapOfStringToStruct = new HashMap<>();
56+
mapOfStringToStruct.put("test1", null);
57+
mapOfStringToStruct.put("test2", null);
58+
validateJacksonSerialization(AllTypesRequest.builder().mapOfStringToStruct(mapOfStringToStruct).build());
59+
}
60+
5161
@Test
5262
public void jacksonSerializationWorksForPopulatedRequestModels() throws IOException {
5363
SdkBytes blob = SdkBytes.fromUtf8String("foo");

0 commit comments

Comments
 (0)