Groovy - no signature of method after inserting a method - groovy

Well, I'm getting MissingMethodException even after inserting a method into a metaclass. It's strange that its says there's no signature applicable for a String, but there's for java.lang.Object
Some obs:
yeah, the List<Class> classes that I'm iterating contains the class I'm trying to use
please don't suggest me to use #Log4j or any other, it's not working with any method I try to insert (even though I can manipulate the same class fields with reflections)
as I said, the stackstrace says that there isn't signature (java.lang.String) but there's to (java.lang.Object)
classes.each { clazz ->
clazz.metaClass.log = { instance.simpleLogger.log(it) }
clazz.metaClass.debug = { instance.simpleLogger.debug(it) }
#Override
void enable() {
debug("eae meu bom")
}
groovy.lang.MissingMethodException: No signature of method: com.dont.testplugin.Terminal.debug() is applicable for argument types: (java.lang.String) values: [eae meu bom]
Possible solutions: debug(), debug(java.lang.Object), getAt(java.lang.String), log(), dump(), log(java.lang.Object)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:56) ~[?:?]
at org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78) ~[?:?]
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49) ~[?:?]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133) ~[?:?]
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141) ~[?:?]

Echoing #daggett here, with the assumption that you are calling the debug method from groovy (and not java) and that the place you are calling it from is not annotated with something like #CompileStatic I would have expected that to work as well.
The following code:
class Foo {}
Foo.class.metaClass.debug = { println("debug: $it") }
def f = new Foo()
f.debug("eae meu bom")
when executed prints:
─➤ groovy solution.groovy
debug: eae meu bom
(Groovy Version: 3.0.6 JVM: 11.0.9.1)
I think we need more context to get you relevant answers.

For future readers:
I really don't what's happening. I solved changing from
classes.each { clazz ->
clazz.metaClass.method = {methodHere}
}
to
classes.each { clazz ->
Instance instance = generateInstance(clazz)
instance.metaClass.method = {methodHere}
}
I was already instantiating it, so wasn't a problem to me to change it, don't know for you future readers.

Related

Call Java Method with Suppliers from Groovy

How can I call a Java method that accepts suppliers as varargs from a Groovy application?
My Java method:
public class Framework {
public static void run(Supplier<?>... suppliers) {
System.out.println(Arrays.stream(suppliers).map(supplier -> supplier.get()).collect(Collectors.toList()));
}
}
My Groovy application:
class Application {
static void main(String[] arguments) {
Framework.run { 42 }
}
}
IntelliJ doesn't show any errors. However, when I try to execute my Groovy application, I get an exception:
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: static Framework.run() is applicable for argument types: (Application$_main_closure1) values: [Application$_main_closure1#aecb35a]
Possible solutions: run([Ljava.util.function.Supplier;), dump(), find(), any(), grep(), grep(java.lang.Object)
at groovy.lang.MetaClassImpl.invokeStaticMissingMethod(MetaClassImpl.java:1525)
at groovy.lang.MetaClassImpl.invokeStaticMethod(MetaClassImpl.java:1511)
at org.codehaus.groovy.runtime.callsite.StaticMetaClassSite.call(StaticMetaClassSite.java:50)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:115)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:127)
at Application.main(Application.groovy:6)
Currently, I suppose the only solution would be:
Framework.run({ 42 } as Supplier)
Framework.run({ 42 } as Supplier, { 43 } as Supplier)
Framework.run([{ 42 }, { 43 }] as Supplier[])
I've also tried Groovy 3.0.0-alpha-4. It supports lambda syntax but not in the vararg case. Quick search through their jira didn't show any issues on this matter. You can raise the issue as explained at http://groovy-lang.org/support.html

What does it mean that Groovy Category use is confined to the current thread?

I found the following statement in the book Groovy In Action, 2nd Edition:
Category use is confined to the current thread
What does this statement actually mean ?
It means you are able to call methods added via category class in the same thread only. Consider following example:
class StringUtils {
static String transform(String source) {
return source.toUpperCase().reverse().substring(0, source.length() / 2 as int)
}
}
use (StringUtils) {
println "Lorem ipsum".transform()
}
In this example we are adding String.transform() method via category. Running this example produces following output:
MUSPI
In this example we have used category class in the main thread and we have called String.transform() method in the main thread as well.
Now let's change this example a little bit and let's call String.transform() method outside main thread by calling it in the newly started thread:
class StringUtils {
static String transform(String source) {
return source.toUpperCase().reverse().substring(0, source.length() / 2 as int)
}
}
use (StringUtils) {
Thread.start {
println "Lorem ipsum".transform()
}
}
We have used StringUtil category class in the main thread and we call this method from Thread-1 thread. Let's see what happens when we run it:
Exception in thread "Thread-1" groovy.lang.MissingMethodException: No signature of method: java.lang.String.transform() is applicable for argument types: () values: []
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at script$_run_closure1$_closure2.doCall(script.groovy:9)
at script$_run_closure1$_closure2.doCall(script.groovy)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1022)
at groovy.lang.Closure.call(Closure.java:414)
at groovy.lang.Closure.call(Closure.java:408)
at groovy.lang.Closure.run(Closure.java:495)
at java.lang.Thread.run(Thread.java:748)
An exception is thrown, because String.transform() does not exist in scope of Thread-1 thread - it exists only in main thread.
But let's assume that we have to make this method available in Thread-1 thread scope. We can make it happened by defining use(StringUtils){} inside the Thread-1 block, e.g.
class StringUtils {
static String transform(String source) {
return source.toUpperCase().reverse().substring(0, source.length() / 2 as int)
}
}
Thread.start {
use(StringUtils) {
println "Lorem ipsum".transform()
}
}
Now everything is fine - category usage block is defined inside Thread-1 and we call String.transform() method from the same thread. Running this example produces expected output to the console:
MUSPI
This is what
Category use is confined to the current thread
means in practice.
But how this method gets called?
When we call:
"Lorem ipsum".transform()
from the above example, following Groovy method handles invocation of transform() method:
groovy.lang.MetaClassImpl.invokeMethod(Class sender, Object object, String methodName, Object[] originalArguments, boolean isCallToSuper, boolean fromInsideClass)
You can find it at line 1044 (Groovy 2.4.12). transform() method does not exist in class String so Groovy has to find its implementation somewhere else. In this case the method is found in line 1055:
MetaMethod method = null;
if (CLOSURE_CALL_METHOD.equals(methodName) && object instanceof GeneratedClosure) {
method = getMethodWithCaching(sender, "doCall", arguments, isCallToSuper);
}
Most important part of this method is line 1283:
if (!isCallToSuper && GroovyCategorySupport.hasCategoryInCurrentThread()) {
return getMethodWithoutCaching(sender, methodName, MetaClassHelper.convertToTypeArray(arguments), isCallToSuper);
} else {
....
}
GroovyCategorySupport.hasCategoryInCurrentThread() checks if the category is used in the current thread (ThreadLocal is used in this case).
If you trace what happens next you will get to the MetaClassImpl line 690 where getMethods(Class sender, String name, boolean isCallToSuper) is located. In line 706 this method calls:
List used = GroovyCategorySupport.getCategoryMethods(name);
And this is the final part that actually finds the method by its name in the category class. Later it checks if the method is static and if it expects a parameter with a valid type (String in this case).

java.lang.UnsupportedOperationException when using Groovy's Constructor Coersion

Why can't I Coerce my map into a constructor for IStringHolder?
When I run Example.main
interface IStringHolder {
String getString()
}
class StringHolder implements IStringHolder {
String string
StringHolder(string) {
this.string = string
}
#Override
String getString() {
return string
}
}
class Example {
public static void main(String[] args) {
doSomething([string:"hey"] as IStringHolder)
}
static void doSomething(IStringHolder stringHolder) {
println stringHolder.getString()
}
}
I get the following exception
Exception in thread "main" java.lang.UnsupportedOperationException
at org.codehaus.groovy.runtime.ConvertedMap.invokeCustom(ConvertedMap.java:52)
at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:124)
at com.sun.proxy.$Proxy0.getString(Unknown Source)
at IStringHolder$getString.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
at Example.doSomething(Example.groovy:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.invoke(StaticMetaMethodSite.java:46)
at org.codehaus.groovy.runtime.callsite.StaticMetaMethodSite.callStatic(StaticMetaMethodSite.java:102)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:56)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:194)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:206)
at Example.main(Example.groovy:21)
Why is the exception coming from the first line in Example.doSomething?
When I coerce the map to StringHolder then it works. What is going on?
The Problem
The problem with this code is this line:
doSomething([string:"hey"] as IStringHolder)
The language feature of Groovy you're attempting to leverage here is called Explicit Constructor Coercion, which looks for a constructor within the IStringHolder class that it can call with the arguments you provided.
In this case, Groovy will look within the IStringHolder class for a no-arg constructor it can call to instantiate it, then it will look for a setter setString(String str) and call it with the "hey" you provided.
The reason you're seeing UnsupportedOperationException is because there is no constructor in IStringHolder to call, because it's not an implementation.
Switching the type coercion to as StringHolder does work, but probably not as you're expecting. Had you provided simply "hey", instead of string:"hey", it would have done what you were expecting and what I detailed above. This is because the map is interpreted as a Named Argument Constructor, which causes Groovy to instantiate your object using the only constructor it can find, passing null into it, and then calling the synthetic setString(String str) method with "hey" once it has been constructed. While this yields the result you're looking for, it does it in a non-intuitive way.
Solutions
Explicit Constructor Coercion
StringHolder stringHolderImpl = [ "hey" ] as StringHolder
Here Groovy will look for a constructor that takes one-arg of type String and pass our value "hey" into it.
Implicit Constructor Coercion
StringHolder stringHolder = [ "hey" ]
This is the same as above, except Groovy is using the left-side type to determine what the right-side probably is, before it proceeds with finding the constructor, etc.
I don't recommend this only because it makes Groovy assume too much, and IDEs like Intellij will complain about this syntax.
Explicit Closure Coercion
If you're adamant about not using the implementation class StringHolder you can create an implementation at runtime via:
IStringHolder stringHolderImpl = { getString: "hey" } as IStringHolder
This creates a closure which satisfies the IStringHolder contract, so it can be easily cast to an implementation of it.
Implicit Closure Coercion
IStringHolder stringHolderImpl = { getString: "hey" }
Again I don't really recommend this style, but it works.
My Thoughts
I'm a fan of explicit constructor coercion due to the explicit nature and because it doesn't require the overhead of creating a closure. I'll use explicit closure coercion from time to time when I need an implementation of a class that only needs to exist at runtime.
What's the best option? You'll have to determine that for yourself!
tl;dr
You were trying to coerce to an interface instead of an implementation
You tried to use a Named Argument Constructor for the coercion when you needed to use a Positional Argument Constructor

Mockito NullPointerException while using any

I am trying to use Mockito like this :
Mockito.when(Mockito.any(ObjectMapper.class).readValue(Mockito.any(BufferedReader.class),Mockito.any(Class.class))).thenReturn(new Person("1","abc"));
This is from Jackson library .
public <T> T readValue(Reader src, Class<T> valueType)
The reason I am doing it is because the time I reach this point of the code there are a ton of objects which were created. Mocking on every step would take time.
Any reason why I am getting NPE when code reaches this mockito statement?
Stack Trace :
java.lang.NullPointerException
at com.prashant.flax.ShellTest.givenDirectoryHasFiles(ShellTest.java:139)
at com.prashant.flax.ShellTest.testExecute(ShellTest.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
As you can see it is in a given method(this method only has this piece of code) , so I can see while debugging, it reaches over there and crashes.
As Oliver mentioned in the comments, you can't apply when to happen to all objects. Mockito works via subclassing, so you have to create a mock instance using mock, spy, or a #Mock or #Spy annotation; customize the behavior; and then install the mock using dependency injection or other similar tricks.
As to why this happens, the return value for any() actually is null; matchers like any are only supposed to be used as arguments to when and verify, and Mockito can't produce a specialized instance of Class that represents "any Class", so Mockito returns a dummy value (null) and stores data on a specialized stack of argument matchers. Though Mockito has better error messages to alert you to this situation, your code NPEs before Mockito can give you a proper exception with usage examples.
For more about matcher return values and the stack, see my other SO answer on "How do Mockito matchers work?".
To extend on what #jeff-bowman said in his answer, any() returns null, so if you need something that doesn't return null, you can try this:
/**
* never returns null
*/
private inline fun <reified T> any(type: Class<T>): T = Mockito.any(type)
/**
* returns null
*/
private inline fun <reified T> any(): T = Mockito.any<T>()
For me the actual problem was that I was trying to mock a spy. When mocking a spy you have to use the doReturn or doAnswer methods. Otherwise the method of the spy will be actually called while trying to mock it and unexpected behavior can happen. E.g. when calling when with any(), any() will just return null. So it is likely that you will get an NullPointerException.
Here is a full example that demonstrates the bahavior:
package com.company;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
public class SpyTest {
public class Controller {
public String method(String arg) {
return arg.substring(0, 1);
}
}
#Test
public void withMockTest() {
Controller controllerMocked = mock(Controller.class);
when(controllerMocked.method(anyString())).thenReturn("42");
assertEquals("42", controllerMocked.method("FOO"));
}
#Test(expected = NullPointerException.class)
public void withSpyWhenThenReturnBreakingBecauseMethodToBeMockedIsActuallyBeingCalled() {
Controller controllerSpied = spy(new Controller());
when(controllerSpied.method(any())).thenReturn("42");
}
#Test
public void withSpyDoReturnWhen() {
Controller controllerSpied = spy(new Controller());
doReturn("42").when(controllerSpied).method(any());
assertEquals("42", controllerSpied.method("FOO"));
}
}

Why does Groovy think I'm passing an instance of the class from a static method?

I'm new to Groovy, so it's likely I am doing something wrong. I had written a configuration to be taken in by ConfigSlurper. But something goes wrong when I actually try to parse it. My code is as follows:
class CharacterMap {
public static final String CHARACTER_CONFIGURATION = 'location'
static Map<String,String> characterMap = null
public static String ASCIIize(String input)
{
if (!characterMap)
{
def property = System.getProperty( CHARACTER_CONFIGURATION )
ConfigObject config = null
if( property ) {
ConfigSlurper cs = new ConfigSlurper()
File file = new File( property )
URL location = file.toURL()
config = cs.parse(location)
}
if (config)
{
characterMap = config.characters
}
else
{
getAnonymousLogger().logp WARNING, getClass().name, 'constructor',
"Server configuration groovy file not configured with system property ${CHARACTER_CONFIGURATION}"
return input
}
}
for (String key: characterMap.keySet())
{
if (input.contains(key))
{
input = input.replace(key, characterMap.get(key))
}
}
return input
}
public static void main(String[] args)
{
print ASCIIize(args[0])
}
}
When it gets to calling the parse method it complains Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: groovy.util.ConfigSlurper.parse() is applicable for argument types: (CharacterMap, java.net.URL)
As you can see, I am only passing in one argument, which was declared to be a URL. Since all the methods of the class are static and no constructor is referenced anywhere, it's kind of bizarre that an instance is being created at all, and more bizarre still that it's being passed into the parse method. I've read other people on Stack Overflow getting MissingMethodException (though usually related to closures rather than superfluous arguments), and it being blamed on Eclipse. I am running this in IntelliJ rather than Eclipse.
EDIT: In response to the comment below the groovy version is 1.8.6. Here is the stack-trace:
Exception in thread "main" groovy.lang.MissingMethodException: No
signature of method: groovy.util.ConfigSlurper.parse() is applicable
for argument types: (CharacterMap, java.net.URL) values:
[CharacterMap#34374a16, file:/C:/Program Files
(x86)/JetBrains/IntelliJ IDEA Community Edition
11.1.2/UCP/config/CharacterMap.groovy]
Possible solutions: parse(java.net.URL), parse(groovy.lang.Script,
java.net.URL), parse(groovy.lang.Script), parse(java.lang.Class),
parse(java.lang.String), parse(java.util.Properties)
at
org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:55)
at
org.codehaus.groovy.runtime.callsite.PogoMetaClassSite.callCurrent(PogoMetaClassSite.java:78)
at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:46)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:145)
at groovy.util.ConfigSlurper.parse(ConfigSlurper.groovy:148) at
groovy.util.ConfigSlurper$parse.call(Unknown Source) at
org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:42)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at
org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at ucp.cms.search.CharacterMap.ASCIIize(CharacterMap.groovy:26) at
ucp.cms.search.CharacterMap.main(CharacterMap.groovy:51) at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601) at
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Process finished with exit code 1

Resources