One of the final solutions to the Java Path Problem

Source: Internet
Author: User
Tags getstream
From http://xieyunc.blog.163.com/blog/static/1363060120070245548680/

 

Preface

The Java path is very difficult to solve. My recent work involves creating and reading files. Here I will give you a thorough solution to the Java path problem.

I have compiled a method that is more powerful than the classloader. getresource (string relative path) method. It can accept parameters such as "../", allowing us to use relative paths to locate resources outside classpath. In this way, we can use the path relative to classpath to locate resources in all locations!

Java path

The paths used in Java are divided into absolute paths and relative paths. Specifically, there are four types:

1. Absolute resource path in Uri form

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/AAA. B

URL is a special case of Uri. The URL prefix/protocol must be known by Java. The URL can open resources, but the URI cannot.

The URL and Uri objects can be converted to each other. Use the respective touri () and tourl () methods!

2. absolute path of the Local System

D:/Java/eclipse32/workspace/jbpmtest3/bin/AAA. B

This parameter is required for classes in the Java. Io package.

However, they generally provide URI-type parameters, while URI-type parameters accept URI-style strings. Therefore, the absolute path of the URI style can be used in the class in the Java. Io package through URI conversion.

3. Relative Path to classpath

For example

File:/D:/Java/eclipse32/workspace/jbpmtest3/bin/relative path of this path. Bin is the classpath of the project. All the. class files compiled from the Java source file are copied to this directory.

4. Relative Path to the current user directory

Is relative to the path returned by system. getproperty ("user. dir.

For general projects, this is the root path of the project. For a javaee server, this may be a path of the server. There is no unified specification!

Therefore, do not use the relative path relative to the current user directory ". However:

By default, classes in the Java. Io package always analyze relative path names based on the current user directory. This directory is specified by the system property user. dir, which is usually the call Directory of the Java Virtual Machine.

This means that when using classes in the Java. Io package, it is best not to use relative paths. OtherwiseProgramMay still be normal, but in the J2EE program, there will be problems! The path is different on different servers!

Relative Path Best Practices

We recommend that you use the relative path relative to the current classpath.

Therefore, when using relative paths, we should use relative paths relative to the current classpath.

The getresource (string name) and getresourceasstream (string name) Methods of the classloader class use the relative path relative to the classpath of the current project to find resources.

This is also true for getbundle (string path) of the resourcebundle class that is commonly used to read attribute files.

ViewSource code, I found that it actually uses an absolute path in Uri format. Obtain the absolute path in the URI form of the current classpath, and construct the absolute path in the URI form of the relative path. (This is actually a conjecture, because the JDK calls the sun source internally.CodeAnd the Code does not belong to JDK, not open source .)
The relative path is essentially an absolute path.

Therefore, in essence, Java can only use absolute paths to find resources. All relative paths are just some convenient methods to find resources. However, the API helps us build an absolute path at the underlying level to find resources!

Obtain the absolute path of classpath and the current class.

The following are some methods to obtain the absolute path of classpath and the current class. You may need to use some of these methods to obtain the absolute path of the resources you need.

1. filetest. Class. getresource ("")

The URI Directory of the current filetest. Class file is obtained. Not yourself!

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/COM/test/

2. filetest. Class. getresource ("/")

Obtain the absolute URI path of the current classpath.

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/

3. thread. currentthread (). getcontextclassloader (). getresource ("")

The obtained absolute URI path of the current classpath.

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/

4. filetest. Class. getclassloader (). getresource ("")

The obtained absolute URI path of the current classpath.

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/

5. classloader. getsystemresource ("")

The obtained absolute URI path of the current classpath.

For example, file:/D:/Java/eclipse32/workspace/jbpmtest3/bin/

We recommend that you use thread. currentthread (). getcontextclassloader (). getresource ("") to obtain the URI representation of the absolute path of the current classpath.

Addressing resources in Web Applications

As mentioned above, the current user directory is relative to the path returned by system. getproperty ("user. dir.

For the javaee server, this may be a path of the server. There is no uniform specification!

Instead of the root directory of the Web application we released!

In this way, in Web applications, we absolutely cannot use relative paths relative to the current user directory.

In Web applications, we generally use the servletcontext. getrealpath ("/") method to obtain the absolute path of the root directory of the Web application.

In this way, we only need to provide the path relative to the root directory of the Web application program to build an absolute path to locate the resource.

This is a general strategy we adopt when developing web applications.

Web applications can be published and run as Web applications. However, we often use javase to run the main method of a class of a Web application. Alternatively, use JUnit for testing. This requires the javase method.

In this way, we cannot use the servletcontext. getrealpath ("/") method to obtain the absolute path of the root directory of the Web application.

The classloader class provided by JDK, its getresource (string name), getresourceasstream (string name) and other methods, uses the relative path relative to the classpath of the current project to find resources.

This is also true for getbundle (string path) of the resourcebundle class that is commonly used to read attribute files.

They can only use relative paths to read resources under classpath and cannot locate resources outside classpath.

Reading configuration files outside classpath

For example, if we use the test-driven development method to develop Web applications using configuration files such as spring, hibernate, and ibatis, we will encounter problems.

Although Spring provides filesystem (which is relative to the user, Dir directory) to read the Web configuration file, it is not very convenient after all. It is inconsistent with the code usage in web programs!

As for hibernate, ibatis is more troublesome! You only need to move the configuration file to classpath. Otherwise, it is impossible to use the test driver for development!

What should I do?

General Relative Path Solution

To solve this problem, I decided to write a helper class classloaderutil to provide a convenient method [public static URL getextendresource (string relativepath)]. In all Java programs such as Web applications, when you need to locate resources outside classpath, use the convenient method of this helper class instead of using the servletcontext that is unique to Web applications. getrealpath ("/") method to locate the resource.

Use the absolute path of classpath to locate all resources

The implementation principle of this convenient method is to "use the absolute path of classpath to locate all resources ".

The getresource ("") method of the classloader class can obtain the absolute path of the current classpath. This is the capability of all Java programs and has the greatest adaptability!
Currently, the getresource (string relative path) method of the classloader class provided by JDK can only accept general relative paths. In this way, you can only locate resources under classpath by using the getresource (string relative path) method of the classloader class.

If it can accept parameters such as "../" and allow us to use relative paths to locate resources outside the classpath, then we can locate the resources in the location!

Of course, I cannot modify this method of the classloader class, so I wrote a helper class classloaderutil class that provides the [public static URL getextendresource (string relativepath)] method. It can accept the relative path with the "../" symbol, realizing the function of freely searching for resources.

Source code of the helper class that allows you to freely find resources through the classpath path:

Import java. Io. ioexception;
Import java. Io. inputstream;
Import java.net. malformedurlexception;
Import java.net. url;
Import java. util. properties;

Import org. Apache. commons. Logging. log;
Import org. Apache. commons. Logging. logfactory;

/**
* @ Author Shen Dongliang shendl_s@hotmail.com
* Nov29, 2006 10:34:34 AM
* Used to load class, resource files and attribute files under classpath.
* The getextendresource (stringrelativepath) method can use the ../symbol to load resources outside the classpath.
*/
Publicclass classloaderutil {
Privatestatic log = logfactory. getlog (classloaderutil. Class );
/**
* Thread. currentthread (). getcontextclassloader (). getresource ("")
*/

/**
* Load the Java class. Use fully qualified class names
* @ Paramclassname
* @ Return
*/
Publicstatic class loadclass (string classname ){
Try {
Return getclassloader (). loadclass (classname );
} Catch (classnotfoundexception e ){
Thrownew runtimeexception ("class not found '" + classname + "'", e );
}
}
/**
* Get the class loader.
* @ Return
*/
Publicstatic classloader getclassloader (){
Return classloaderutil. Class. getclassloader ();
}
/**
* Provides the resource path relative to classpath to return the input stream of the file
* @ Paramrelativepath the relative path of the resource must be passed. Is the path relative to classpath. If you need to find external resources of classpath, you need to use ../to find
* @ Return file input stream
* @ Throwsioexception
* @ Throwsmalformedurlexception
*/
Publicstatic inputstream getstream (string relativepath) throws malformedurlexception, ioexception {
If (! Relativepath. Contains ("../")){
Return getclassloader (). getresourceasstream (relativepath );
} Else {
Return classloaderutil. getstreambyextendresource (relativepath );
}
}
/**
*
* @ Paramurl
* @ Return
* @ Throwsioexception
*/
Publicstatic inputstream getstream (URL) throws ioexception {
If (URL! = NULL ){
Return URL. openstream ();
} Else {
Returnnull;
}
}
/**
*
* @ Paramrelativepath the relative path of the resource must be passed. Is the path relative to classpath. If you need to find external resources of classpath, you need to use ../to find
* @ Return
* @ Throwsmalformedurlexception
* @ Throwsioexception
*/
Publicstatic inputstream getstreambyextendresource (string relativepath) throws malformedurlexception, ioexception {
Return classloaderutil. getstream (classloaderutil. getextendresource (relativepath ));
}

/**
* Provides the resource path relative to classpath and returns the property object, which is a hash
* @ Paramresource
* @ Return
*/
Publicstatic properties getproperties (string resource ){
Properties Properties = new properties ();
Try {
Properties. Load (getstream (Resource ));
} Catch (ioexception e ){
Thrownew runtimeexception ("couldn't load properties file" + resource + "'", e );
}
Return properties;
}
/**
* Obtain the absolute classpat path of the classloader of this class.
* URL-based
* @ Return
*/
Publicstatic string getabsolutepathofclassloaderclasspath (){
Classloaderutil.log.info (classloaderutil. getclassloader (). getresource (""). tostring ());
Return classloaderutil. getclassloader (). getresource (""). tostring ();
}
/**
*
* @ Paramrelativepath the relative path of the resource must be passed. Is the path relative to classpath. If you need to find external resources of classpath, you need to use ../to find
* @ Return indicates the absolute URL of the resource.
* @ Throwsmalformedurlexception
*/
Publicstatic URL getextendresource (string relativepath) throws malformedurlexception {
Classloaderutil.log.info ("Input relative path:" + relativepath );
// Classloaderutil.log.info (integer. valueof (relativepath. indexof ("../")));
If (! Relativepath. Contains ("../")){
Return classloaderutil. getresource (relativepath );
}
String classpathabsolutepath = classloaderutil. getabsolutepathofclassloaderclasspath ();
If (relativepath. substring (0, 1). Equals ("/")){
Relativepath = relativepath. substring (1 );
}
Classloaderutil.log.info (integer. valueof (relativepath. lastindexof ("../")));
String wildcardstring = relativepath. substring (0, relativepath. lastindexof ("../") + 3 );
Relativepath = relativepath. substring (relativepath. lastindexof ("../") + 3 );
Int containsum = classloaderutil. containsum (wildcardstring ,"../");
Classpathabsolutepath = classloaderutil. cutlaststring (classpathabsolutepath, "/", containsum );
String resourceabsolutepath = classpathabsolutepath + relativepath;
Classloaderutil.log.info ("absolute path:" + resourceabsolutepath );
URL resourceabsoluteurl = new URL (resourceabsolutepath );
Return resourceabsoluteurl;
}
/**
*
* @ Paramsource
* @ Paramdest
* @ Return
*/
Privatestaticint containsum (string source, string DEST ){
Int containsum = 0;
Int destlength = DeST. Length ();
While (source. Contains (DEST )){
Containsum = containsum + 1;
Source = source. substring (destlength );
}
Return containsum;
}
/**
*
* @ Paramsource
* @ Paramdest
* @ Paramnum
* @ Return
*/
Privatestatic string cutlaststring (string source, string DEST, int num ){
// String cutsource = NULL;
For (INT I = 0; I <num; I ++ ){
Source = source. substring (0, source. lastindexof (DEST, source. Length ()-2) + 1 );
}
Return source;
}
/**
*
* @ Paramresource
* @ Return
*/
Publicstatic URL getresource (string resource ){
Classloaderutil.log.info ("the path to pass in to classpath:" + Resource );
Return classloaderutil. getclassloader (). getresource (Resource );
}
/**
* @ Paramargs
* @ Throwsmalformedurlexception
*/
Publicstaticvoid main (string [] ARGs) throws malformedurlexception {
// Classloaderutil. getextendresource ("../spring/Dao. xml ");
// Classloaderutil. getextendresource ("http://www.cnblogs.com/../src/log4j.properties ");
Classloaderutil. getextendresource ("log4j. properties ");
System. Out. println (classloaderutil. getclassloader (). getresource ("log4j. properties"). tostring ());
}
}

Postscript

Although the public static URL getextendresource (string relativepath) of the classloaderutil class is simple, it can solve the big problem.

However, this method is simple. I also want to further enhance its capabilities in the future. For example, add an ant-style match character. Use ** to represent multiple directories, and * to represent multiple characters ,? Represents a character. To achieve the same capabilities as spring, return the URLs of multiple resources at a time to facilitate development.

Summary:

1. Try not to use the relative path relative to the current user directory of system. getproperty ("user. dir. This is a time bomb, and you may be killed at any time.

2. Try to use absolute path resources in Uri format. It can easily be converted to Uri, URL, and file objects.

3. Try to use the relative path of the classpath. Do not use absolute paths. You can use the public static URL getextendresource (string relativepath) method of the classloaderutil class above to locate resources in all locations using the relative path relative to classpath.

4. Do not use hard-coded absolute paths. Because we can use the getresource ("") method of the classloader class to obtain the absolute path of the current classpath.
Using a hard-coded absolute path is completely unnecessary! It will make your death ugly! The program cannot be transplanted!

If you must specify an absolute path, it is much better to use the configuration file than hard encoding!

Of course, I recommend that you use the program to obtain the absolute path of classpath to spell the absolute path of resources!

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.