Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add resources to classpath

How do you add a folder (e.g. a resource folder containing arts) to the classpath of a netbeans project? I managed to do that manually via editing the NB generated jar file of the project (that is its MANIFEST.MF file + copying the resources manually), but there should be a way to tell netbeans as well to mind the resources, no?

The folder structure looks like this:

/project/art/
/project/dist/lib/
/project/dist/art/
/project/dist/project.jar
/project/lib/
/project/src/

I don't want to package the art into the jar because I'd like the art to be easily exchangeable. If I add the art folder to the src folder then NB compiles fine, but the art resources end up in the jar.

Adding the art folder to the netbeans project libraries (Properties -> Libraries -> Add JAR/Folder) seemed not to work, because then I ended up with an error '...\project\art is a directory or can't be read. Not copying the libraries.' which in turn prevents even the real libraries folder from being copied.

Any ideas?

Best regards Chris

2 Observations made, based on the comments from gpeche: a) Rather specifying the additional resources folder in the "Run" tab than in the "Compile" tab of the project properties -> Libraries doesn't seem to make a lot of difference in Netbeans (I'm currently using 6.9.1). The output (and thus error) stays the same, that is nothing gets copied at all:

Created dir: C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\dist
C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\art is a directory or can't be read. Not copying the libraries.
Not copying the libraries.
Building jar: C:\Users\Chrisi\Desktop\vocabulary\VocabularyTrainer\dist\VocabularyTrainer.jar

Another interesting aspect is that in the help menu of the Libraries panel nothing is explicitly mentioned regarding folders as libraries. Could it be possible, that the button in Netbeans is falsely named, that is only real jar's are allowed?

b) Adding the resources folder to the Libraries list does have the impact though, to add another entry to the MANIFEST.MF. While - and that's the smaller issue - the classpath entry seems to be always expecting the resource folder to be a subfolder of the library folder (e.g. "lib/arts") the major problem is that there seems to be a slash missing. As mentioned the NB generated entry in the MANIFEST.MF will look like this "lib/arts" (which does not work for me), while (manually set) "lib/arts/" does?!

The way I use resources from the folder is something like this:

URL resource = getClass().getResource("/gui/refresh.png");
ImageIcon tmp = new ImageIcon(resource);

Edit:

Based on Tushars comment and this posting I found the following solution to be an acceptable tradeoff between functionality and comfort.

I override the ANT target from the auto generated 'build-impl.xml' file which creates the Class-Path in the MANIFEST.MF file in the basic 'build.xml' file of the Netbeans project. The code which goes to the 'build.xml' file looks like this:

  <property name="art.classpath" value="art/" />

  <target name="-post-jar">
    <mkdir dir="${dist.dir}/art"/>
    <copy todir="${dist.dir}/art">
      <fileset dir="${basedir}/art">
        <!-- <exclude name="**/!source/**"/> if you want to exclude something... -->
      </fileset>
    </copy>
  </target>

  <target name="-init-macrodef-copylibs">
    <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
      <element name="customize" optional="true"/>
      <sequential>
        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
        <pathconvert property="run.classpath.without.build.classes.dir">
          <path path="${run.classpath}"/>
          <map from="${build.classes.dir.resolved}" to=""/>
        </pathconvert>
        <pathconvert pathsep=" " property="jar.classpath">
          <path path="${run.classpath.without.build.classes.dir}"/>
          <chainedmapper>
            <flattenmapper/>
            <globmapper from="*" to="lib/*"/>
          </chainedmapper>
        </pathconvert>
        <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
        <copylibs compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}" manifest="${manifest.file}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
          <fileset dir="${build.classes.dir}"/>
          <manifest>
            <attribute name="Class-Path" value="${jar.classpath} ${art.classpath}"/>
            <customize/>
          </manifest>
        </copylibs>
      </sequential>
    </macrodef>
  </target>

The tradeoff is that for development in Netbeans I still have to add the resource folder (e.g. 'art') to the libraries list to make the project run in Netbeans. This will cause an additional entry in the MANIFEST.MF file ('lib/art') along with the effect that the libraries will not get automatically copied to the 'dist' folder, with the message

...\art is a directory or can't be read. Not copying the libraries.
Not copying the libraries.

This behavor is - afaik - intended (to force everything to be bundled up in a jar), even though there are discussions about it going on. To make a real distribution bundle I'd have to take away the resource folder(s) from the library list in NB and rebuild.

Ideas about a more streamlined setup without any tradeoffs are of course still welcome. :)

like image 714
ChristianS Avatar asked Sep 15 '10 13:09

ChristianS


People also ask

What is a classpath resource?

A resource is file-like data with a path-like name, which resides in the classpath. The most common use of resources is bundling application images, sounds, and read-only data (such as default configuration). Resources can be accessed with the ClassLoader. getResource and ClassLoader. getResourceAsStream methods.

How do I load a file in classpath?

We can either load the file(present in resources folder) as inputstream or URL format and then perform operations on them. So basically two methods named: getResource() and getResourceAsStream() are used to load the resources from the classpath. These methods generally return the URL's and input streams respectively.

How do I add a resource file to a JAR file?

1) click project -> properties -> Build Path -> Source -> Add Folder and select resources folder. 2) create your JAR!


1 Answers

  1. Adding resource folder to classpath:

    When you Clean-&-Build a NetBeans Ant Based Project it creates a manifest.mf file in the root directory of the project. This file gets included in the JAR file also. Modify this file and add entry like follows:

    Manifest-Version: 1.0
    X-COMMENT: Main-Class will be added automatically by build
    Class-Path: arts/  
    

    slash is important after arts in the class path.

  2. Including the arts resource folder in the distribution

    Either copy this folder in the dist folder after the build or add a ANT target to copy the required resources in the dist folder.

    Add the target like as follows in the build.xml file:

    <target name="-post-jar">
         <mkdir dir="${dist.dir}/resources"/>
         <copy todir="${dist.dir}/resources">
             <fileset dir="${basedir}/resources" />
         </copy>
     </target>
    
  3. Code to access such resources:

    The code needed to access such resource files shall be as follows: (This will not work in design time but surely from the JAR file)

    // pay attention to relative path
    URL resource = ClassLoader.getSystemResource("gui/refresh.png"); 
    ImageIcon tmp = new ImageIcon(resource);
    

    NOTE: The files manifest.mf and build.xml located in the root directory of the project are accessible from the Files Panel in NetBeans IDE

like image 140
4 revs, 2 users 67% Avatar answered Sep 20 '22 12:09

4 revs, 2 users 67%