New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Not working with classes with lambdas (retrolambda) #2364
Comments
Just curious: how is it possible to have 'real' (not the ones which went through retrolambda) lambdas in an Android class? What are you trying to shadow? |
I forgot to mention that I use retrolambda. Seems like classes got instrumented by robolectric before they are processed by retrolambda. |
I use JDK8 + Retrolambda just fine. Please show some example code. |
And then constructor
I suppose it's a bug in |
Usually when people use |
@jaredsburrows |
Do you really need to shadow your own classes? I recommend using a mocking library instead for that. I do think you're right though, this could be a bug related to the use of @jaredsburrows https://github.com/jaredsburrows — |
@jongerrish |
I've just encountered the same issue, trying to shadow a class, which uses retrolambdas. |
@budnyjj Can you show an example test? I use retrolambda in my apps just fine. @SammyVimes Any updates? |
Engine.java: public class Engine {
public static final Callback EMPTY_CALLBACK = args -> {
};
} EngineShadow.java: @Implements(Engine.class)
public class EngineShadow {
} CustomShadowTestRunner.java: public class CustomShadowTestRunner extends RobolectricGradleTestRunner {
public CustomShadowTestRunner(Class<?> testClass) throws InitializationError {
super(testClass);
}
@Override
public InstrumentationConfiguration createClassLoaderConfig() {
return InstrumentationConfiguration.newBuilder()
.addInstrumentedClass(Engine.class.getName())
.build();
} I'm running my tests on Linux as well as on Mac using robolectric 3.0 with retrolambda plugin 3.2.5. |
So this should work normally. Are you only seeing this error when using shadows + retrolambda? |
And the test is: @Config(shadows = {EngineShadow.class})
@RunWith(CustomShadowTestRunner.class)
public class JSEngineTest {
// TODO: add unit tests
@Test
public void testBasic() {
Assert.assertTrue(true);
}
} |
Yes, each time I replace public static final Callback EMPTY_CALLBACK = args -> {
}; with public static final Callback EMPTY_CALLBACK = new Callback() {
@Override
public void invoke(String[] args) {
}
} it passes. |
@SammyVimes @budnyjj This seems to work fine for me. I am using Robolectric 3.1.1.
CustomShadowTestRunner.java
Engine.java
EngineShadow.java
JSEngineTest.java
|
@SammyVimes Can we close this? @jongerrish @xian |
Sorry, my mistake. Here is failing test body: @Config(constants = BuildConfig.class, shadows = {EngineShadow.class}, sdk = 21)
@RunWith(CustomShadowTestRunner.class)
public class ExampleUnitTest {
@Test
public void testBasic() {
Engine.EMPTY_CALLBACK.invoke(new String[]{"abc"});
assertTrue(true);
}
} Error message: java.lang.NoClassDefFoundError: budnyjj/robolambda/Engine
at budnyjj.robolambda.ExampleUnitTest.testBasic(ExampleUnitTest.java:14)
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:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:251)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:188)
at org.robolectric.RobolectricTestRunner.runChild(RobolectricTestRunner.java:54)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.robolectric.RobolectricTestRunner$1.evaluate(RobolectricTestRunner.java:152)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
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)
Caused by: java.lang.ClassNotFoundException: couldn't load budnyjj.robolambda.Engine
at org.robolectric.internal.bytecode.InstrumentingClassLoader.findClass(InstrumentingClassLoader.java:155)
at org.robolectric.internal.bytecode.InstrumentingClassLoader.loadClass(InstrumentingClassLoader.java:95)
... 28 more
Caused by: java.lang.ClassCastException: org.objectweb.asm.tree.InvokeDynamicInsnNode cannot be cast to org.objectweb.asm.tree.MethodInsnNode
at org.robolectric.internal.bytecode.InstrumentingClassLoader$ClassInstrumentor.filterNasties(InstrumentingClassLoader.java:626)
at org.robolectric.internal.bytecode.InstrumentingClassLoader$ClassInstrumentor.instrument(InstrumentingClassLoader.java:386)
at org.robolectric.internal.bytecode.InstrumentingClassLoader.getInstrumentedBytes(InstrumentingClassLoader.java:243)
at org.robolectric.internal.bytecode.InstrumentingClassLoader.findClass(InstrumentingClassLoader.java:148)
... 29 more |
@budnyjj Now that fails for me. This is just hard for Robolectric to handle since Retrolambda takes Java8 byte code and turn it into Java7 byte code. |
What are the options to do in this situation? |
I guess. What is the use that the class you are using needs a shadow? or maybe for now, do not shadow classes with java 8 code or just switch those lambdas to a java 7 implementation. |
This shadow class should mock the original one, which has a number of native methods. |
You can just try mocking it for now or use a java 7 implementation instead of lambdas for the class that you are shadowing. |
Yes, I'll try to mock them. |
I have the same issue. But I'm using plain IDEA for development rather than AS. And I noticed that if I use JUnit Runner (IDE internals configured in Settings) then such test really fails but if I choose Gradle Runner - such tests passes. So my conclusion is that when IDE runs tests using JUnit Runner then tests get Java 8 code with real lambdas rather than retrolambdas. And seems that roboelectric does not support Java 8. I looked in the source code where stacktrace points to. And there's no special handling for invokedynamic opcode. It's the same as for all other invokeXXX methods. |
Closing this as it hasn't been updated in a while. If its still an issue with Robolectric 4.0 please reopen with a reproducible test case and we'll prioritize. |
When you try to shadow class, which has lambdas inside, its creationfails with
NoClassDefFoundError
with cause:java.lang.ClassCastException: org.objectweb.asm.tree.InvokeDynamicInsnNode cannot be cast to org.objectweb.asm.tree.MethodInsnNode at org.robolectric.internal.bytecode.InstrumentingClassLoader$ClassInstrumentor.filterSpecialMethods(InstrumentingClassLoader.java:683)
The text was updated successfully, but these errors were encountered: