Skip to content

Commit 6dbb465

Browse files
committed
TypedValue implements equals/hashCode based on value and TypeDescriptor
Issue: SPR-11960 (cherry picked from commit a8848cb)
1 parent 47de943 commit 6dbb465

File tree

2 files changed

+42
-13
lines changed

2 files changed

+42
-13
lines changed

spring-expression/src/main/java/org/springframework/expression/TypedValue.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.expression;
1818

1919
import org.springframework.core.convert.TypeDescriptor;
20+
import org.springframework.util.ObjectUtils;
2021

2122
/**
2223
* Encapsulates an object and a type descriptor that describes it.
@@ -63,18 +64,35 @@ public Object getValue() {
6364
}
6465

6566
public TypeDescriptor getTypeDescriptor() {
66-
if (this.typeDescriptor == null) {
67+
if (this.typeDescriptor == null && this.value != null) {
6768
this.typeDescriptor = TypeDescriptor.forObject(this.value);
6869
}
6970
return this.typeDescriptor;
7071
}
7172

7273

74+
@Override
75+
public boolean equals(Object other) {
76+
if (this == other) {
77+
return true;
78+
}
79+
if (!(other instanceof TypedValue)) {
80+
return false;
81+
}
82+
TypedValue otherTv = (TypedValue) other;
83+
return (ObjectUtils.nullSafeEquals(this.value, otherTv.value) &&
84+
((this.typeDescriptor == null && otherTv.typeDescriptor == null) ||
85+
getTypeDescriptor().equals(otherTv.getTypeDescriptor())));
86+
}
87+
88+
@Override
89+
public int hashCode() {
90+
return ObjectUtils.nullSafeHashCode(this.value);
91+
}
92+
7393
@Override
7494
public String toString() {
75-
StringBuilder str = new StringBuilder();
76-
str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor()).append("]");
77-
return str.toString();
95+
return "TypedValue: '" + this.value + "' of [" + getTypeDescriptor() + "]";
7896
}
7997

8098
}

spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -97,9 +97,20 @@ public void testUtilities() throws ParseException {
9797

9898
@Test
9999
public void testTypedValue() {
100-
TypedValue tValue = new TypedValue("hello");
101-
assertEquals(String.class,tValue.getTypeDescriptor().getType());
102-
assertEquals("TypedValue: 'hello' of [java.lang.String]",tValue.toString());
100+
TypedValue tv1 = new TypedValue("hello");
101+
TypedValue tv2 = new TypedValue("hello");
102+
TypedValue tv3 = new TypedValue("bye");
103+
assertEquals(String.class, tv1.getTypeDescriptor().getType());
104+
assertEquals("TypedValue: 'hello' of [java.lang.String]", tv1.toString());
105+
assertEquals(tv1, tv2);
106+
assertEquals(tv2, tv1);
107+
assertNotEquals(tv1, tv3);
108+
assertNotEquals(tv2, tv3);
109+
assertNotEquals(tv3, tv1);
110+
assertNotEquals(tv3, tv2);
111+
assertEquals(tv1.hashCode(), tv2.hashCode());
112+
assertNotEquals(tv1.hashCode(), tv3.hashCode());
113+
assertNotEquals(tv2.hashCode(), tv3.hashCode());
103114
}
104115

105116
@Test
@@ -481,7 +492,7 @@ static class Unconvertable {}
481492
/**
482493
* Used to validate the match returned from a compareArguments call.
483494
*/
484-
private void checkMatch(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) {
495+
private void checkMatch(Class<?>[] inputTypes, Class<?>[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) {
485496
ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArguments(getTypeDescriptors(expectedTypes), getTypeDescriptors(inputTypes), typeConverter);
486497
if (expectedMatchKind == null) {
487498
assertNull("Did not expect them to match in any way", matchInfo);
@@ -504,7 +515,7 @@ else if (expectedMatchKind == ArgumentsMatchKind.REQUIRES_CONVERSION) {
504515
/**
505516
* Used to validate the match returned from a compareArguments call.
506517
*/
507-
private void checkMatch2(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) {
518+
private void checkMatch2(Class<?>[] inputTypes, Class<?>[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) {
508519
ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArgumentsVarargs(getTypeDescriptors(expectedTypes), getTypeDescriptors(inputTypes), typeConverter);
509520
if (expectedMatchKind == null) {
510521
assertNull("Did not expect them to match in any way: " + matchInfo, matchInfo);
@@ -535,9 +546,9 @@ private void checkArgument(Object expected, Object actual) {
535546
assertEquals(expected,actual);
536547
}
537548

538-
private List<TypeDescriptor> getTypeDescriptors(Class... types) {
549+
private List<TypeDescriptor> getTypeDescriptors(Class<?>... types) {
539550
List<TypeDescriptor> typeDescriptors = new ArrayList<TypeDescriptor>(types.length);
540-
for (Class type : types) {
551+
for (Class<?> type : types) {
541552
typeDescriptors.add(TypeDescriptor.valueOf(type));
542553
}
543554
return typeDescriptors;

0 commit comments

Comments
 (0)