java.lang.IllegalAccessError while running Mockito from SBT - sbt

Looks like SBT classloading messes with Mockito.
project/Build.scala
import sbt._
import Keys._
import sbtassembly.Plugin._
import AssemblyKeys._
object Build extends Build {
lazy val root = project.in(file("."))
.settings(
name := "so-mockito",
compileOrder := CompileOrder.JavaThenScala,
libraryDependencies += "org.mockito" % "mockito-core" % "1.9.5"
)
.settings(buildSettings: _*)
.settings(assemblySettings: _*)
.settings(mainClass in assembly := Some("com.example.JavaMain"))
}
project/plugins.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.10.2")
src/main/java/com/example/Consumer.java
package com.example;
class Consumer {
interface Input {
String get();
}
private final Input input;
static Consumer create(Input input) {
return new Consumer(input);
}
private Consumer(Input input) {
this.input = input;
}
}
src/main/java/com/example/JavaMain.java
package com.example;
import static org.mockito.Mockito.*;
import static com.example.Consumer.*;
public class JavaMain {
public static void main(String[] args) {
final Input input = mock(Input.class);
System.out.println(String.format("[JavaMain] Created mock: '%s'", input));
}
}
sbt run yields the following exception:
[info] Running com.example.JavaMain
[error] (run-main-0) org.mockito.exceptions.base.MockitoException:
[error] Mockito cannot mock this class: interface com.example.Consumer$Input
[error] Mockito can only mock visible & non-final classes.
[error] If you're not sure why you're getting this error, please report to the mailing list.
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: interface com.example.Consumer$Input
Mockito can only mock visible & non-final classes.
If you're not sure why you're getting this error, please report to the mailing list.
at com.example.JavaMain.main(JavaMain.java:8)
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:606)
Caused by: org.mockito.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:238)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
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:606)
Caused by: java.lang.reflect.InvocationTargetException
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:606)
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
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:606)
Caused by: java.lang.IllegalAccessError: class com.example.Consumer$Input$$EnhancerByMockitoWithCGLIB$$5997e3ec cannot access its superinterface com.example.Consumer$Input
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
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:606)
at org.mockito.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:385)
at org.mockito.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:220)
at org.mockito.cglib.proxy.Enhancer.createHelper(Enhancer.java:378)
at org.mockito.cglib.proxy.Enhancer.createClass(Enhancer.java:318)
at org.mockito.internal.creation.jmock.ClassImposterizer.createProxyClass(ClassImposterizer.java:110)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:62)
at org.mockito.internal.creation.jmock.ClassImposterizer.imposterise(ClassImposterizer.java:56)
at org.mockito.internal.creation.CglibMockMaker.createMock(CglibMockMaker.java:23)
at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:26)
at org.mockito.internal.MockitoCore.mock(MockitoCore.java:51)
at org.mockito.Mockito.mock(Mockito.java:1243)
at org.mockito.Mockito.mock(Mockito.java:1120)
at com.example.JavaMain.main(JavaMain.java:8)
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:606)
However, running with java or scala works as expected:
> sbt assembly && java -jar target/scala-2.10/so-mockito-assembly-0.1-SNAPSHOT.jar
[JavaMain] Created mock: 'Mock for Input, hashCode: 1317029026'
> sbt assembly && scala -cp target/scala-2.10/so-mockito-assembly-0.1-SNAPSHOT.jar 'com.example.JavaMain'
[JavaMain] Created mock: 'Mock for Input, hashCode: 1035091326'
Can anyone confirm (SBT 0.13.1)?

It works fine when the access modifier for the inner com.example.Consumer.Input interface becomes public as follows (note the public keyword for the interface):
package com.example;
class Consumer {
public interface Input {
String get();
}
private final Input input;
static Consumer create(Input input) {
return new Consumer(input);
}
private Consumer(Input input) {
this.input = input;
}
}
A sample sbt run with about before to know the versions, plugins and such.
$ sbt about run
[info] Loading global plugins from /Users/jacek/.sbt/0.13/plugins
[info] Loading project definition from /Users/jacek/sandbox/so/mockito/project
[info] Set current project to so-mockito (in build file:/Users/jacek/sandbox/so/mockito/)
[info] This is sbt 0.13.1
[info] The current project is {file:/Users/jacek/sandbox/so/mockito/}root 0.1-SNAPSHOT
[info] The current project is built against Scala 2.10.3
[info] Available Plugins: com.typesafe.sbt.SbtGit, com.typesafe.sbt.SbtProguard, growl.GrowlingTests, np.Plugin, com.timushev.sbt.updates.UpdatesPlugin, sbtassembly.Plugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.3
[info] Running com.example.JavaMain
[JavaMain] Created mock: 'Mock for Input, hashCode: 256995217'
[success] Total time: 0 s, completed Jan 29, 2014 10:00:13 PM
BTW, in this particular build configuration using build.sbt might be a better choice as it'd become clearer.
build.sbt
import AssemblyKeys._
name := "so-mockito"
compileOrder := CompileOrder.JavaThenScala
libraryDependencies += "org.mockito" % "mockito-core" % "1.9.5"
sbtassembly.Plugin.buildSettings
sbtassembly.Plugin.assemblySettings
mainClass in assembly := Some("com.example.JavaMain")

I was beaten by a similar error when mocking flyway from scala code mock[org.flywaydb.core.Flyway] the test ran nicely through Intellij but through sbt test it raised:
java.lang.IllegalAccessError: tried to access class org.flywaydb.core.Flyway
for other googlers my solution was simply upgrading mockito core:
```
- "org.mockito" % "mockito-core" % "2.7.22",
+ "org.mockito" % "mockito-core" % "2.15.0",
```

Related

Can't run JavaFX - Kotlin app

I can't run my javafx - kotlin app.
My Starter class
class Starter : Application() {
override fun start(primaryStage: Stage?) {
val root : Parent = FXMLLoader.load(javaClass.getResource("view/main.fxml"))
primaryStage?.title = "Title"
primaryStage?.scene = Scene(root)
primaryStage?.show()
}
fun main(args: Array<String>) {
launch(args)
}
}
I can't pass the param "args" to "launch" method because compiler says:
Error:(19, 9) Kotlin: None of the following functions can be called
with the arguments supplied: public open fun launch(p0: Class!, vararg p1: String!): Unit defined in
javafx.application.Application public open fun launch(vararg p0:
String!): Unit defined in javafx.application.Application
If I trying call "launch" method without params I have following Exception
Exception in thread "main" java.lang.reflect.InvocationTargetException
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
sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.NullPointerException 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
com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at
com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
... 5 more
You need to use spread operator
fun main(args: Array<String>) {
Application.launch(Starter::class.java, *args)
}

Designing an API - troubles with class loading (Groovy)

It's my first time designing an API. I have a program with folder 'plugins'. I made a test plugin in that folder packaged in JAR. In the program I have a Groovy class 'Configuration', which is supposed to load the plugins.
Configuration.java:
static void processConfiguration()
{
File pluginDirectory=new File(PLUGINDIRECTORY)//it's 'plugins'
if(!pluginDirectory.exists()) pluginDirectory.mkdir()
File[] pluginfiles=pluginDirectory.listFiles()
for(File f:pluginfiles)
{
if(f.name.endsWith('.jar'))
{
JarFile jar=new JarFile(f)
for(JarEntry jarEntry:jar.entries())
{
if(jarEntry.getName().endsWith('.class'))
{
//try loading the class
}
}
}
}
}
So, I tried doing these at the //try loading the class block
Class cl=ClassLoader.getSystemClassLoader().loadClass(jarEntry.name)
Class cl=new GroovyClassLoader().loadClass(jarEntry.name)
Class cl=Configuration.classLoader.loadClass(jarEntry.name)
Class cl=Class.forName(jarEntry.getName())
also tried with replacing - jarEntry.name.replaceAll('/','.').replace('.class',''), but I think it's done automatically.
Getting Class not found exception:
Exception in Application start method
java.lang.reflect.InvocationTargetException
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 com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
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 sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$155(LauncherImpl.java:182)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: jace/plugins/JavaPlugin.class
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java_lang_ClassLoader$loadClass.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:125)
at jace.Configuration.processConfiguration(Configuration.groovy:87)
at jace.Jace.start(Jace.java:56)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$162(LauncherImpl.java:863)
at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$175(PlatformImpl.java:326)
at com.sun.javafx.application.PlatformImpl.lambda$null$173(PlatformImpl.java:295)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl.lambda$runLater$174(PlatformImpl.java:294)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139)
After some searching and tinkering I finally resolved it.
First, need to create a list of proper URLs;
Second, make a list of classes from the jar;
Third, instantiate GroovyClassLoader and give him all URLs;
Fourth, load classes from list, check whether they implement plugin interfaces, then instantiate them.
static void processConfiguration()
{
File pluginDirectory=new File(PLUGINDIRECTORY)
if(!pluginDirectory.exists()) pluginDirectory.mkdir()
File[] pluginfiles=pluginDirectory.listFiles()
URL[] urls=[]
ArrayList<String> classes=new ArrayList<>()
for(File f:pluginfiles)
{
if(f.name.endsWith('.jar'))
{
JarFile jar=new JarFile(f)
URL url=new URL('jar:file:'+PLUGINDIRECTORY+'/'+f.name+'!/')
urls+=url
jar.entries().each {if(it.name.endsWith('.class'))classes.add(it.name) }
}
}
// println(gcl.loadedClasses)
GroovyClassLoader groovyClassLoader=new GroovyClassLoader()
urls.each {groovyClassLoader.addURL(it)}
// println(classes)
classes.each {
Class cl=groovyClassLoader.loadClass(it.replaceAll('/','.').replace('.class',''))
Class[] interfaces=cl.getInterfaces()
if(interfaces.contains(Plugin.class))
{
Object instance=cl.newInstance()
if(interfaces.contains(SuggestionPlugin.class))
{
SuggestionProcessor.suggestionPlugins.add(instance as SuggestionPlugin)
}
Constructor[] constructors=cl.getConstructors()
println("Loaded a plugin $cl.simpleName")
}
}
}

Realm doesn't work with SLF4J?

We wanted to integrate Realm in our app, and we encountered following problem:
FATAL EXCEPTION: XService
Process: xx.xxx.xxxx, PID: 16462
java.lang.NoClassDefFoundError: Failed resolution of: Lorg/gradle/logging/internal/slf4j/OutputEventListenerBackedLoggerContext;
at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:30)
at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:27)
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:128)
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:108)
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:279)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:252)
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:265)
at xx.xxx.xxxx.xxxxx.impl.core.StateMachine.<init>(StateMachine.java:52)
at xx.xxx.xxxx.xxxxx.android.XService$ServiceHandler.startController(XService.java:670)
at xx.xxx.xxxx.xxxxx.android.XService$ServiceHandler.handleMessage(XService.java:536)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
Caused by: java.lang.ClassNotFoundException: Didn't find class "org.gradle.logging.internal.slf4j.OutputEventListenerBackedLoggerContext" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/data/app/xx.xxx.xxxx-2/base.apk"],nativeLibraryDirectories=[/data/app/xx.xxx.xxxx-2/lib/arm, /data/app/xx.xxx.xxxx-2/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at org.slf4j.impl.StaticLoggerBinder.<init>(StaticLoggerBinder.java:30) 
at org.slf4j.impl.StaticLoggerBinder.<clinit>(StaticLoggerBinder.java:27) 
at org.slf4j.LoggerFactory.bind(LoggerFactory.java:128) 
at org.slf4j.LoggerFactory.performInitialization(LoggerFactory.java:108) 
at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:279) 
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:252) 
at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:265) 
at xx.xxx.xxxx.xxxxx.impl.core.StateMachine.<init>(StateMachine.java:52) 
at xx.xxx.xxxx.xxxxx.android.XService$ServiceHandler.startController(XService.java:670) 
at xx.xxx.xxxx.xxxxx.android.XService$ServiceHandler.handleMessage(XService.java:536) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:148) 
at android.os.HandlerThread.run(HandlerThread.java:61) 
Suppressed: java.lang.ClassNotFoundException: org.gradle.logging.internal.slf4j.OutputEventListenerBackedLoggerContext
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 14 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack trace available
Where StaticLoggerBinder looks like:
public class StaticLoggerBinder implements LoggerFactoryBinder {
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
private static final String loggerFactoryClassStr = AndroidCustomLoggerFactory.class.getName();
private final ILoggerFactory loggerFactory = new AndroidCustomLoggerFactory();
private StaticLoggerBinder() {
}
public static final StaticLoggerBinder getSingleton() {
return SINGLETON; // line 27
}
public ILoggerFactory getLoggerFactory() { //line 30
return this.loggerFactory;
}
public String getLoggerFactoryClassStr() {
return loggerFactoryClassStr;
}
}
From my understanding, problem is probably with Realm's transformer. It wants to include some unknown logger to our code. Main problem with our app is, that we have some 3rd party library, that uses also SLF4J, and we can't modify it. I tried with 0.90.1 version, while SLF4J used by 3rd party library is in 1.6.4 version. Dexguard is 7.1.26.
Also, note that, Realm works with my environment and another project with same dependencies except this 3rd party library and SLF4J.
List of dependencies:
plugins:
apply plugin: 'com.android.library'
apply plugin: 'com.neenbedankt.android-apt'
apply plugin: 'dexguard'
apply plugin: 'realm-android'
dependencies:
provided 'javax.annotation:jsr250-api:1.0'
apt 'com.google.dagger:dagger-compiler:2.0.2'
compile([
'com.google.dagger:dagger:2.0.2',
'com.mcxiaoke.volley:library:1.0.18',
'com.google.code.gson:gson:2.3.1',
'io.reactivex:rxjava:1.0.11',
'io.reactivex:rxandroid:0.24.0',
'com.jakewharton.timber:timber:3.1.0',
'com.squareup.okhttp:okhttp:2.6.0',
'com.squareup.okio:okio:1.6.0',
'com.android.support:support-v4:22.1.1'
])
compile files('libs/libconceal.jar')
compile files('libs/conceal_android.jar')
compile files('../dexguard/dexguard-runtime.jar')
compile files('libs/slf4j-api-1.6.4.jar')
compile files('libs/lib3rdparty.jar')
retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:2.3.0'
Is this possible, that Realm mess up here with that implementation? Is there any way to prevent it?

Realm release build with proguard fails - Could not find io.realm.RealmHelper

We're getting ready to release our first app with realm and, oops, finally tried a release build. Everything works fine until we enable proguard, then the app crashes on launch with:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.activities.IntroActivity}: io.realm.exceptions.RealmException: Could not find io.realm.RealmHelper$ManifestModuleMediator
...
Caused by: io.realm.exceptions.RealmException: Could not find io.realm.RealmHelper$ManifestModuleMediator
at io.realm.y.a(Unknown Source)
at io.realm.y.a(Unknown Source)
at io.realm.y.<init>(Unknown Source)
at io.realm.y.<init>(Unknown Source)
at io.realm.z.a(Unknown Source)
at com.example.realm.RealmHelper.a(Unknown Source)
at com.example.activities.IntroActivity.onCreate(Unknown Source)
We're using the realm recommended proguard settings, i.e.:
-keep class io.realm.annotations.RealmModule
-keep #io.realm.annotations.RealmModule class *
-keep class io.realm.internal.Keep
-keep #io.realm.internal.Keep class * { *; }
-dontwarn javax.**
-dontwarn io.realm.**
Any suggestions? Unfortunately we don't have any proguard wizards...
FWIW, I tried adding this line to the proguard config:
-keep class io.realm.** { *; }
That changed the trace to:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example/com.example.activities.IntroActivity}: io.realm.exceptions.RealmException: Could not find io.realm.RealmHelper$ManifestModuleMediator
...
Caused by: io.realm.exceptions.RealmException: Could not find io.realm.RealmHelper$ManifestModuleMediator
at io.realm.RealmConfiguration.getModuleMediator(Unknown Source)
at io.realm.RealmConfiguration.createSchemaMediator(Unknown Source)
at io.realm.RealmConfiguration.<init>(Unknown Source)
at io.realm.RealmConfiguration.<init>(Unknown Source)
at io.realm.RealmConfiguration$Builder.build(Unknown Source)
at com.example.realm.RealmHelper.a(Unknown Source)
at com.example.activities.IntroActivity.onCreate(Unknown Source)
at android.app.Activity.performCreate(Activity.java:6251)
Not sure if that helps...
We were able to fix this by splitting out our two #RealmModule classes into separate files. I.e. we went from:
RealmHelper.java
#RealmModule(classes = {Publisher.class, Puzzle.class, Volume.class, VolumeSet.class})
public static class ManifestModule {
}
#RealmModule(classes = {PuzzleMove.class, PuzzleState.class, VolumeState.class})
public static class PuzzleStateModule {
}
to:
realm/modules/ManifestModule.java
#RealmModule(classes = {Publisher.class, Puzzle.class, Volume.class, VolumeSet.class})
public class ManifestModule {
}
and realm/modules/PuzzleStateModule.java
#RealmModule(classes = {PuzzleMove.class, PuzzleState.class, VolumeState.class})
public class PuzzleStateModule {
}
RealmHelper.java
import com.example.realm.modules.ManifestModule;
import com.example.realm.modules.PuzzleStateModule
I'm not sure what magic wasn't happening with one file that worked ok with two, and why Proguard nudged it one way or the other, but it seems to be working again!

java.io.NotSerializableException while writing to Oracle Coherence cache

I have 2 storage enabled cache nodes that i am trying to use for pre-loading of cache. About 1 million accounts are to be loaded by these 2 storage enabled nodes. Both key and value are String objects which I am trying to write to cache. I am using InvocationService.execute() method to invoke the pre-loading tasks asynchronously:
for (Map.Entry<Member, LoaderInvocable> entry : mappedWork.entrySet()) {
Member member = entry.getKey();
LoaderInvocable task = entry.getValue();
invocationService.execute(task, Collections.singleton(member), null);
}
LoaderInvocable is a class that is implementing Invocable and Serializable interfaces and its run() method has been overridden to performs the actual work of reading from database and writing to the cache.
InvocationService is defined as below in the coherence config file:
<invocation-scheme>
<scheme-name>
InvocationScheme</scheme-name>
<service-name>
LoaderInvocationService</service-name>
<autostart system-property="tangosol.coherence.invocation.autostart">true</autostart>
</invocation-scheme>
Below is the exception that i am getting:
2016-02-22 17:16:24,612 [pool-1-thread-1] ERROR (support.context.SessionExecutable) Caught exception from SessionExecutable.execute()
(Wrapped) java.io.NotSerializableException: com.oracle.common.collections.ConcurrentLinkedQueue
at com.tangosol.util.Base.ensureRuntimeException(Base.java:289)
at com.tangosol.util.Base.ensureRuntimeException(Base.java:270)
at com.tangosol.coherence.component.util.daemon.queueProcessor.packetProcessor.PacketPublisher.packetizeMessage(PacketPublisher.CDB:28)
at com.tangosol.coherence.component.util.daemon.queueProcessor.packetProcessor.PacketPublisher$InQueue.add(PacketPublisher.CDB:8)
at com.tangosol.coherence.component.util.daemon.queueProcessor.packetProcessor.PacketPublisher.post(PacketPublisher.CDB:1)
at com.tangosol.coherence.component.net.Message.dispatch(Message.CDB:77)
at com.tangosol.coherence.component.net.Message.post(Message.CDB:1)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Grid.post(Grid.CDB:2)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.Grid.send(Grid.CDB:1)
at com.tangosol.coherence.component.util.daemon.queueProcessor.service.grid.InvocationService.execute(InvocationService.CDB:33)
at com.tangosol.coherence.component.util.safeService.SafeInvocationService.execute(SafeInvocationService.CDB:1)
.
.
.
.
.
.
Caused by: java.io.NotSerializableException: com.oracle.common.collections.ConcurrentLinkedQueue
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at java.util.Hashtable.writeObject(Hashtable.java:988)
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 java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:975)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:438)
at com.tangosol.coherence.Component.writeObject(Component.CDB:1)
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 java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:975)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528)
at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:438)
at com.tangosol.coherence.Component.writeObject(Component.CDB:1)
It seems that half of the accounts have been cached successfully. Can it be node specific issue? Both of the storage enabled cache nodes are on the same server using the same cluster configuration. From the logs it is clear that both nodes successfully joined the cluster.
Thanks Praveen. I have implemented the PortableObject interface and not facing the NotSerializableException anymore. But now i am facing a new problem. The second node is not invoking the task and leaving the cluster without any exception in the logs.
I used the InvocationObserver which suggests that memberLeft() the cluster. Can it be something wrong with my implementation of readExternal() and writeExternal() methods for serialization? Below is the implementation:
#Override
public void readExternal(PofReader paramPofReader) throws IOException {
// TODO Auto-generated method stub
cacheName = paramPofReader.readString(0);
firstRow = paramPofReader.readLong(1);
lastRow = paramPofReader.readLong(2);
}
#Override
public void writeExternal(PofWriter paramPofWriter) throws IOException {
// TODO Auto-generated method stub
paramPofWriter.writeString(0, cacheName);
paramPofWriter.writeLong(1, firstRow);
paramPofWriter.writeLong(2, lastRow);
}

Resources