Importing external jar file in Android Studio---NoClassDefFoundError - jar

I created a new project using Android Studio and copied a jar file into my application's libs. Then added it as a library, which made the IDE recognize it. Later, I added it to the build.gradle and it now compiles just fine. However, when I attempt to run the application on a device it crashes with NoClassDefFoundError.
Attached and in order:
The project tree on Android Studio. Notice the test-jar-to-import.jar inside HelloSheepProject/HelloSheep/libs/.
The contents of the MainActivity.java. It is attempting to create a new MyFile. Nothing else.
The build.gradle inside HelloSheepProject/HelloSheep/. I added the line compile files('libs/test-jar-to-import.jar').
The contents of MyFile.java. It was created in Eclipse and exported as a jar file.
The error when I trying to run it on a device.
Any ideas on what I am missing? I have tried a ./gradlew clean in HelloSheepProject but it didn't help.
package top.furrylamb.example.hellosheep;
import android.os.Bundle;
import android.app.Activity;
import top.furrylamb.example.MyFile;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyFile myFile = new MyFile("hi", "there");
}
}
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.5.+'
}
}
apply plugin: 'android'
repositories {
mavenCentral()
}
dependencies {
compile 'com.android.support:support-v4:13.0.+'
//compile fileTree(dir: "libs", include: "*.jar")
compile files('libs/test-jar-to-import.jar')
}
android {
compileSdkVersion 17
buildToolsVersion "17.0.0"
defaultConfig {
minSdkVersion 14
targetSdkVersion 16
}
}
package top.furrylamb.example;
public class MyFile {
public final String left;
public final String right;
public MyFile(String left, String right) {
this.left = left;
this.right = right;
}
}
07-19 19:26:33.855 13656-13656/? E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.NoClassDefFoundError: top.furrylamb.example.MyFile
at top.furrylamb.example.hellosheep.MainActivity.onCreate(MainActivity.java:15)
at android.app.Activity.performCreate(Activity.java:5206)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1083)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2064)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2125)
at android.app.ActivityThread.access$600(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1227)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4898)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1006)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:773)
at dalvik.system.NativeStart.main(Native Method)

I found the solution to my problem. Since I've been lost on this for hours I'll keep the thread instead of deleting it.
The jar I was importing had been compiled/exported with Java 7 in mind. Once I enabled compliance with Java 6 it worked fine.
To sum it up, when adding an external jar file in Android Studio:
Copy jar to root/project/libs folder;
Right-click and add as library;
Add the jar to root/project/build.gradle (something like compile files('libs/test-jar-to-import.jar'));
Make sure the imported jar complies with Java 6 (7 will not do, for now).

In my case, I was getting the same NoClassDefFoundError error at runtime, even though it compiled ok. It had been working fine previously. But one day, I added a new package to my app, which resulted in the package name-space being changed. My jar had already been a part of the application's structure, so I was somewhat surprised at this new runtime error suddenly complaining about an unknown class in a jar library that was working previously.
The fix, in my case, was a simple Build->Clean Project.

Related

Launch iOS fails on init. Runs locally

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'org.javafxports:jfxmobile-plugin:1.1.1'
}
}
apply plugin: 'org.javafxports.jfxmobile'
repositories {
jcenter()
maven {
url 'https://mvnrepository.com/artifact/com.caucho/hessian'
}
maven {
url'http://nexus.gluonhq.com/nexus/content/repositories/releases'
}
}
mainClassName = 'com.demoapp.DemoApp'
dependencies {
compile 'com.gluonhq:charm:4.1.0'
compile 'com.airhacks:afterburner.mfx:1.6.2'
compile 'com.caucho:hessian:4.0.7'
compile 'com.google.code.gson:gson:2.3.1'
compile 'org.apache.poi:poi:3.9'
}
jfxmobile {
downConfig {
version '3.0.0'
plugins 'display', 'lifecycle', 'statusbar', 'storage'
}
android {
manifest = 'src/android/AndroidManifest.xml'
}
ios {
infoPList = file('src/ios/Default-Info.plist')
forceLinkClasses = [
'com.demoapp.**.*',
'com.gluonhq.**.*',
'io.datafx.**.*',
'javax.annotations.**.*',
'javax.inject.**.*',
'javax.json.**.*',
'org.glassfish.json.**.*',
'com.caucho.**.*',
'com.google.code.gson.**.*',
'org.apache.poi.**.*'
]
}
}
Error Exception in Application init method
QuantumRenderer: shutdown
java.lang.RuntimeException: Exception in Application init method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:109069952)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$156(LauncherImpl.java:109069952)
at com.sun.javafx.application.LauncherImpl$$Lambda$2.run(Unknown Source)
at java.lang.Thread.run(Thread.java:109069952)
Caused by: java.lang.NoSuchMethodError: com.demoapp.DemoApp$$Lambda$1.()V
at com.demoapp.DemoApp.init(DemoApp.java:109070784)
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:109070784)
at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$156(LauncherImpl.java:109070784)
at com.sun.javafx.application.LauncherImpl$$Lambda$2.run(Unknown Source)
at java.lang.Thread.run(Thread.java:109070784)
Any idea where to search for the init-Error when deploying..? Thanks.
Init:
#Override
public void init() {
NavigationDrawer drawer = new NavigationDrawer();
NavigationDrawer.Header header = new NavigationDrawer.Header("demo inc", "smart teamwork", new Avatar(21, new Image(DemoApp.class.getResourceAsStream("/icon.png"))));
drawer.setHeader(header);
drawer.getItems().addAll(primaryItem, secondaryItem, thirdItem);
primaryItem.setSelected(true);
addViewFactory(PRIMARY_VIEW, () -> (View) new PrimaryView().getView());
addViewFactory(SECONDARY_VIEW, () -> (View) new SecondaryView().getView());
addViewFactory(THIRD_VIEW, () -> (View) new ThirdView().getView());
addLayerFactory(MENU_LAYER, () -> new SidePopupView(drawer));
}
#Override
public void postInit(Scene scene) {
Swatch.ORANGE.assignTo(scene);
scene.getStylesheets().add(DemoApp.class.getResource("style.css").toExternalForm());
((Stage) scene.getWindow()).getIcons().add(new Image(DemoApp.class.getResourceAsStream("/icon.png")));
switchView(SECONDARY_VIEW);
}
The exception shows that a lambda expression is failing. Probably those in your init method with the view suppliers.
Possible reasons for this exception are:
Retrolambda
The jfxmobile plugin since version 1.1.0 applies retrolambda to all the dependencies. But you can't apply it twice.
The first step will be checking which dependencies might use retrolambda.
Charm 4+ doesn't use it. Afterburner 1.6.2 does, so either you change it to:
dependencies {
compileNoRetrolambda 'com.airhacks:afterburner.mfx:1.6.2'
}
or you use the brand new version that excludes it:
dependencies {
compile 'com.airhacks:afterburner.mfx:1.6.3'
}
To make sure none of the other dependencies use it, replace compile with compileNoRetrolambda in hessian, gson and poi.
Cache
Also, when updating projects with lower versions of the jfxmobile plugin, it is possible that you have a previous build on your cache. This might contain classes that you compiled with retrolambda.
While the code is the same, Gradle will skip compiling them again, but when the retrolambda plugin is applied again over them, this will fail.
To avoid this problem, an easy solution is using clean before building and deploying your project: Run ./gradlew clean launchIOSDevice.

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?

NullPointerException from LeakCanary when running Robolectric tests

Added LeakCanary (1.3) to my Application:
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
When I run the Robolectric test suite for my application I get a NullPointerException in LeakCanary.
Caused by: java.lang.NullPointerException
at com.squareup.leakcanary.LeakCanary.isInServiceProcess(LeakCanary.java:165)
at com.squareup.leakcanary.LeakCanary.isInAnalyzerProcess(LeakCanary.java:141)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:52)
at com.squareup.leakcanary.LeakCanary.install(LeakCanary.java:43)
at com.package.application.MyApplication.onCreate(MyApplication.java:50)
at org.robolectric.internal.ParallelUniverse.setUpApplicationState(ParallelUniverse.java:131)
at org.robolectric.RobolectricTestRunner.setUpApplicationState(RobolectricTestRunner.java:431)
at org.robolectric.RobolectricTestRunner$2.evaluate(RobolectricTestRunner.java:224)
I added that Im using Crashlytics to point out that it (and other methods as well) receives the same Application but does not throw any Exceptions.
Wasn't sure if this should be here or on GitHub issues for LeakCanary. Anyone else experiencing this issue?
Converting my comment to the answer.
Robolectric provides way to deal with different initialisations and application test lifecycles through test application.
Here is your application class:
public class <YourAppplication> extends Application {
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
LeakCanary.install(this);
}
}
You should put in test sources in the same package as yours application next class:
public class Test<YourAppplication> extends <YourApplication> {
#Override
public void onCreate() {
}
}
Robolectric will load it instead of your application. As you can see I suppress all static initialisations from your application.
You can find more details here
A simple way to avoid the NullPointerException is to disable LeakCanary for unit tests by specifying the release (no-op) version in the testCompile directive in build.gradle. For instance:
dependencies {
...
testCompile (
'junit:junit:4.12',
'org.robolectric:robolectric:3.0',
'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
)
...
}

Android Studio export jar with dependencies

I had a project library in Eclipse with Maven and the generated jar included some libraries dependencies inside.
Now I am migrating to Android Studio and I would like to build the same jar. I can generate a jar with the following lines in gradle:
task clearJar(type: Delete) {
delete 'build/libs/mysdk.jar'
}
task makeJar(type: Copy) {
from('build/intermediates/bundles/release/')
into('release/')
include('classes.jar')
rename ('classes.jar', 'mysdk.jar')
}
makeJar.dependsOn(clearJar, build)
But inside the jar there are not included the libraries that I use in my project library. With Maven I can use the "provided" scope in order to include or not a library in my jar but with gradle... how can I do that?
Thanks
Solved with the following tasks:
task jarTask(type: Jar) {
baseName="my-sdk-android"
from 'src/main/java'
}
task createJarWithDependencies(type: Jar) {
baseName = "my-sdk-android-jar-with-dependencies"
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jarTask
}
configurations {
jarConfiguration
}
artifacts {
jarConfiguration jarTask
}

JavaFx in headless mode

Is it possible to run JavaFx in headless mode(in Java 7)? It is being used to generate images on the server but is asking for an X-Server. Does there exist something like java.awt.headless in JavaFx ?(I can't use Xvfb )
Here is how I solved this problem for server-side image geneartion on Ubuntu linux environment with jetty application server. It uses xvfb but only as a "library" - without any additional special actions on server:
apt-get install xvfb
// then on application server start:
export DISPLAY=":99"
start-stop-daemon --start --background --user jetty --exec "/usr/bin/sudo" -- -u jetty /usr/bin/Xvfb :99 -screen 0 1024x768x24
You can see the details of my server-side image generation solution in this SO question.
This is a kind of problem which I encountered while capturing images in Mac OS.
I have solved this issue by using
static {
System.setProperty("java.awt.headless", "false");
}
See for reference : Headless environment error in java.awt.Robot class with MAC OS
Answer by Shreyas Dave didn't work for me anymore. Though I don't know why, here is what I did:
public static void main(String[] args) {
// to avoid
// [JRSAppKitAWT markAppIsDaemon]: Process manager already initialized: can't fully enable headless mode.
System.setProperty("javafx.macosx.embedded", "true");
java.awt.Toolkit.getDefaultToolkit();
// end
launch(args);
}
This was also pointed out here: JavaFX screencapture headless exception on OSX
If you have the source code of the JavaFX application you could also try to use TestFX run the application in a headless mode, to control it and to make screenshots. To run your TestFX application in headless mode you have to start it with the following JVM parameters (to enable Monocle):
-Dtestfx.robot=glass -Dglass.platform=Monocle -Dmonocle.platform=Headless -Dprism.order=sw
Moreover you might need to install Monocle first. See Headless testing with JavaFx and TestFx for more information.
I have an application that can be used interactively (displaying JavaFx dialogs) but also must be able to run non-interactive on a server without display.
Even though no GUI element is used in non-interactive mode, we got
Caused by: java.lang.UnsupportedOperationException: Unable to open DISPLAY
at com.sun.glass.ui.gtk.GtkApplication.<init>(GtkApplication.java:68)
This happens as soon as a class derived from javafx.application.Application is instantiated, which you normally do with your main class.
Here is the way I solved the problem:
I created an additional class GuiAppExecution:
import java.util.List;
import javafx.application.Application;
import javafx.stage.Stage;
/**
* JavaFx launch class for {#link AppExecution}.
*/
public class GuiAppExecution extends Application {
#Override
public void start(Stage stage) throws Exception {
List<String> parameters = getParameters().getRaw();
AppExecution appExecution = new AppExecution();
appExecution.launch(parameters);
}
/**
* Launches the {#link AppExecution} as JavaFx {#link Application}.
*
* #param parameters program parameters
*/
public void launchGui(String[] parameters) {
launch(parameters);
}
}
In the main class AppExecution I created a method
public void launch(List<String> parameters) {
which parses the parameters and launches the application for both interactive and non-interactive execution.
The main method looks like this:
public static void main(String[] parameters) {
List<String> parameterList = Arrays.asList(parameters);
if (parameterList.stream().anyMatch(p -> p.equalsIgnoreCase(BATCH_PARAMETER))) {
AppExecution appExecution = new AppExecution();
appExecution.launch(parameterList);
}
else {
GuiAppExecution guiAppExecution = new GuiAppExecution();
guiAppExecution.launchGui(parameters);
}
}
with
private static final String BATCH_PARAMETER = "-batch";
as the program option that request the non-interactive execution.
Since GuiAppExecution (which is derived from javafx.application.Application) is not instantiated for non-interactive execution, the JavaFx environment is not started.

Resources