|
From: Colin S. <col...@ex...> - 2003-09-30 16:07:50
|
I actually added two convenience methods to ClassLoadUtils, for making
this sort of stuff easier:
/**
* Given an input class object, returns a string which consists of
the class's package
* name as a pathname, i.e., a leading '/' is added, and all dots
('.') are replaced by
* slashes ('/'). A trailing slash is <b>not</b> added.
* @param clazz the input class
* @return a path which represents the package name, including a
leading slash
*/
public static String classPackageAsResourcePath(Class clazz) {
StringBuffer retval = new StringBuffer("/");
if (clazz == null)
return retval.toString();
StringTokenizer st = new
StringTokenizer(clazz.getPackage().getName(), ".");
while (st.hasMoreTokens()) {
retval.append(st.nextToken());
if (st.hasMoreTokens())
retval.append("/");
}
return retval.toString();
}
/**
* Returns a path suitable for use with {@see Class.getResource}
build by taking
* the package of the specified class file, converting all dots
('.') to slashes
* ('/'), adding a trailing slash, and concatenating the specified
resource name
* to this. As such, this function may be used to build a path
suitable for loading
* a resource file that is in the same package as a class file.
* @param clazz the Class whose package will be used as the base.
* @param resourceName the resource name to append. A leading slash
is optional.
* @return The built-up resource path.
*/
public static String addResourcePathToPackagePath(Class clazz,
String resourceName) {
if (!resourceName.startsWith("/"))
return classPackageAsResourcePath(clazz) + "/" + resourceName;
else
return classPackageAsResourcePath(clazz) + resourceName;
}
These should make having a context definition (or any other resource)
that stays in the same package as a certain class trivial. E.g.
import ClassLoaderUtils;
public class MyClass {
private static String RESOURCE =
ClassLoaderUtils.addResourcePathToPackagePath(MyClass.class,
"myresource.xml";
...
}
Regards,
Colin
Colin Sampaleanu wrote:
> Yes, Class.getResourceAsStream will attempt to load out of the package
> where the code is executing, but don't forget, it is not your code (in
> your package), which would be calling getResourceAsStream, it is
> Spring's code, in its own package. It's actually even more complicated
> then that, because the call actually ends up going to Springs's
> ClassLoaderUtils, where the loading happens via a
> InputStream in =
> Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
> This is so that if you are in an environment such as a J2EE
> application server, where the context classpath has been set
> appropriately by the appserver in the current thread, the right
> classloader ends up loading the data. If Spring didn't do this, in
> some app server environments, a spring lib instance in the appserver's
> own support directory would be used as the basis of the classpath to
> search, and would never see the resources in the classloader farther
> down in the hierarchy.
>
> So what I would suggest doing is something like this:
>
> Define a utility method somewhere:
> /**
> * Given an input class object, returns a string which consists of
> the class's package
> * name as a pathname, i.e., a leading '/' is added, and all dots
> ('.') are replaced by
> * slashes ('/')
> * @param clazz the input class
> * @return a path which represents the package name, including a
> leading slash
> */
> public static String classPackageAsPath(Class clazz) {
> StringBuffer retval = new StringBuffer("/");
> if (clazz == null)
> return retval.toString();
> StringTokenizer st = new
> StringTokenizer(clazz.getPackage().getName(), ".");
> while (st.hasMoreTokens()) {
> retval.append(st.nextToken());
> if (st.hasMoreTokens())
> retval.append("/");
> }
> System.out.println("returning: " + retval.toString());
> return retval.toString();
> }
>
> then when you need to load resources relative to a class's package, do
> something like this:
>
> private static final String CONTEXT =
> FileUtil.classPackageAsPath(BasicMappedPersistenceTest.class)
> + "/BasicMappedPersistenceTestContext.xml";
>
> ....
> appContext = new ClassPathXmlApplicationContext(CONTEXT);
>
>
>
> As to whether this belongs in the user list or the dev list, it's
> somewhat of a grey area. That is, my explanation above definitely
> belongs in the user list, but this discussion could certainly have
> lead (or may lead) to further discussion about how to improve this
> area of spring, which is best handled in the dev list.
>
>
> Regards,
> Colin
>
>
> Keith Donald wrote:
>
>> Is it correct to always prepend a "/" to a resource path passed into
>> ClassPathXmlApplicationContext? This behaivior forces me to hard-code
>> fully-qualified references to my application context xml files.
>> Instead,
>> I'd like to be able to pass in a relative name and have
>> getResourceAsStream() attempt to load the resource out of the package
>> where
>> the code is executing (which is the default behaivior of
>> Class.getResourceAsStream().)
>>
>> For example, I have a context located in my classpath at:
>> /com/csi/cogids/console/console-context.xml. To load it, I must pass
>> that
>> full path to ClassPathApplicationContext(). Now say two weeks later I
>> re-factor and re-locate this code to another package--I have to make
>> sure I
>> update the reference. I'd rather just be able to say: new
>> ClassPathApplicationContext("console-context.xml") and have it by
>> default
>> look in the current executing class's package directory.
>>
>> Should I mail stuff like this to the developer list?
>>
>> Thanks,
>> Keith
>
|
|
From: Colin S. <col...@ex...> - 2003-09-30 16:27:49
|
Ughhh, please forgive the gratuitous use of StringTokenizer below, it's
gone now. I promise most of my code does take advantage of available
java library functions like Sring.replace() :-)
Colin Sampaleanu wrote:
> I actually added two convenience methods to ClassLoadUtils, for making
> this sort of stuff easier:
>
> /**
> * Given an input class object, returns a string which consists of
> the class's package
> * name as a pathname, i.e., a leading '/' is added, and all dots
> ('.') are replaced by
> * slashes ('/'). A trailing slash is <b>not</b> added.
> * @param clazz the input class
> * @return a path which represents the package name, including a
> leading slash
> */
> public static String classPackageAsResourcePath(Class clazz) {
> StringBuffer retval = new StringBuffer("/");
> if (clazz == null)
> return retval.toString();
> StringTokenizer st = new
> StringTokenizer(clazz.getPackage().getName(), ".");
> while (st.hasMoreTokens()) {
> retval.append(st.nextToken());
> if (st.hasMoreTokens())
> retval.append("/");
> }
> return retval.toString();
> }
>
>
> /**
> * Returns a path suitable for use with {@see Class.getResource}
> build by taking
> * the package of the specified class file, converting all dots
> ('.') to slashes
> * ('/'), adding a trailing slash, and concatenating the specified
> resource name
> * to this. As such, this function may be used to build a path
> suitable for loading
> * a resource file that is in the same package as a class file.
> * @param clazz the Class whose package will be used as the base.
> * @param resourceName the resource name to append. A leading slash
> is optional.
> * @return The built-up resource path.
> */
> public static String addResourcePathToPackagePath(Class clazz,
> String resourceName) {
> if (!resourceName.startsWith("/"))
> return classPackageAsResourcePath(clazz) + "/" + resourceName;
> else
> return classPackageAsResourcePath(clazz) + resourceName;
> }
>
>
> These should make having a context definition (or any other resource)
> that stays in the same package as a certain class trivial. E.g.
>
> import ClassLoaderUtils;
> public class MyClass {
> private static String RESOURCE =
> ClassLoaderUtils.addResourcePathToPackagePath(MyClass.class,
> "myresource.xml";
>
> ...
> }
>
>
> Regards,
> Colin
>
>
>
> Colin Sampaleanu wrote:
>
>> Yes, Class.getResourceAsStream will attempt to load out of the
>> package where the code is executing, but don't forget, it is not your
>> code (in your package), which would be calling getResourceAsStream,
>> it is Spring's code, in its own package. It's actually even more
>> complicated then that, because the call actually ends up going to
>> Springs's ClassLoaderUtils, where the loading happens via a
>> InputStream in =
>> Thread.currentThread().getContextClassLoader().getResourceAsStream(name);
>>
>> This is so that if you are in an environment such as a J2EE
>> application server, where the context classpath has been set
>> appropriately by the appserver in the current thread, the right
>> classloader ends up loading the data. If Spring didn't do this, in
>> some app server environments, a spring lib instance in the
>> appserver's own support directory would be used as the basis of the
>> classpath to search, and would never see the resources in the
>> classloader farther down in the hierarchy.
>>
>> So what I would suggest doing is something like this:
>>
>> Define a utility method somewhere:
>> /**
>> * Given an input class object, returns a string which consists of
>> the class's package
>> * name as a pathname, i.e., a leading '/' is added, and all dots
>> ('.') are replaced by
>> * slashes ('/')
>> * @param clazz the input class
>> * @return a path which represents the package name, including a
>> leading slash
>> */
>> public static String classPackageAsPath(Class clazz) {
>> StringBuffer retval = new StringBuffer("/");
>> if (clazz == null)
>> return retval.toString();
>> StringTokenizer st = new
>> StringTokenizer(clazz.getPackage().getName(), ".");
>> while (st.hasMoreTokens()) {
>> retval.append(st.nextToken());
>> if (st.hasMoreTokens())
>> retval.append("/");
>> }
>> System.out.println("returning: " + retval.toString());
>> return retval.toString();
>> }
>>
>> then when you need to load resources relative to a class's package,
>> do something like this:
>>
>> private static final String CONTEXT =
>> FileUtil.classPackageAsPath(BasicMappedPersistenceTest.class)
>> + "/BasicMappedPersistenceTestContext.xml";
>>
>> ....
>> appContext = new ClassPathXmlApplicationContext(CONTEXT);
>>
>>
>>
>> As to whether this belongs in the user list or the dev list, it's
>> somewhat of a grey area. That is, my explanation above definitely
>> belongs in the user list, but this discussion could certainly have
>> lead (or may lead) to further discussion about how to improve this
>> area of spring, which is best handled in the dev list.
>>
>>
>> Regards,
>> Colin
>>
>>
>> Keith Donald wrote:
>>
>>> Is it correct to always prepend a "/" to a resource path passed into
>>> ClassPathXmlApplicationContext? This behaivior forces me to hard-code
>>> fully-qualified references to my application context xml files.
>>> Instead,
>>> I'd like to be able to pass in a relative name and have
>>> getResourceAsStream() attempt to load the resource out of the
>>> package where
>>> the code is executing (which is the default behaivior of
>>> Class.getResourceAsStream().)
>>>
>>> For example, I have a context located in my classpath at:
>>> /com/csi/cogids/console/console-context.xml. To load it, I must
>>> pass that
>>> full path to ClassPathApplicationContext(). Now say two weeks later I
>>> re-factor and re-locate this code to another package--I have to make
>>> sure I
>>> update the reference. I'd rather just be able to say: new
>>> ClassPathApplicationContext("console-context.xml") and have it by
>>> default
>>> look in the current executing class's package directory.
>>>
>>> Should I mail stuff like this to the developer list?
>>>
>>> Thanks,
>>> Keith
>>
|