Skip to content

Commit 8a9f43b

Browse files
committed
Added @IgnoreDefaultEqualsAndToString annotation that allows by-pass Groovy equals and toString methods for Map and Collection objects
1 parent 5492f93 commit 8a9f43b

File tree

5 files changed

+143
-0
lines changed

5 files changed

+143
-0
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package groovy.lang;
21+
22+
import java.lang.annotation.ElementType;
23+
import java.lang.annotation.Retention;
24+
import java.lang.annotation.RetentionPolicy;
25+
import java.lang.annotation.Target;
26+
27+
/**
28+
* Classes marked with this {@link IgnoreDefaultEqualsAndToString} annotation
29+
* by-pass the default groovy formatting and equality rules and allowing
30+
* a user to provide a custom format and equals method
31+
*
32+
* @author Paolo Di Tommaso <[email protected]>
33+
*/
34+
@Retention(RetentionPolicy.RUNTIME)
35+
@Target({ElementType.TYPE})
36+
public @interface IgnoreDefaultEqualsAndToString {
37+
}

src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12026,6 +12026,9 @@ public static boolean equals(List left, List right) {
1202612026
if (left == right) {
1202712027
return true;
1202812028
}
12029+
if( left.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null && right.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null ) {
12030+
return left.equals(right);
12031+
}
1202912032
if (left.size() != right.size()) {
1203012033
return false;
1203112034
}
@@ -12078,6 +12081,9 @@ public static <T> boolean equals(Set<T> self, Set<T> other) {
1207812081
if (self == other) {
1207912082
return true;
1208012083
}
12084+
if( self.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null && other.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null ) {
12085+
return self.equals(other);
12086+
}
1208112087
if (self.size() != other.size()) {
1208212088
return false;
1208312089
}
@@ -12122,6 +12128,9 @@ public static boolean equals(Map self, Map other) {
1212212128
if (self == other) {
1212312129
return true;
1212412130
}
12131+
if( self.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null && other.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null ) {
12132+
return self.equals(other);
12133+
}
1212512134
if (self.size() != other.size()) {
1212612135
return false;
1212712136
}

src/main/org/codehaus/groovy/runtime/InvokerHelper.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import groovy.lang.GroovyObject;
2626
import groovy.lang.GroovyRuntimeException;
2727
import groovy.lang.GroovySystem;
28+
import groovy.lang.IgnoreDefaultEqualsAndToString;
2829
import groovy.lang.MetaClass;
2930
import groovy.lang.MetaClassRegistry;
3031
import groovy.lang.MissingMethodException;
@@ -688,6 +689,9 @@ private static String formatMap(Map map, boolean verbose, int maxSize, boolean s
688689
if (map.isEmpty()) {
689690
return "[:]";
690691
}
692+
if (map.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null) {
693+
return map.toString();
694+
}
691695
StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * map.size() * 2);
692696
buffer.append('[');
693697
boolean first = true;
@@ -723,6 +727,9 @@ private static int sizeLeft(int maxSize, StringBuilder buffer) {
723727
}
724728

725729
private static String formatCollection(Collection collection, boolean verbose, int maxSize, boolean safe) {
730+
if (collection.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null) {
731+
return collection.toString();
732+
}
726733
StringBuilder buffer = new StringBuilder(ITEM_ALLOCATE_SIZE * collection.size());
727734
buffer.append('[');
728735
boolean first = true;

src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,4 +266,56 @@ public class DefaultGroovyMethodsTest extends GroovyTestCase {
266266
delegate.iterator()
267267
}
268268
}
269+
270+
271+
@IgnoreDefaultEqualsAndToString
272+
private static class CustomList extends ArrayList {
273+
CustomList( Object... items) {
274+
addAll(items)
275+
}
276+
277+
@Override
278+
boolean equals(Object other) {
279+
return this.sum() == other.sum()
280+
}
281+
}
282+
283+
@IgnoreDefaultEqualsAndToString
284+
private static class CustomSet extends HashSet {
285+
CustomSet( Object... items) {
286+
addAll(items)
287+
}
288+
289+
@Override
290+
boolean equals(Object other) {
291+
return this.collect { it.toString().toUpperCase() } == other.collect { it.toString().toUpperCase() }
292+
}
293+
}
294+
295+
@IgnoreDefaultEqualsAndToString
296+
private static class CustomMap extends HashMap {
297+
CustomMap(Map params) {
298+
this.putAll(params)
299+
}
300+
301+
boolean equals(Object other) {
302+
this.values().sum() == other.values().sum()
303+
}
304+
}
305+
306+
public void testCustomEqualsForList() {
307+
308+
assertTrue(new CustomList(1,2,3).equals(new CustomList(3,3)))
309+
assertTrue(new CustomList(1,2,3) == new CustomList(3,3) )
310+
311+
assertTrue(new CustomSet('a','b','c').equals(new CustomSet('A','B','C')))
312+
assertTrue(new CustomSet('a','b','c') == new CustomSet('A','B','C') )
313+
314+
assertTrue(new CustomMap(a:10) == new CustomMap(b:3,c:7))
315+
assertTrue(new CustomMap(a:10).equals(new CustomMap(b:3,c:7)))
316+
assertFalse(new CustomMap(a:1) == new CustomMap(b:2))
317+
318+
}
319+
320+
269321
}

src/test/org/codehaus/groovy/runtime/InvokerHelperFormattingTest.groovy

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,42 @@ class InvokerHelperFormattingTest extends GroovyTestCase {
214214
assert '[(this Map):(this Map)]' == InvokerHelper.toString(m)
215215
}
216216

217+
218+
219+
public void testIgnoreDefaultToStringForCustomList() {
220+
221+
String TEST = "" +
222+
"@IgnoreDefaultEqualsAndToString \n" +
223+
"class Foo extends ArrayList { \n" +
224+
" String toString() { return this.reverse().join('-') } \n" +
225+
"}\n" +
226+
"" +
227+
"def foo = new Foo()\n" +
228+
"foo << 1 << 2 << 3 \n" +
229+
"assert foo.toString() == \"1-2-3\"\n" +
230+
"assert \"$foo\".toString() == \"1-2-3\"\n" +
231+
"return true";
232+
233+
assertTrue((Boolean)Eval.me(TEST));
234+
235+
}
236+
237+
public void testIgnoreDefaultToStringForCustomMap() {
238+
239+
String TEST = "" +
240+
"@IgnoreDefaultEqualsAndToString \n" +
241+
"class Foo extends HashMap { \n" +
242+
" String toString() { return 'MyCustomToString' } \n" +
243+
"}\n" +
244+
"" +
245+
"def foo = new Foo()\n" +
246+
"assert foo.toString() == 'MyCustomToString'\n" +
247+
"assert \"$foo\".toString() == 'MyCustomToString'\n" +
248+
"return true";
249+
250+
assertTrue((Boolean)Eval.me(TEST));
251+
252+
}
253+
254+
217255
}

0 commit comments

Comments
 (0)