grailsgroovyoverridingdefault-method

Override DefaultGroovyMethods method


Is there a way to easily override toSet(Collection<T> self) method from DefaultGroovyMethods?
Its implementation uses HashMap

public static <T> Set<T> toSet(Collection<T> self) {
    Set<T> answer = new HashSet<T>(self.size());
    answer.addAll(self);
    return answer;
}

but I’d like to use a LinkedHashMap to preserve the order of elements in the argument collection.

I tried with metaprogramming (already used a few times in various custom classes), e.g.

Collection.metaClass.toSet = {
    println 'in'
    Collection self = (Collection) delegate
    Set<Collection> answer = new LinkedHashSet<Collection>(self.size())
    answer.addAll(self)
    return answer
}

but with no luck (cannot enter that closure).
Any suggestion will be very welcome. Thanks is advance!

ps: I'm currently developing a Grails 4.0.3 app, Groovy 2.5.6


Solution

  • You can override this method using Groovy extensions module. It works fine in a regular Groovy code, but it should also work when used with Grails framework. Consider the following example:

    package com.example
    
    import groovy.transform.CompileStatic
    
    @CompileStatic
    class MyDefaultGroovyMethods {
    
        static <T> Set<T>  toSet(final Collection<T> self) {
            final Set<T> set = new LinkedHashSet<T>(self.size())
            set.addAll(self)
            return set
        }
    }
    

    You can register this helper method to override a Collection.toSet() method by creating a following src/main/resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule file:

    moduleName = my-default-groovy-methods-module
    moduleVersion = 1.0
    extensionClasses = com.example.MyDefaultGroovyMethods
    

    Then you can test it with something like this:

    def xs = [1,3,2,4]
    
    def set =  xs.toSet()
    
    println xs.toSorted()
    
    println set
    
    println set.class
    

    Output:

    [1, 2, 3, 4]
    [1, 3, 2, 4]
    class java.util.LinkedHashSet