Skip to content

Commit 0b0682a

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

File tree

5 files changed

+145
-0
lines changed

5 files changed

+145
-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;
@@ -685,6 +686,9 @@ private static String handleFormattingException(Object item, Exception ex) {
685686
}
686687

687688
private static String formatMap(Map map, boolean verbose, int maxSize, boolean safe) {
689+
if (map.getClass().getAnnotation(IgnoreDefaultEqualsAndToString.class)!=null) {
690+
return map.toString();
691+
}
688692
if (map.isEmpty()) {
689693
return "[:]";
690694
}
@@ -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: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,44 @@ 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
223+
class Foo extends ArrayList {
224+
String toString() { return this.join('-') }
225+
}
226+
227+
def foo = new Foo()
228+
foo << 1 << 2 << 3
229+
assert foo.toString() == "1-2-3"
230+
assert "$foo".toString() == "1-2-3"
231+
return true
232+
'''
233+
234+
assertTrue((Boolean)Eval.me(TEST));
235+
236+
}
237+
238+
public void testIgnoreDefaultToStringForCustomMap() {
239+
240+
String TEST = '''
241+
@IgnoreDefaultEqualsAndToString
242+
class Foo extends HashMap {
243+
String toString() { return 'MyCustomToString' }
244+
}
245+
246+
def foo = new Foo()
247+
assert foo.toString() == 'MyCustomToString'
248+
assert "$foo".toString() == 'MyCustomToString'
249+
return true
250+
'''
251+
252+
assertTrue((Boolean)Eval.me(TEST));
253+
254+
}
255+
256+
217257
}

0 commit comments

Comments
 (0)