Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"type": "bugfix",
"category": "Amazon DynamoDB Enhanced Client",
"contributor": "",
"description": "Fix NullPointerException in `EnhancedType.hashCode()`, `EnhancedType.equals()`, and `EnhancedType.toString()` when using wildcard types."
}
Original file line number Diff line number Diff line change
Expand Up @@ -541,14 +541,17 @@ private List<EnhancedType<?>> loadTypeParameters(Type type) {

private StringBuilder innerToString() {
StringBuilder result = new StringBuilder();
result.append(rawClass.getTypeName());
if (isWildcard) {
result.append("?");
} else {
result.append(rawClass.getTypeName());

if (null != rawClassParameters && !rawClassParameters.isEmpty()) {
result.append("<");
result.append(rawClassParameters.stream().map(EnhancedType::innerToString).collect(Collectors.joining(", ")));
result.append(">");
if (null != rawClassParameters && !rawClassParameters.isEmpty()) {
result.append("<");
result.append(rawClassParameters.stream().map(EnhancedType::innerToString).collect(Collectors.joining(", ")));
result.append(">");
}
}

return result;
}

Expand All @@ -566,7 +569,7 @@ public boolean equals(Object o) {
if (isWildcard != enhancedType.isWildcard) {
return false;
}
if (!rawClass.equals(enhancedType.rawClass)) {
if (rawClass != null ? !rawClass.equals(enhancedType.rawClass) : enhancedType.rawClass != null) {
return false;
}
if (rawClassParameters != null ? !rawClassParameters.equals(enhancedType.rawClassParameters) :
Expand All @@ -584,7 +587,7 @@ public boolean equals(Object o) {
@Override
public int hashCode() {
int result = (isWildcard ? 1 : 0);
result = 31 * result + rawClass.hashCode();
result = 31 * result + (rawClass != null ? rawClass.hashCode() : 0);
result = 31 * result + (rawClassParameters != null ? rawClassParameters.hashCode() : 0);
result = 31 * result + (tableSchema != null ? tableSchema.hashCode() : 0);
result = 31 * result + (documentConfiguration != null ? documentConfiguration.hashCode() : 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,57 @@
assertThat(type.documentConfiguration().get().preserveEmptyObject()).isTrue();
}

@Test
public void wildcardType_hashCode_doesNotRaiseNPE() {

Check warning on line 243 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyih&open=AZz4HiqSbxxwzGFwfyih&pullRequest=6745
// When using a wildcard type like List<?>, the type parameter is a wildcard
// with rawClass = null. hashCode() should handle this without NPE.
EnhancedType<List<?>> listWithWildcard = new EnhancedType<List<?>>(){};
EnhancedType<?> wildcardParam = listWithWildcard.rawClassParameters().get(0);

// This should not throw NPE
assertThatCode(() -> wildcardParam.hashCode()).doesNotThrowAnyException();

Check warning on line 250 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this lambda with method reference 'wildcardParam::hashCode'.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyik&open=AZz4HiqSbxxwzGFwfyik&pullRequest=6745
}

@Test
public void wildcardType_equals_handlesNullRawClass() {

Check warning on line 254 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyii&open=AZz4HiqSbxxwzGFwfyii&pullRequest=6745
// Wildcard types should be comparable via equals without NPE
EnhancedType<List<?>> listWithWildcard1 = new EnhancedType<List<?>>(){};
EnhancedType<List<?>> listWithWildcard2 = new EnhancedType<List<?>>(){};

EnhancedType<?> wildcard1 = listWithWildcard1.rawClassParameters().get(0);
EnhancedType<?> wildcard2 = listWithWildcard2.rawClassParameters().get(0);

// Wildcards should be equal to each other
assertThat(wildcard1).isEqualTo(wildcard2);
assertThat(wildcard1.hashCode()).isEqualTo(wildcard2.hashCode());

Check warning on line 264 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use assertThat(actual).hasSameHashCodeAs(expected) instead.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyil&open=AZz4HiqSbxxwzGFwfyil&pullRequest=6745
}

@Test
public void wildcardType_equals_notEqualToNonWildcard() {

Check warning on line 268 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz8qwuObE8dfXhDVL55&open=AZz8qwuObE8dfXhDVL55&pullRequest=6745
// A wildcard type (rawClass=null) should not be equal to a non-wildcard type (rawClass!=null)
EnhancedType<List<?>> listWithWildcard = new EnhancedType<List<?>>(){};
EnhancedType<?> wildcardType = listWithWildcard.rawClassParameters().get(0);
EnhancedType<String> nonWildcardType = EnhancedType.of(String.class);

// Wildcard vs non-wildcard should not be equal (tests both comparison directions)
assertThat(wildcardType).isNotEqualTo(nonWildcardType);
assertThat(nonWildcardType).isNotEqualTo(wildcardType);
}

@Test
public void wildcardType_toString_doesNotRaiseNPE() {

Check warning on line 280 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this 'public' modifier.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyij&open=AZz4HiqSbxxwzGFwfyij&pullRequest=6745
// Wildcard types should be convertible to string without NPE
EnhancedType<List<?>> listWithWildcard = new EnhancedType<List<?>>(){};
EnhancedType<?> wildcardParam = listWithWildcard.rawClassParameters().get(0);

// This should not throw NPE and should return "?" for wildcard
assertThatCode(() -> wildcardParam.toString()).doesNotThrowAnyException();

Check warning on line 286 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this lambda with method reference 'wildcardParam::toString'.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyim&open=AZz4HiqSbxxwzGFwfyim&pullRequest=6745
assertThat(wildcardParam.toString()).isEqualTo("EnhancedType(?)");

Check warning on line 287 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use assertThat(actual).hasToString(expectedString) instead.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyin&open=AZz4HiqSbxxwzGFwfyin&pullRequest=6745

// Also verify that the parent type renders correctly with wildcard
assertThat(listWithWildcard.toString()).isEqualTo("EnhancedType(java.util.List<?>)");

Check warning on line 290 in services-custom/dynamodb-enhanced/src/test/java/software/amazon/awssdk/enhanced/dynamodb/EnhancedTypeTest.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Use assertThat(actual).hasToString(expectedString) instead.

See more on https://sonarcloud.io/project/issues?id=aws_aws-sdk-java-v2&issues=AZz4HiqSbxxwzGFwfyio&open=AZz4HiqSbxxwzGFwfyio&pullRequest=6745
}

public class InnerType {
}

Expand Down
Loading