views:

249

answers:

2

Hello!

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"&gt;
      <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. :)

A: 

Project properties -> Libraries -> Compile time -> Add JAR/Folder, or something like that

gpeche
Apart from title and tags, did you read the question message as well?
BalusC
Sorry, skipped the last paragraph. If you include the folder through Project properties -> Libraries -> *Run* -> Add JAR/Folder (using a relative path), it will include a reference in the MANIFEST.MF as lib/art, without including the folder in the JAR. Then it should be a matter of putting the art folder inside lib at runtime.
gpeche
+1  A: 

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)

URL resource = ClassLoader.getSystemResource("gui/refresh.png"); // pay attention to relative path
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

with regards
Tushar

Tushar Joshi
Your suggestion nearly solves the problem, but (there's always a 'but' ;-)):
ChristianS
1) adding something to the NB project manifest.mf file (that is the Class-Path in this case) seems to override anything else that would otherwise go there (e.g. the other libraries added to the project). Any idea how to get the original path back as well? For example the libraries itself would be copied.3) for me it does not work without the leading slash - i have to add that slash, then it works.
ChristianS
I would suggest first generating the manifest.mf from NetBeans build and then using those default class path values plus your additional directory paths added.
Tushar Joshi