Code running under ant doesn't find a properties file unless I fork the JVM
I'm just getting started with Ant, and I'm having problems getting a "run" target to work. Part of my code loads a properties file, and it always fails to find this file unless I make my run target use a new JVM. Below is a very simplified example, the "run" target fails, the "run_fork" target works. My understanding is that Ant has it's own class loader that replaces the default one, so I imagine this is mucking with the search path somehow. Is there any way I can change my code to make this work without having to fork a new JVM?
build.xml:
<project name="PropsExample" default="compile" basedir=".">
<property name="src" location="src"/>
<property name="bin" location="bin"/>
<target name="init">
<tstamp/>
<mkdir dir="${bin}"/>
</target>
<target name="compile" depends="init">
<javac includeAntRuntime="false" srcdir="${src}" destdir="${bin}"/>
<copy todir="${bin}">
<fileset dir="${src}" includes="**/*.properties"/>
</copy>
</target>
<target name="clean">
<delete dir="${bin}"/>
<delete dir="${dist}"/>
</target>
<target name="run" depends="compile">
<java classname="com.example.Test">
<classpath>
<pathelement location="${bin}"/>
</classpath>
</java>
</target>
<target name="run_fork" depends="compile">
<java fork="true" classname="com.example.Test">
<classpath>
<pathelement location="${bin}"/>
</classpath>
</java>
</target>
example code:
package com.example;
import java.util.Properties;
import java.io.InputStream;
public class PropertiesLoader {
public static String getProperty() t开发者_开发百科hrows Exception {
InputStream in = ClassLoader.getSystemResourceAsStream("com/example/test.properties");
if ( in == null ) {
throw new Exception("Cannot find test.properties");
}
Properties p = new Properties();
p.load(in);
in.close();
return p.getProperty("test");
}
}
and:
package com.example;
public class Test {
public static void main(String[] args) throws Exception {
try {
System.out.println(PropertiesLoader.getProperty());
} catch ( Exception e ) {
e.printStackTrace(System.out);
}
}
}
ANT, having already launched by the time it reads the XML file containing your run's specified classpath, cannot actually reset the classpath of the running JVM. Instead it attempts to append to it as it goes with chains of classloaders; however, your call to the class loader is likely grabbing the root classloader. You might want to do something like this:
this.getClass().getClassLoader().getResourceAsStream("com/example/test.properties");
which would force the class to use the same classloader as it was loaded with. This should (hopefully) jump into the ClassLoader chain at the right spot, as if it loaded the current class and the properties file is appropriately "moved" along with the current class, then the properties file should be accessible through the same class loader.
Note that there are a lot of good reasons to fork the JVM anyway. The most important in my mind is to rid the entire JVM of ANT related classes. You don't want to accidentally bind your run time to classes which are only available during the software build process, and if you want to bind your classes to ANT, it should be managed as a 3rd party library (so you can control the versions it binds to, the degree of binding, the ability to reproduce the build identically across multiple versions / releases of ANT, etc.)
精彩评论