views:

131

answers:

3

What is the simplest way to manage dependencies of Java classes to data files present in the classpath?

More specifically:
How should data dependencies be annotated? Perhaps using Java annotations (e.g., @Data)? Or rather some build entries in a build script or a properties file? Is there build tool that integrates and evaluates such information (Ant, Scons, ...)? Do you have examples?

Consider the following scenario:
A few lines of Ant create a Jar from my sources that includes everything found on the classpath. Then jarjar is used to remove all .class files that are not necessary to execute, say, class Foo. The problem is that all the data files that class Bar depends upon are still there in the Jar. The ideal deployment script, however, would recognize that the data files on which only class Bar depends can be removed while data files on which class Foo depends must be retained.

Any hints?

A: 

Can't you refactor your project so that you have submodules that each contain the relevant files for the project itself ; Bar class and Bar related files will be packaged in their bundle while Foo ones will packed into another?

Another possibility would be to use some package naming convention to be able to filter the files you want to see i your bundles.

Matthieu BROUILLARD
This would *implicitly* model the dependency of classes on data, however, in the extreme case this would mean one project per class, which is infeasible. Also, I'd hate if my data dependencies would dictate my component layout. Again, what is the simplest and most often used way to *explicitly* model code-data-dependencies? Thanks for your help!
Martin Potthast
+1  A: 

This is one of the many problems Maven has already solved with it's build, dependency, and resource management. Any maven project follows a standard directory layout which dictates where you should put your Data files: in the 'resources' directories. The conventional Maven directory structure is as follows...

/
/src/
/src/main/java/
/src/main/java/App.java
/src/main/resources/
/src/main/resources/my.prod.data.or.cfg.or.whatever
/src/test/java/
/src/test/java/AppTest.java
/src/test/resources/
/src/test/resources/my.test.data.or.cfg.or.whatever
/pom.xml

The benefit of this is that all files which are contained in the 'main' (prod) resources directories are available to your application at run-time from the Classpath. All of the 'test/resources' files are available to your code during build & unit test time but are NOT included in your final artifact.

Gweebz
Thanks for your answer, but I'm afraid this does not solve the problem: Does Maven *explicitly* annotate the dependency between App.java and my.prod.data.or.cfg.or.whatever? And does Maven automatically ignore the latter if the former is excluded during deployment?
Martin Potthast
I am not aware of any built in annotations that offer the functionality you are looking for. However, with the maven solution I explained above, you can use the line of code...ClassLoader.getSystemResource("classpath:/my.prod.data.or.cfg.or.whatever")The 'classpath:/' part is optional because it looks to the classpath first anyway by default but I like to be explicit. With this in mind, it shouldn't be too hard to write your own annotation to wrap this implementation. Look at the ClassLoader API for more info on this and it's other methods. Hope this helps in the right direction.
Gweebz
Separating data from code is a good idea, anyway. But again, this does not solve the problem of maintaining a strong tie between data and classes.In conclusion it must be said, unfortunately, that Maven does not support this.Can it be that there is no build system out there that implements a solution to this?
Martin Potthast
A: 

I don't think a generic solution exists for the system you describe, however, I just had a stab at reading annotations on classes using ASM, since that is used by jarjar as well. It is not hard to read the annotation data that way (pass in a ClassVisitor to the accept() method on ClassReader, and do something useful on the visitAnnotation callback). This means you can either try and include your intended behavior to jarjar or you could add it as a custom step to your build process.

Simon Groenewolt
This sounds like an interesting approach. Thanks! I am not entirely happy, though, since I'd have to do all the work myself, and the solution would be proprietary.
Martin Potthast