My Java program loads classes dynamically at runtime. All classes are located in the same jar.
After deploying a new jar file, I sometimes get errors while the jar file is copying (NoClassDefFoundError etc.). This goes away the next time I run the program of course. Is there a way to preload classes so that my program is not affected when updating the jar?
I guess I could create instances of all classes and then clone() them, but perhaps there's a better way?
Even if you load all the classes, you may still get errors from resources.
I suggest deploying to a different location if at all possible. Alternatively, if you can manager the class loading, copy the jar to a temporary file (which is automatically done for http URLs, for instance) or into memory.
Related
I know the file needs to be where the getClass().getResource(filename) can find it, but I don't know where that is.
I'm interested both in where to put the files on the filesystem itself, and how to go about using Eclipse's functionality to set up the resources.
For Eclipse, typically all you need to do is set up a folder somewhere within your source code directory. For instance, if the directory containing your source is /src then you can create a /src/resources folder to place your images/files in. Then, within your class you do a getResource("/resources/image.png") to retrieve it.
You can also place the image/file within the same folder/package as the class trying to access it if you wish (example: place the image.png in the com.mycompany package with the com.mycompany.Foo class that needs to access it and call getResource("image.png")), but I've found it's easier to keep resources like images and other files in their own special directory outside of the class folders -- they're just easier to manage that way.
In Eclipse, whenever you do a build, the files within this resource directory will be copied over into your build directory along with your compiled classes.
It's important to note that if you have "Build Automatically" turned on in Eclipse (as most people do) any resources in this directory that get changed outside of Eclipse (i.e. you edit an image using an image editing tool) that the IDE may not always detect this change. Usually doing a refresh on the project folder will ensure that the file gets updated in the build in these situations.
You can either put them in the src folder alongside your classes, or you can create a new source folder for the purpose (usually called resources), although you'll locate them identically from code.
Then you get at them using getResource("/com/x/y/foo.png").
Well, maybe it's convoluted, anyway...
I'm not very experienced with java, though I've dabbled in creating some Minecraft mods and Android apps.
My question is: I have a .jar that contains code that I don't have a lot of control on (I don't have the source code though I do have some infos about the classes in it), and when this jar is run it itself load some code from other external libraries and classes, and consolidate everything.
My question is then, how do I, without touching/modifying the jar, make a java program that runs the jar, let it do its consolidating from other jars and external classes, then get the results (a few objects) of that consolidating into my own java program ? Is that even permitted in the java security model ?
I've heard of URLclassloader that I think is to load load classes from a jar. It can't seem to make it work, and I'm not even sure that would work ? I know roughly which classes are entry point in the jar in order to run it and make it load the external libraries. But I always run into exceptions left and right.
First you should make sure all 3rd partyd dependencies (e.g. libraries that your jar needs) are ~visible~ to your application (e.g. reside on classpath and/or -Djava.library.path). Next, you should just instantiate classes/call methods from your jar file normally and operate with returned objects as its been locally created by your Java application. jar file is just an external library that becomes the part of your application upon loading.
in my Java project I am using an H2 in-memory database, for which I have to load the JDBC driver when I initialize my application. I want/need to load the H2 .jar file dynamically, so I do the following:
String classname = "org.h2.Driver";
URL u = new URL("jar:file:libs/h2.jar!/");
URLClassLoader ucl = new URLClassLoader(new URL[] { u });
Driver d = (Driver) Class.forName(classname, true, ucl).newInstance();
DriverManager.registerDriver(new DriverShim(d));
When I put the H2 .jar file into a "libs" folder outside my Java source code folder (that is, in Eclipse, this "libs" directory is on the same level as the "src" folder), then this approach works fine. However, unfortunately I have to put this H2 .jar file into a folder within the source code folder tree, but below the main class folder.
For example, my Java package structure looks like this in Eclipse:
<project>/src/my/app/MyApp.java // main class of my application
<project>/src/my/app/sub/package/h2.jar // how to access this?
<project>/libs/h2.jar // loading from here works
I know this is stupid, but unfortunately I have to work with this strange setup. But what I don't know: how can I edit my Java code (listed above) in order to work with this setup?
EDIT: This has to work outside Eclipse as well, so adding the JAR file to the Java Build Path in Eclipse is no option for me.
EDIT2: I already tried to load "jar:file:my/app/sub/package/h2.jar!/", but that did not work for me.
Thanks in advance for all helpful ideas!
Kind regards, Matthias
In some frameworks referring to files inside JARs can be done using the classpath: prefix. I doubt URLClassLoader supports it natively, but it's worth a try (e.g. classpath:/my/app/sub/package/h2.jar). But since that doesn't work with URLClassLoader, here are other ways:
One way to do it would be to write your own ClassLoader which reads the JAR file from classpath (using getResourceAsStream), uncompresses it (using ZipInputStream) to memory (e.g. a map of byte arrays) and loads the classes from there.
Another, slightly easier way, is to read the JAR file from classpath and write it into a temporary file. Then you can use the plain URLClassLoader to load classes from it. This has the disadvantage that the file must be written to a file and the file probably cannot be removed until the JVM exits (unless using Java 7 or higher).
I'm using the second approach (copying to a temp file) in one project, though I'm using it to launch an external process. I would be curious to hear why you have such a requirement. If it's just a matter of having the whole application in one JAR, there are numerous simpler methods for achieving that (Maven Assembly Plugin, Maven Shade Plugin, Jar Jar Links, One-JAR to name a few).
No it's not a homework, but an online build system that uses my classes under my/app/* and several other classes (not from me) to automatically build the whole solution. Anyway, I can't give you more details on the internals of this system, as I don't know them. As said, I simply have to live with it, and that is why I am asking here...
Sounds like you are working in a WTF environment (does it have a name?), so here are some ways to start hacking around it:
Find out more about your environment, especially absolute file paths of the following: directory where the source files are saved, directory where the generated .class files are saved, and the current working directory when the program is run.
If you can get any kind of output of what your program prints during runtime, you can put into your application some debug code where you use File.listFiles() to crawl the machine's directory trees. If you can get output only from what happens when compiling, it might be possible to execute your own code during compile by creating your own annotation processor (apt is part of javac since Java 6), though I'm not sure whether the annotation processor must be compiled first separately.
The working directory can be read from the user.dir system property and the location of class files can be probably gotten from the java.class.path system property (unless custom class loaders are used). There is no guarantee that a JAR file in the source directory would be copied to the classpath, so you might need to do some looking around.
Then when you know the file path of the JAR file, then you can get an URL to it using new File("path/to/h2.jar").toURI().toURL() which you can then pass to URLClassLoader.
If nothing else works, upload the source code of the libraries and compile them together with your project.
In the long run, try to replace the WTF build environment with one that uses a standard build tool (such as Maven) and a common CI server (such as Jenkins). It's normal for projects to have lots of library dependencies, so you shouldn't need to hack around a build environment to use them.
I have created a few classes in Java and have combined them into a single package in the 'org' namespace. How do I access them from RingoJS?
Must I copy the package into the 'src/org' directory in Ringo or do I have to modify the classpath dynamically from the script?
I finally figured out how to access custom Java classes in RingoJS. I must have been really stupid to have never seen it right in front of my eyes before.
In Rhino, to access custom Java classes you need to add them to your Java classpath. This can be tedious, especially when an end user without any knowledge about programming tries to install a CommonJS package which requires specific Java classes to be in the classpath. Correct me if I'm wrong. Package managers like Tusk might be able to do that for you, and I would really appreciate it if you would notify me about such a feature. However, as far as I know it's the end users responsibility to add the Java classes and/or jar files to the classpath.
RingoJS simplifies this a great deal. It provides a global function addToClasspath(pathName) which adds a JAR file or directory to the classpath. Thus we may have a Java package or JAR file in the root directory of the CommonJS package and use the addToClasspath function in the JavaScript file itself to automatically add it to the classpath. In addition, all JAR files in the RingoJS lib directory are included in the classpath by default. This simplifies matters a great deal.
For programming purposes you may add JAR files to the RingoJS lib directory. However, I wouldn't recommend it. To reduce coupling and keep the RingoJS lib directory clean (preventing future namespace problems); and to make installation for the end user easier, I suggest using the addToClassPath function. Perhaps it should be implemented in other Rhino-based CommonJS implementations as well.
I am building an update system in which I need to be able to replace a referenced jar of a running application jar at runtime. However, I am running into file locking issues on Windows when trying to perform file utility functions on the jar such as 'setLastModified'.
After some googling I found this snippet...
What I found in my research is that
the standard ClassLoader
implementation never closes a jar
file once it has been opened. It also
only loads resources from the jar file
as needed. So at any particular time,
there may be Classes in the jar file
that have not been loaded into memory.
Obviously, if you delete the jar file
out from under the ClassLoader, and it
tries to find a resource in the
missing file, you're going to get an
IOException at the very least.
Does anyone have any references to information on doing this, or working around this issue?
Thanks.
There is a lot of solutions for classes/lib hot-swapping :
Hotswap for ant
JRebel
OSGi
It depends on what you want to do.
The closest thing is OSGi
Please have a look at the 'See also' section of the mentioned artice for concrete products.
I don't know of any good way to deal with this. Creating a custom classloader might be an option, although I don't like that idea..
We worked around it by running an updater from a separate jar before launching the main application. This works well enough, but obviously, you can only update the jar when the application is launched.