From 6dbb46558547f72fe86781764ae7a086396c6322 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 7 Jul 2014 11:29:29 +0200 Subject: [PATCH] TypedValue implements equals/hashCode based on value and TypeDescriptor Issue: SPR-11960 (cherry picked from commit a8848cb) --- .../expression/TypedValue.java | 28 +++++++++++++++---- .../spel/support/ReflectionHelperTests.java | 27 ++++++++++++------ 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java index 96dc6124cad..cca3cd24f16 100644 --- a/spring-expression/src/main/java/org/springframework/expression/TypedValue.java +++ b/spring-expression/src/main/java/org/springframework/expression/TypedValue.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.expression; import org.springframework.core.convert.TypeDescriptor; +import org.springframework.util.ObjectUtils; /** * Encapsulates an object and a type descriptor that describes it. @@ -63,18 +64,35 @@ public class TypedValue { } public TypeDescriptor getTypeDescriptor() { - if (this.typeDescriptor == null) { + if (this.typeDescriptor == null && this.value != null) { this.typeDescriptor = TypeDescriptor.forObject(this.value); } return this.typeDescriptor; } + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (!(other instanceof TypedValue)) { + return false; + } + TypedValue otherTv = (TypedValue) other; + return (ObjectUtils.nullSafeEquals(this.value, otherTv.value) && + ((this.typeDescriptor == null && otherTv.typeDescriptor == null) || + getTypeDescriptor().equals(otherTv.getTypeDescriptor()))); + } + + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(this.value); + } + @Override public String toString() { - StringBuilder str = new StringBuilder(); - str.append("TypedValue: '").append(this.value).append("' of [").append(getTypeDescriptor()).append("]"); - return str.toString(); + return "TypedValue: '" + this.value + "' of [" + getTypeDescriptor() + "]"; } } diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java index 32447dda910..4b9aee60494 100644 --- a/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java +++ b/spring-expression/src/test/java/org/springframework/expression/spel/support/ReflectionHelperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,9 +97,20 @@ public class ReflectionHelperTests extends AbstractExpressionTests { @Test public void testTypedValue() { - TypedValue tValue = new TypedValue("hello"); - assertEquals(String.class,tValue.getTypeDescriptor().getType()); - assertEquals("TypedValue: 'hello' of [java.lang.String]",tValue.toString()); + TypedValue tv1 = new TypedValue("hello"); + TypedValue tv2 = new TypedValue("hello"); + TypedValue tv3 = new TypedValue("bye"); + assertEquals(String.class, tv1.getTypeDescriptor().getType()); + assertEquals("TypedValue: 'hello' of [java.lang.String]", tv1.toString()); + assertEquals(tv1, tv2); + assertEquals(tv2, tv1); + assertNotEquals(tv1, tv3); + assertNotEquals(tv2, tv3); + assertNotEquals(tv3, tv1); + assertNotEquals(tv3, tv2); + assertEquals(tv1.hashCode(), tv2.hashCode()); + assertNotEquals(tv1.hashCode(), tv3.hashCode()); + assertNotEquals(tv2.hashCode(), tv3.hashCode()); } @Test @@ -481,7 +492,7 @@ public class ReflectionHelperTests extends AbstractExpressionTests { /** * Used to validate the match returned from a compareArguments call. */ - private void checkMatch(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) { + private void checkMatch(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) { ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArguments(getTypeDescriptors(expectedTypes), getTypeDescriptors(inputTypes), typeConverter); if (expectedMatchKind == null) { assertNull("Did not expect them to match in any way", matchInfo); @@ -504,7 +515,7 @@ public class ReflectionHelperTests extends AbstractExpressionTests { /** * Used to validate the match returned from a compareArguments call. */ - private void checkMatch2(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) { + private void checkMatch2(Class[] inputTypes, Class[] expectedTypes, StandardTypeConverter typeConverter, ArgumentsMatchKind expectedMatchKind) { ReflectionHelper.ArgumentsMatchInfo matchInfo = ReflectionHelper.compareArgumentsVarargs(getTypeDescriptors(expectedTypes), getTypeDescriptors(inputTypes), typeConverter); if (expectedMatchKind == null) { assertNull("Did not expect them to match in any way: " + matchInfo, matchInfo); @@ -535,9 +546,9 @@ public class ReflectionHelperTests extends AbstractExpressionTests { assertEquals(expected,actual); } - private List getTypeDescriptors(Class... types) { + private List getTypeDescriptors(Class... types) { List typeDescriptors = new ArrayList(types.length); - for (Class type : types) { + for (Class type : types) { typeDescriptors.add(TypeDescriptor.valueOf(type)); } return typeDescriptors;