groovy.lang.MissingMethodException for 'collect' closure in Groovy

I am getting this error

No signature of method: ClassPath$_method_closure3.doCall() is applicable for argument types: ([AncestorOfFile]) values: [...values]
Possible solutions: doCall(File), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)

For this code

pageFiles = (someCollection as Collection<File>).collect {File file ->
    ...
    some logic
    ...
}

Works perfectly fine without type declaration "File" for inner variable. I thought I can use type declaration for collect closure like that because i work with typed Collection. Am I doing something wrong?

Upvotes: 1

Views: 1564

Answers (1)

Szymon Stepniak
Szymon Stepniak

Reputation: 42184

You need to double-check the assumption that the variable someCollection is of type Collection<File>. It looks like you expect that every element of that collection is of type ru.naumen.modules.portal.types.File, and if that was correct, then you could apply it to the closure you defined for the collect() method.

The reason you don't see a similar error when you don't define File file parameter for that closure is that in such a case, the closure you define accepts any type of argument. Let me show you this by example.

def someCollection = [[1,2,3,4,5]]

(someCollection as Collection<Integer>).collect { 
    // do something...
}

In this example, someCollection is of the type List<List<Integer>>. There are no errors, the code seems to work fine. But it is not if you expect that the collect method gets every number one by one. Instead, it gets the whole list of numbers. This problem can be discovered if we declare a desired type of argument for that closure:

def someCollection = [[1,2,3,4,5]]

(someCollection as Collection<Integer>).collect { Integer it ->
    // do something...
}

If we try to run this example, we get an error that is similar to yours:

Caught: groovy.lang.MissingMethodException: No signature of method: test$_run_closure1.doCall() is applicable for argument types: (ArrayList) values: [[1, 2, 3, 4, 5]]
Possible solutions: doCall(java.lang.Integer), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
groovy.lang.MissingMethodException: No signature of method: test$_run_closure1.doCall() is applicable for argument types: (ArrayList) values: [[1, 2, 3, 4, 5]]
Possible solutions: doCall(java.lang.Integer), findAll(), findAll(), isCase(java.lang.Object), isCase(java.lang.Object)
    at test.run(test.groovy:3)

To fix the problem with your code you will need to find out what is the type of the argument passed to the closure with no type definition. One way to do it would be to print the it.dump() result and see what is the type of the value. This is what it looks like for the example I shown you earlier:

def someCollection = [[1,2,3,4,5]]

(someCollection as Collection<Integer>).collect {
    println it.dump()
}

Output:

<java.util.ArrayList@1c3e4a2 elementData=[1, 2, 3, 4, 5] size=5 modCount=1>

You will see that the value you expect to be of type ru.naumen.modules.portal.types.File is something else in reality. Maybe this is a list of files, or maybe this is something else. And then if you want to make the closure with specific type to work, you will have to make sure that someCollection is a collection of those values in reality.

Upvotes: 2

Related Questions