LuaJ and Android: cannot bind class - java

I am currently writing a game engine in Java using the LibGDX framework. For several months now, I have successfully used LuaJ 3.0 with my engine. I have had no problems getting scripts to run on Android (tested on two devices) or Desktop (in and out of Eclipse).
However, when I tried to deploy to Android today, I got the following error:
org.luaj.vm2.LuaError: script:2 vm error: java.lang.ClassNotFoundException: com.javamon.console.ScriptPlayerCreate
The line of the script causing this error is:
Result = luajava.bindClass("com.javamon.console.ScriptPlayerCreate")
This is typographically identical to the class supposedly "not found" on Android.
If I try to bind a regular java class, such as java.lang.ClassNotFoundException, I don't get any error. However, this error does not occur on the Desktop version, whether run from within Eclipse or via a runnable *.jar.
Here is the stack trace, retrieved from LogCat:
org.luaj.vm2.LuaError: script:2 vm error: java.lang.ClassNotFoundException: com.javamon.console.ScriptPlayerCreate
at org.luaj.vm2.lib.jse.LuajavaLib.invoke(Unknown Source)
at org.luaj.vm2.lib.VarArgFunction.call(Unknown Source)
at org.luaj.vm2.LuaClosure.execute(Unknown Source)
at org.luaj.vm2.LuaClosure.call(Unknown Source)
at com.javamon.console.Script.runFunction(Script.java:91)
at com.javamon.console.Script.runFunction(Script.java:96)
at com.javamon.console.ScriptPlayerCreate.run(ScriptPlayerCreate.java:39)
What bothers me is the very last line. ScriptPlayerCreate certainly exists -- it's running the very script that produces the error!
Things I have tried:
Trying different versions of LuaJ
Binding a different class within the com.javamon package (same problem)
Updating my ADT/SDK plugins
Cleaning/rebuilding the project within Eclipse
"Starting Over" (creating a new LibGDX project using the GUI tool, and manually importing my source files)
Checking classes.dex -- ScriptPlayerCreate is certainly there
Testing on separate Android devices (Moto X and Incredible 2)
I would like to reiterate that I have successfully used LuaJ with Android for several months without incident. Additionally, I have not changed my scripting engine since my last (successful) Android deployment.
UPDATE
After trying to revert to backup versions of my app and Eclipse, the problem persists -- even on another computer. I am beginning to suspect that luajava.bindClass() does not know how to interpret the contents of classes.dex, and is instead searching for actual class files.
When I attempted to recompile some backup versions, I noticed that the recompiled version almost always has a smaller classes.dex file than the backup. Perhaps something is wrong or has changed with Eclipse's/Android's compiler?
I tried manually inserting class files into the com/javamon/console/ folder within the APK, but of course that messes up the file integrity, and even after re-signing the app will not load. Any ideas?

I got a similar problem,and I'd fix it
LuaJavaLib.java:202
original
return Class.forName(name, true, ClassLoader.getSystemClassLoader());
change to
return Class.forName(name, true, Thread.currentThread().getContextClassLoader());

Reverting to LuaJ 2.0.1 solved the issue.
It appears that all versions of LuaJ above 2.0.1 have a different implementation of LuajavaLib.class. In the new implementation, only Java system libraries can be accessed through luajava.bindClass(), whereas in the older versions, bindClass() permits access to local application classes as well. All other script functions behave normally; only luajava.bindClass() is affected.
In the newer versions, if a class is not found in the Java system libraries, LuaJ apparently checks the local application directory. Because the Desktop project is a runnable *.jar and contains actual class files, the Desktop version of the game would have worked properly in any version of LuaJ. Contrastingly, Android bundles everything in a classes.dex file, which is not "searchable" in the file-path sense. Hence the ClassNotFoundException.
Lastly: I have been using LuaJ successfully for months, so what changed? Apparently, when I upgraded to 3.0 several months ago, Eclipse never actually recognized the file change. It was only when I refreshed and cleaned the project that Eclipse realized a new version of LuaJ was present. Because the main project in LibGDX is source-files only (assets are in -android), you almost never click "refresh". Thus, the LuaJ problem has been a time-bomb of sorts.
I plan on submitting a support ticket to the author so he can address this issue. Until he does, I advise Android developers to stay with LuaJ 2.0.1!

Also you can fix it with your class Helper.
Create package: org.luaj.vm2.lib.jse
In this package create following class:
package org.luaj.vm2.lib.jse;
public class Helper {
public static JavaClass forClass(Class c) {
return JavaClass.forClass(c);
}
public Class<JavaClass> huskClass() {
return JavaClass.class;
}
}
Then create something like bridge class:
public class LuaBridge {
public Varargs getClass(String clazzName) {
try {
Class clazz = Class.forName(clazzName);
return Helper.forClass(clazz);
} catch (Exception e) {
e.printStackTrace();
Crashlytics.logException(e);
}
return null;
}
}
And now when you run your script you can pass instance to your lua script:
_globals = JsePlatform.standardGlobals();
_bridge = new LuaBridge();
//...
_globals.loadfile(scriptName)
.call(CoerceJavaToLua.coerce(_bridge));
Inside your LUA script:
First line:
local luaBridge = ...
-- some code here...
UserManager = luaBridge:getClass("com.dexode.cree.ScriptPlayerCreate")
-- used like luajava.bindClass("com.dexode.cree.ScriptPlayerCreate")

Related

Why is Java RunTime has reported a java.lang.NoSuchMethodError on Hex.encodeHex() method call?

I had to include some bittorrent java library to my Android project. My workspace: Android Studio 1.0.2 (osx) and jdk8. I've connected its maven-repository (ttorrent:1.4) with Gradle and after starting using main classes and features i've got an error:
java.lang.NoSuchMethodError: No static method encodeHex([BZ)[C in class Lorg/apache/commons/codec/binary/Hex; or its super classes (declaration of 'org.apache.commons.codec.binary.Hex' appears in /system/framework/ext.jar).
I went to library's code and find out that it's using org.apache.commons.codec from where ttorrent is importing encodeHex and calling it. Looks like binaryHex method is gone! Or it never been. But I went to commons.codec's code and found binaryHex in its place and with arguments that I was looking for. How come? Why? My Android Studio found it. But java runtime not.
In fact, the decision was more difficult than I thought. Let's start with the fact that I came across an article by Dieser Beitrag'a, from which it is clear that not one I had similar problems. The whole thing turned out that within the Android operating system already has some libraries that have a higher priority use, rather than loaded with dependencies along with the application. Among them there and my org.apache.commons.codec.
Yes, such things.
To solve the problem in two ways, either you need to pump source code library and using some tool to rename the project (i.e. org.apache.commons.codec to org.apache.commons.codec.android), collected it to a .jar file, include .jar in a project and at code use imports of the necessary classes only "our" library, or just get the required class to your project and do not pull a megabytes of unneeded code. However, I did just that.
Thanks for help!

SelendroidDriver not in jar file

I have recently written a Selenium program in Java that works perfectly with the FireFoxDriver(). My step 2 is to be able to run this program on my Android device with Selendroid. I went on their website here and have been able to download the jar and connect to their localhost with port:4444.
However, when I try their example, Eclipse doesn't recognize the SelendroidDriver() and suggests me to go back to WebDriver().
Here is their code:
SelendroidCapabilities capa = new SelendroidCapabilities("io.selendroid.testapp:0.10.0");
// My error appears when I create the new SelendroidDriver().
WebDriver driver = new SelendroidDriver(capa);
WebElement inputField = driver.findElement(By.id("my_text_field"));
Assert.assertEquals("true", inputField.getAttribute("enabled"));
inputField.sendKeys("Selendroid");
Assert.assertEquals("Selendroid", inputField.getText());
driver.quit();
I have also noticed that the SelendroidDriver class does not appear in my files although I downloaded the Selendroid jar file, version 0.10.0.
For those of you who are curious about how I fixed my problem, here is what I did:
I went to this site to get the selendroid-client jar file corresponding to the standalone version I had.
Downloading the standalone jar file was somehow not enough.
I was facing the same problem till I found the SelendroidDriver class here. Import this and change the package name according to your project.
SelendroidDriver.java has classes implementing interface methods, which in Java 1.6 can be annotated with #Override. However, in Java 1.5, #override could only be applied to methods overriding a superclass method.
Go to your project preferences and set the "Java compiler level" to 1.6 and also make sure you select JRE 1.6 to execute your program from Eclipse.
After adding this class, you would still see multiple dependency errors, but now in the SelendroidDriver.java file. You can import these classes now to counter these errors. Ensure that the package hierarchies are maintained correctly, in accordance with the GitHub directories and your working project.
After importing all these classes, the constant fields SWITCH_TO_CONTEXT, GET_CONTEXT_HANDLES and GET_CURRENT_CONTEXT_HANDLE were not being resolved. I used a poor workaround of changing them to some other available constant field for testing this sample.
I struggled a lot with this error and finally came to know that the paths have been changed in the latest releases. Use these paths and it shall work:
import io.selendroid.common.SelendroidCapabilities;
import io.selendroid.client.SelendroidDriver;
Tested this for versions 0.15.0 & 0.17.0

NanoHTTPD: How do I add it to a current Java eclipse project and use it?

This is my first time with Java and Eclipse. I started a brand new Java project and I want to import/add NanoHTTPD into it. How do you this?
This is NanoHTTPD's site: http://nanohttpd.com
Thanks!
Edit
Lesson learned, be specific or you get backslashed for asking. I edited the question and here's some background and the problem I'm running into.
I'm developing a Nodejs backend that needs to query a JAVA project I was given. Pipes are a no go because the services will run on different machines. Tomcat seems like an overkill so I decided to use NanoHTTPD to develop the web service. I come from Ruby & Nodejs so compilation and Eclipse are very new to me. First off, I have no JAR file just TAR and ZIP and from what I read they are fundamentally different. However, I tried importing the TAR and ZIP files as recommended but the structure I get in Eclipse does not seem right compared to the JRE System Library or others I've seen. Notwithstanding, I went ahead and tried to import the package from my Main.java file
package fi.iki.elonen;
public class Main {
public static void main (String[] args)
{
System.out.println("Main");
}
}
When I try to run it I get the following error:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
at Main.main(Main.java:4)
I found a great article from IBM "Managing the Java classpath (UNIX and Mac OS X)" where it mentions that an IDE such as Eclipse can alleviate the pain of dealing with the source path, classpath and compilation. Unfortunately, I'm afraid this is where I might be getting stuck.
I tried uploading images of what I have but apparently I'm not popular enough yet to do it.
Could someone help me figuring out how to not only import libraries but using them on projects? Even just a URL to a clear Linux/Mac OS X post that explains import with multiple packages would be great.
NanoHTTPD is designed to be very lightweight.
I just cut and pasted the 'NanoHTTPD' class from the source on github, its all in there - and pasted it as a class into my own project.
Then I created a subclass of nanoHTTPD, overrode the 'serve' method to send my own stuff and it was job done.
Download the jar, drag it into the project, and right-click it to add it to the build path.

How do you create a jar file of classes that can be re-used by multiple Android projects?

Here are the steps I have followed so far, with no luck. I am extremely new to Java projects so I suspect I may be missing something obvious.
Using Eclipse, I have created a simple Java project called TestSDK, created within that a package called com.test.testsdk, and within that the following class:
package com.test.testsdk;
public class TestClass {
public void TestMethod() {
}
}
This compiles without errors or warnings.
I then export this as a JAR file (TestSDK.jar) using Eclipse and the standard export options (export generated class files and resources, compress the contents of the JAR, generate manifest file). I have tried both sealing and not sealing the JAR which makes no difference.
I then create a new Android application project from File->New->Project in the Wizards list. This compiles and runs without warnings or errors on both the Android emulator and my test device (I get the hello world message).
I then add a reference to my TestSDK.jar file (using a variety of different methods as I will expand on shortly), import it into the main (and only) Android activity, and try to instantiate my TestClass and call TestMethod on it, like so:
package com.apptest.mobilesdktestapp;
import android.app.Activity;
import android.os.Bundle;
import com.test.testsdk.TestClass;
public class MobileSDKTestAppActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TestClass test = new TestClass();
test.TestMethod();
}
}
This compiles fine without warnings or errors. When trying to run it on the emulator or the device, however, I get the following error in my LogCat window:
AndroidRuntime Uncaught handler: thread main exiting due to uncaught exception
AndroidRuntime java.lang.NoClassDefFoundError: com.test.testsdk.TestClass
Searching the web for the NoClassDefFoundError results in a lot of suggestions on how to import the JAR file such that the class path is correct. As a result, I have tried all of the following methods of importing the JAR file:
"Add External JARs..." from the Libraries tab of Java Build Path in the project properties, followed by checking (or not checking, I tried both) the JAR in the Order and Export tab. Also tried moving the JAR to the top of the Order and Export list, which made no difference.
Creating a "libs" folder in the project, and adding the JAR there. I confirmed that the JAR is then also added to the "Android Dependencies" thing in the project list. Also tried right-clicking the JAR file and selecting Build Path->Add to Build Path which made no difference.
Moving the JAR into my Android Application project directory and doing "Add JARs..." instead of external JARs as in step 1, also all permutations of exporting or not and moving it to the top of the order list or not.
I have subsequently downloaded other 3rd party SDKs that are packaged as JAR files and included those in the very same Android application project, and those have all worked fine using any of the 3 methods above (I am able to instantiate classes from those SDKs and use them without error), which leads me to believe I am missing something or doing something wrong in my TestSDK project and/or class which is preventing it from being used in the Android Application project.
As I said, I am very new to Java, so I'm hoping it's something simple that I've overlooked. Any help or guidance would be appreciated.
If you are on R17 or higher version of the Android tools and ADT in Eclipse, then the first sentence of #2 is the correct answer; everything else listed in your question is unnecessary at best or harmful at worst.
I would recommend that you create a clean project, create the test activity, create the libs/ folder, copy the JAR into the libs/ folder, code to the JAR's API, compile, and run. If that works, then your original project still has stuff lingering around from your previous efforts that is causing you grief. If it fails, then something fairly strange is going on. The JAR itself is presumably fine, otherwise you would get compile errors.
I think I figured out what the issue was (or at least how to fix the issue, I'm still not 100% sure what I did)--
When I created the original TestSDK java project, I let it target the default JRE in the project creation dialog (jre7).
Checking the project properties of a new Android Application project, the Java Compiler section has "Compiler compliance level" set to 1.5. So, I tried recreating my TestSDK project again, but told it to use J2SE-1.5 as the execution environment instead of the defalut jre7.
After doing this, exporting the JAR and importing it to the Android project's libs directory, I am now able to instantiate the TestSDK classes and use them just fine without the NoClassDefFoundError exception.
Best guess is that the Android application was being compiled against an older version of the JRE than my TestSDK class (which I believe was targeting JavaSE-1.7), causing the issues. Matching the two versions up has solved it.

Can't compile an application using Eclipse, Maven, and the Android Plugin for Maven

I'm trying to create an Android application in Eclipse using the Maven plugin and the m2eclipse-android-plugin as well. Things were going "ok" until recently. I'm using Helios on Ubuntu and have the latest JDK (removed the default one installed by Ubuntu).
The project references two libraries that I've also created. One is an Android specific utility project and generates the .apklib (successfully). The other library is a more general purpose set of utilities not specific to Android which produces a JAR file. Both of these projects are also built using the Maven plugin for Eclipse. In addition, I've verified that both the .apklib and .jar files are in the local repository and both included all of the generated class files as would be expected.
When it goes to build the .apk file, I'm getting a "cannot find symbol" on a class in my Android project where the symbol is a class from the non-Android utility JAR file. For some completely bizarre reason, the class file cannot be found inside the JAR file. I verified that, in fact, the JAR file is in my local maven repository and that the class file is in the JAR file. I've also run the maven install command with debugging on, copied the command line that gets fed into the Java compiler. When I execute that command in a console, I receive the SAME error (indicating that it's a Java compiler error and not a Maven error).
Has anyone else run into this type of situation before? It's extraordinarily strange and I've completely combed the command line for potential issues and, best as I can tell, everything seems correct.
Well, through what appears to be trial and error I seem to have fixed the problem. I had a file that looked "similar" to this:
import Test.TestObserver;
import com.myself.ImportedClassThatCouldntBeFound;
class Test extends ImportedClassThatCouldntBeFound {
public interface TestObserver {
public void event ();
}
public void addObserver (TestObserver observer) {
...
}
}
public class AnotherTest {
private Test test = new Test ();
public void blah () {
this.test.addObserver (new TestObserver () {
public void event () {
...
}
});
}
}
The problem happened at the TOP of the file. For some reason, Eclipse imported the inner interface!
When I "REMOVED" that import, and then changed AnotherTest to:
public class AnotherTest {
private Test test = new Test ();
public void blah () {
this.test.addObserver (new Test.TestObserver () {
public void event () {
...
}
});
}
}
it compiled correctly! I even verified it by putting the import BACK into the file and removing the fully declared interface name and it caused it to fail again! It's definitely one of the craziest compiler issues I've ever seen and once I get back the FOUR HOURS of my life that I lost researching this, I'll do more investigation into why this is occurring.
This will be the first time I do this on StackOverflow, but I'm going to mark this as the solution because it most definitely was the issue. However, it definitely requires more research (at least on my part) to try and understand what was causing the compiler to become so confused.
edited this to make it apparent that the class that had the inner interface was extending the class that could not be found when compiled
To me, it looks like a problem caused (ultimately) by putting two top-level classes into a single source code file. This is generally thought to be bad practice.
It is not clear whether the compilation error is mandated by the JLS, whether it is a bug in the Java compiler. But either way, the best fix is to not put multiple classes into one source file.

Categories