I'm using JNI in my app. In Java classes which need native things I load the native library like so:
static
{
System.loadLibrary("nativeegl");
}
To be honest I don't know what the static thing does exactly, but I guess this is to make sure that the nativeegl library is loaded before anything else. Don't remember where I got this pattern from.
Now if this is a View subclass, and I'm using the graphical editor in Android Studio, the editor can't load the view subclass because of this exception:
java.lang.UnsatisfiedLinkError: no nativeegl in java.library.path
Since View.isInEditMode() is an instance method, I can't use it within the static{} block.
Is there an alternative? Maybe I can load the library differently?
Now that I think about it, one possible workaround is to split your View code into two classes: the actual View, and a separate standalone class that contains your JNI code, including the static block. For the purposes of the rest of this answer, I'll call these FooView and BarWrapper, respectively.
Then, only reference BarWrapper from code in FooView that is inside an if (isInEditMode()) block.
This may prevent BarWrapper from being loaded by the Java/pseudoAndroid environment used by the GUI builder, and therefore not trigger the attempt to load your native library. Leastways, the Dalvik classloading rules would cause BarWrapper to be ignored, as classes only get loaded when they are first used, and in your case you would be skipping over all code that uses BarWrapper. Hopefully, the GUI builder code adheres to how Dalvik handles it, though that's far from assured, since it's running on a Java VM, not an Android VM (Dalvik or ART).
It may make your code a bit more clunky, as you have to split out your logic between two classes instead of just one. But, it may be worth an experiment.
Related
I stuck with a problem. I use Chilkat for Java and as i understand there is no, any Maven Repo for it. As it is a two-component library - i need to inject .dll, via System.load(). This part is clear to me, but also they provides something, like wrapper, which calls methods in .dll.
So, i don't want to import their .jar to my project, but, then i call native methods by my own it fails with java.lang.UnsatisfiedLinkError. Because, then java tries to invoke a native method it adds some stuff at the beginning of it's name. For example: if i declare native method in my package, then it will be invoked, java will add all package hierarchy names to it's name.
Can i somehow call directly the native method by it's name, without any runtime "adaptations" ?
javac can generate the bindings you might be looking for ...DLL export viewer (among several others) can list exported methods. Or for SO, just use dumpbin /EXPORTS ./filename. That method names would change at runtime is not a reality, this only happens once when obfuscating them, at build time - which usually excludes all the objects, which need to stay accessible (for reflection).
Just start a new JNI project and learn how it works with vastly reduced complexity. There still is a chance, that this one JAR might pass licensing information in the native assembly - or that the native assembly performs cryptographic functionality for the JAR. An a commercial library is not to be treated alike open source - I'd read THEIR licensing terms, to begin with.
Lets say that a lot of functionality are using methods from this class test.MyClass, but it's very slow and I'd like to code in JNI in hopes of improving the timing...
Is there a way to replace test.MyClass so that the library does not need to be changed, but the codes in the library will use the new test.MyClass with native implementations for certain methods from now on? It's the classic "PC is fine but the timing for Android is crap" problem.
Just create your test.MyClass in the same package/hierarchical structure as the one in the package you want to override. The classloader should load your implementation first and if it tries to load the one from other library the load will fail, because there can be only one loaded instance in the classpath.
I am trying to build an application that runs under JavaSE and Android. Most of the code is the same between the two, but there are some specific functions that need to be separated. I use Eclipse. So I decided to put the shared code in a separate project, and then build one more project for Android and one for Java, which reference the shared project. I put all Java and Android specific functions in one class residing in the Java and Android specific projects. These classes are called UtilsJ (for Java) and UtilsA (for Android). The code in the shared project uses a factory to determine at runtime which version it needs to pick, and then calls the class loader to load the right class. Essentially: if property java.vm.name equals Dalvik, load UtilsA, else load UtilsJ (and of course cast to the Utils interface before returning).
My question is simply if this is a good idea or is something going to eventually break? I've never used class loader before. Any other suggestions how to implement this sharing would also be appreciated.
Generating an interface implementation dynamically is certainly a valid technique. For instance, having a data access interface that has multiple implementations; one each for flat files, MySQL and WebDAV. The program can pick an implementation at run time based on system/platform properties.
But this feels different. If I saw that I had a Java app and an Android app that had a lot of common code, my goal would be to create an Eclipse project that generates a jar file that I could just drop into the libraries of both projects. In that case, the jar file wouldn't contain any code that was incompatible with one platform or the other. So there wouldn't be any reason to have a platform-specific implementation.
Let's take your example some code reading an initialization file. If it's common code, you have an input parameter which is a file. On Android, maybe it's "/data/data/com.whatever.blahblahblah" and on Java you're getting the "user.dir" system parameter for the top level directories. But one way or another, it's a File, and you hand it to your common setup method. That's okay. But if your initialization file read code e.g. needs a Context to get a Resource to read the file for Android, then it's not common code. And it doesn't belong in a library jar for a JVM-hosted app.
So I think that in your case the platform-specific implementation classes are overkill. If it's common code, it's the same code — period.
Let's talk about another example in your comment. If you are using desktop Java, then you are probably using Swing or AWT, so you still have the same issue of running some network task off the UI thread, notifying when it completes, maybe even updating some progress indicator UI while it's processing. Same function, same operation, but the code is so different that I can't see how having it in the same library next to an AsyncTask version could be of any benefit.
And testing might get tricky. Obviously JUnit will work for everything, but some tests would need to run on a device or emulator.
I stated that it was a valid technique, and of course you may have other compelling reasons to choose the multi-platform option. You asked the question; is anything going to break? My answer is: Probably not, but why risk dealing with some heartburn down the road? Speaking for myself, I wouldn't do it. If I had to support multiple MVC apps, my common library would have nothing but M.
For a project, we need a way to run user scripts that can come with attached JAR files with additional classes.
What are my options when I want to write a couple of tests to make sure normal script don't leave anything dangling behind?
I specifically need to know: Are all classes from the attached JARs "unloaded"?
Note: I'm not looking for the 100% super-watertight solution that works across all versions of Java from 1.0 to 7. Right now, I just need to be better than "I have no idea".
The likely best option is to ensure your loaded jars are loaded by a specific class loader, and then to discard that class loader (after discarding all the objects).
As far as unit testing the unloading, if you go with this option, you need to extend your testing framework and customized class loaders to have a "create class loader on demand" flag. Then you load the class once with the flag on, discard the class loader, and attempt to load the class again with the flag off. If the class is truly not reachable, the second attempt should throw a class not found exception. You then wrap your unit tests to pass if they fall into the exception, and fail if they succeed in hitting the line after the second load attempt.
If you are disposed to use more than pure-Java tools, an OSGi container might be a consideration. Most of the established OSGi container implementations explicitly test class unloading.
I wouldn't try to unit test this. Instead, I'd run the JVM with -XX:-TraceClassUnloading and look to see if the classes in question show up in the trace output.
It looks like what you want to test is that hose scripts don't have a classloader leak.
To do that, I'd create a WeakReference to the ClassLoader used to load that JAR, then run the script, then call System.gc() and afterwards assertNull(reference.get())
This depends entirely on the way you allow the scripts to run. Do they have access to the classes of the rest of the application?
The typical way to leak memory in Java is to have a static reference. A static reference is only static within the ClassLoader of the class that contains it. So, if you load your user scripts using a ClassLoader you manage yourself (and you should do this anyway), then the references (static or not) inside will be eligable for GC as soon as your classloader itself it.
The only way they could work around this, is to add a reference to one of their objects into one of yours. So you have to be very careful with the API you expose. Another way is if they would make a static reference to their class in a class from another ClassLoader.
I don't see a way to fully automate testing for this. But I suppose you could trace the class unloading with any decent profiler.
I'm quite restricted in the platform I'm currently working on (JDK 1.3, BD-J). One JAR file I would like to use attempts to perform a self-integrity check on load and if it fails it goes into an inoperable state. It's quite difficult to find out why this is happening but most sources point to that it cannot find/access it self through the BD-J structure, so it dies.
This rules out using it at load time and instead to load it in the application itself. This is quite a large library so I have to create quite an amount of interfaces so I can cast a loaded object to it and potentially use it. This is where my problem lies.
The interfaces are loaded on normal load time and the library is then loaded during run time and casted to the previously loaded interfaces, is this a problem? I'm receiving ClassCastException
I've based the interfaces off the libraries public methods as best I can, but when I attempt to cast to an interface I receive the ClassCastException. Note: It all loads fine, I can access constructors and read the method names. Just when casting it for it to be useable it fails.
The interface packages are different in my project to that of the toolkit, does this matter?
I'm running out of ideas, is there something I have overlooked?
Thanks.
I'm not sure I fully grok what your problem is - maybe some more details about what the class hierarchy looks like would help in figuring out the situation. From what you wrote I can guess two possible scenarios:
.1. The classes you want to use do not implement any interface.
In this case no matter what you name your interfaces, it will not work, since the classes you're loading do not implement them. You're stuck with using reflection if you can't load that jar as part of the boot classpath.
.2. The classes you want implement some interface that you're trying to replicate.
In this case you interface implementation must match the exact qualified name of the interface the classes are implementing. Normally, when loading the classes from the jar, the class loader will pick up the interfaces from the system class loader first, thus loading your interfaces, and everything should work.
If they use some crazy internal class loader, though, they might still try to load their own interfaces. You could try to figure out if that's the case by using "-XX:+TraceClassLoading", although I don't know if the 1.3 jre will understand that option.
Now if you're willing to experiment more, you could also try another approach. Write your own class loader that loads both the classes from that jar and the code you want to run. That way, your code would be able to directly refer to the classes in that jar, but to start your application the "main" method will have to be one that initializes this classloader, loads the "real" main class using reflection, and executes its main() method also via reflection.
Most probably the classes are loaded by different class loaders. http://mindprod.com/jgloss/classloader.html may give some idea.