0

So, I'm working on a Java application and I'd like to package resources into jar files to make them more portable. These jar files would be separate from the application and would only contain assets (images, sounds, save files, etc).

What's the simplest way to access arbitrary resources from inside a jar file like this? I've looked around a bit, but haven't been able to find any simple tutorials. I know that I can retrieve input streams from a Jar file with a ClassLoader but how do I get a ClassLoader that references the correct Jar?

Also, how can I programmatically bundle a bunch of resources into such a jar file? If I can get this working the way I want, I'd like to use it for a bunch of stuff, and would like to be able to dynamically create any needed archives.

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
CodeBunny
  • 1,991
  • 5
  • 22
  • 32
  • The "correct jar"? You're going to have resources with the exact same packaging and names? – Dave Newton Jun 15 '12 at 04:04
  • For a variety of reasons, I recommend `getResource("/path/to/the.resource")` over `getResourceAsStream`. See the [info. page on embedded resources](http://stackoverflow.com/tags/embedded-resource/info) (in which I list the alternative without explanation). – Andrew Thompson Jun 15 '12 at 05:00
  • @DaveNewton - No, of course not, I'm simply referencing the fact that I want to target a specific external jar. – CodeBunny Jun 15 '12 at 13:06
  • @AndrewThompson - Okay, I can see why that could be a good idea. Thanks for the tip. – CodeBunny Jun 15 '12 at 13:06
  • @CodeBunny Why? If the resource has a unique qualifier, you don't need to specify the jar. – Dave Newton Jun 15 '12 at 13:14
  • @DaveNewton I don't think you understand how I want to use the jars. For example, say I have a program that can dynamically use bundles of image files. These jars are not known at start and are accessed by my program at runtime. Also, I don't know anything about the specific files in the archives, so it's not that simple. – CodeBunny Jun 15 '12 at 14:01
  • @CodeBunny Then why do you even need jars? Be even *easier* to not require them on the classpath at all, and just allow associating normal zip files with the app. Whatever--six of one. – Dave Newton Jun 15 '12 at 14:03

3 Answers3

2

For reading resources, construct a new URLClassLoader with the URLs of the JARs you want to load from:

File jarFile1 = new File("myjar.jar");
File jarFile2 = new File("myjar2.jar");
ClassLoader myJarLoader = URLClassLoader.newInstance(new URL[] {jarFile1.toURI().toURL(), 
                                                                jarFile2.toURI().toURL()});

For creating JAR files, you can use the JarOutputStream class.

prunge
  • 22,460
  • 3
  • 73
  • 80
  • Sweet, thanks. I didn't know you could create ClassLoaders on the fly. – CodeBunny Jun 15 '12 at 13:07
  • 1
    Actually, I think you've chosen an overly complex solution. The **easiest** way to get resources is to add the Jar to the run-time class-path of the application. The best way to do that depends on *how* it is deployed. -- OTOH Establishing an `URLClassLoader` is very handy in specific situations, but not necessary for this one. Establishing a `ClassLoader` cannot be done in sand-boxed code, while the `getResource(String)` method works for either sand-boxed or trusted code. – Andrew Thompson Jun 15 '12 at 13:26
0

Shouldn't be a problem to use getResourceAsStream with the resource package path, provided that the jar with the resources is in the classpath of your application

A way to automatically create the resource.jar from your binaries is using apache ant for building, using a target like the following, you will take every res package resources and copy it into the destination jar

<property name="binDir" value="bin" />
...

<target name="resources-jar">
    <echo message="Generating resources.jar" />
    <jar compress="true" destfile="resources.jar" filesetmanifest="mergewithoutmain">
        <fileset defaultexcludes="true" dir="${binDir}"> 
            <include name="**/res/**" />              
        </fileset>
    </jar>
</target>  

For example, due the following packages

 com/myapp/logic 
 com/myapp/logic/res
 com/myapp/menu
 com/myapp/menu/res 
 com/myapp/actions
 com/myapp/actions/res

The resource.jar file will contain the following packages:

 com/myapp/logic/res
 com/myapp/menu/res 
 com/myapp/actions/res

Also you can change res for assets

higuaro
  • 15,730
  • 4
  • 36
  • 43
0

I jar file is in classpath Thread.currentThread().getContextClassLoader().getResourceAsStream(path/file.ext) will load the resource by name.

jar -cvf jarname.jar resource

will add all the resources to jarname.jar, try using ZipOutputStream to programatically achieve the same.

Subin Sebastian
  • 10,870
  • 3
  • 37
  • 42