I want to access file on my classpath called reports/invoiceSweetChoice.jasper in jar on production server. Whatever I do I get null.
I have tried this.getClass().getResourceAsStream("reports/invoiceSweetChoice.jasper"), tried via InputStream etc. I have printed out content of System.getProperty("java.class.path") and it is empty. Not sure how is that possible. Do you have any suggestion how to resolve this ?
In manifest.mf, the classpath is defined using the class-path key and a space-delimited list of files, as follows:
MANIFEST.MF at root of jarfile.
Class-Path: hd1.jar path/to/label007.jar path/to/foo.jar
If there are spaces in the jar filename, you should enclose them in quotes.
If it's a webapp, the reports path should be in your BOOT-INF subdirectory of your classpath -- this is automatically performed by maven if you put it in src/main/resources in the standard layout.
EDIT:
Now that you've clarified what you're trying to do, you have 2 approaches. Like I said above, you can grab the file from the BOOT-INF subdirectory of your webapp or you can enumerate the entries in the jar until you find the one you want:
JarInputStream is = new JarInputStream(new FileInputStream("your/jar/file.jar"));
JarEntry obj = null
while ((obj = is.getNextJarEntry()) != null) {
JarEntry entry = (JarEntry)obj;
if (entry.getName().equals("file.abc")) {
ByteArrayOutputStream baos = new ByetArrayOutputStream();
IOUtils.copy(jarFile.getInputStream(entry), baos);
String contents = new String(baos.toByteArray(), "utf-8");
// your entry is now read into contents
}
}
#Autowired private ResourceLoader resLoad;
void someMethod() {
Resource r = resLoad.getResource("classpath:reports/file.abc");
r.getInputStream()...
...
Related
A lot has been discussed already here about getting a resource.
If there is already a solution - please point me to it because I couldn't find.
I have a program which uses several jars.
To one of the jars I added a properties file under main/resources folder.
I've added the following method to the jar project in order to to read it:
public void loadAppPropertiesFile() {
try {
Properties prop = new Properties();
ClassLoader loader = Thread.currentThread().getContextClassLoader();
String resourcePath = this.getClass().getClassLoader().getResource("").getPath();
InputStream stream = loader.getResourceAsStream(resourcePath + "\\entities.properties");
prop.load(stream);
String default_ssl = prop.getProperty("default_ssl");
}catch (Exception e){
}
}
The problem (?) is that resourcePath gives me a path to the target\test-clasess but under the calling application directory although the loading code exists in the jar!
This the jar content:
The jar is added to the main project by maven dependency.
How can I overcome this state and read the jar resource file?
Thanks!
I would suggest using the classloader used to load the class, not the context classloader.
Then, you have two options to get at a resource at the root of the jar file:
Use Class.getResourceAsStream, passing in an absolute path (leading /)
Use ClassLoader.getResourceAsStream, passing in a relative path (just "entities.properties")
So either of:
InputStream stream = getClass().getResourceAsStream("/entities.properties");
InputStream stream = getClass().getClassLoader().getResourceAsStream("entities.properties");
Personally I'd use the first option as it's briefer and just as clear.
Can you try this:
InputStream stream = getClass().getClassLoader().getResourceAsStream("entities.properties")
File Structure:
/web-project
|
|---/WEB-INF/a.jar
|
|---/META-INF/resources/b.properties
A.class which is located in a.jar wants to read /META-INF/resources/b.properties
I think that both a.jar and b.properties are under the same class loader (because they are in the same web context)
I've tried the following ways to try to achieve my purpose but not work.
InputStream is = null;
ClassLoader[] loaders = { Thread.currentThread().getContextClassLoader(),
ClassLoader.getSystemClassLoader(), getClass().getClassLoader() };
ClassLoader currentLoader = null;
for (int i = 0; i < loaders.length; i++) {
if (loaders[i] != null) {
currentLoader = loaders[i];
is = currentLoader.getResourceAsStream("/META-INF/resources/b.properties");
if (is != null) { // is is always null no matter what ways I used.
break;
}
}
}
I have no idea where I got mistakes.
Please guide me to the right path.
Thank you very much.
=====UPDATED=====
First of all , thanks for all people (especially #Ravi & #EJP) who comment, answer and discuss this question.
Below are what I've tried based on the discussion.
InputStream is = null;
URL url = getClass().getProtectionDomain().getCodeSource().getLocation();
is = A.class.getClassLoader().getResourceAsStream(url.getPath() + "../../../META-INF/resources/b.properites"); // is = null
is = new FileInputStream(url.getPath() + "../../../META-INF/resources/b.properites"); // is != null
It seems that I should use FileInputStream to get resources outside of the JAR instead of using getResourceAsStream()?
=====UPDATED 2=====
Eventually, I figured it out with the following solution.
context.getResourceAsStream("/META-INF/resources/b.properties");
based on the prerequisite below:
a.jar/b.properties are in the same context
A.class can obtain the ServletContext object
It seems that I should use FileInputStream to get resources outside of the JAR instead of using getResourceAsStream()?
Resources are in the JAR file, by definition. Anything outside it is not a resource but a file, and you should use FileInputStream or FileReader to read it. You can use
URL url = getClass().getProtectionDomain().getCodeSource().getLocation();
to get the location of the JAR file, so if you distribute the file in the same directory you just have to do a little path-mangling to get the path of the file from it.
You can solve this issue by first validating the path for your jar file. You can execute following line of code and check the path
getClass().getProtectionDomain().getCodeSource().getLocation();
Since, you resource file is located outside of your jar file, you need to change the path relative to your jar file.
Properties mainProperties = new Properties();
FileInputStream file = new FileInputStream("<relative-path>/META-INF/resources/b.properties");
mainProperties.load(file);
file.close();
I have tested above code with below folder structure
/web-project
|
|---/WEB-INF/a.jar
|
|---/test/resources/b.properties
All our jars contain a certain file version.properties which contains specific information from the build.
When we start a jar from command line (with several jars on the class path), we would like access the version.properties from the same jar. To be more precise: We would like to write Java code that gives us the content of the properties file in the jar where the calling class file resides.
The problem is that all jars on the class path contain version.properties and we do not want to read the first on the class path but the one from the correct jar. How can we achieve that?
Funny problem. You have to find the location of a representative class of the particular jar and use the result to build the URL for the properties file. I hacked together an example using String.class as example and access MANIFEST.MF in META-INF, since the rt.jar has no properties in it (at least a quick jar tf rt.jar | grep properties resulted in zero results)
Class clazz = String.class;
String name = clazz.getName().replace('.', '/') + ".class";
System.out.println(name);
String loc = clazz.getClassLoader().getResource(name).toString();
System.out.println(loc);
if (loc.startsWith("jar:file")) {
String propertyResource = loc.substring(0, loc.indexOf('!')) + "!" + "/META-INF/MANIFEST.MF";
InputStream is = new URL(propertyResource).openStream();
System.out.println(propertyResource);
Properties props = new Properties();
props.load(is);
System.out.println(props.get("Implementation-Title"));
}
I am trying to access a directory inside my jar file. I want to go through every of the files inside the directory itself. I tried using the following:
File[] files = new File("ressources").listFiles();
for (File file : files) {
XMLParser parser = new XMLParser(file.getAbsolutePath());
// some work
}
If I test this, it works well. But once I put the contents into the jar, it doesn't because of several reasons. If I use this code, the URL always points outside the jar.
structure of my project :
src
controllers
models
class that containt traitement
views
ressources
See this:
How do I list the files inside a JAR file?
Basically, you just use a ZipInputStream to find a list of files (a .jar is the same as a .zip)
Once you know the names of the files, you can use getClass().getResource(String path) to get the URL to the file.
I presume this jar is on your classpath.
You can list all the files in a directory using the ClassLoader.
First you can get a list of the file names then you can get URLs from the ClassLoader for individual files:
public static void main(String[] args) throws Exception {
final String base = "/path/to/folder/inside/jar";
final List<URL> urls = new LinkedList<>();
try (final Scanner s = new Scanner(MyClass.class.getResourceAsStream(base))) {
while (s.hasNext()) {
urls.add(MyClass.class.getResource(base + "/" + s.nextLine()));
}
}
System.out.println(urls);
}
You can do whatever you want with the URL - either read and InputStream into memory or copy the InputStream into a File on your hard disc.
Note that this definitely works with the URLClassLoader which is the default, if you are using an applet or a custom ClassLoader then this approach may not work.
NB:
You have a typo - its resources not ressources.
You should use reverse domain name notation for your project, this is the convention.
I need to get all the .class files located in a .jar file which in turn is located within another .ear file.
I am trying to use the JarInputStream to get access to the .ear. This is working ok. However, when I iterate the JarEntry elements inside the JarInputStream, I can't seem to be able to open it as a Jar file in order to read any .class elements within it.
JarInputStream jarFile = new JarInputStream(new FileInputStream("c:/path/to/my/.ear"));
JarEntry jarEntry = null;
while(true) {
jarEntry = jarFile.getNextJarEntry();
if(jarEntry == null) {
break;
}
if((jarEntry.getName().endsWith(".jar"))) {
//Access to the nested jar?
}
}
Edited: worth mentioning that the code above is in the same jar as the classes I am trying to find programmatically.
You should first extract the .jar file from the .ear file and then try to read the class file.
In fact, that's how even the Application Servers do. They extract the EAR file into a temporary directory and then load the classes from there.
Did you try this?
[...]
if((jarEntry.getName().endsWith(".jar"))) {
JarInputStream subJarStream = new JarInputStream(jarFile);
// the same search again
}