Retrieving resources for a subpackage class - java

I haven't been working with java for long, so I'm not sure as what else to look for. I hope somebody can point me in the right direction.
Goal:
I want to use a look up table, stored as a text file. But I don't want to use absolute paths, as in the end I'd like to pack a release and be able to call it from any location (the text file will be included int the packed release).
Current setup:
I put the text file in a folder called "resources" (because from reading tutorials about java, I got the impression, this is where I'm supposed to put it to maintain a better structured project).
In the root package folder I have a class (MainClass.java) that is calling another class (LookUpClass.java) in a subpackage.
The folder setup is as followed:
src
java
main.package.com
subpackage
LookUpClass.java
PlotterClass.java
MainClass.java
resources
LookUpTables
LookUpTable1.txt
LookUpTable2.txt
I wrote a method in LookUpClass.java that is retrieving a certain line from my lookup tables in resources. To retrieve the file and read out a certain line, I used
// Gets respective line from LUT
private static String getLineFromLUT(int line) {
URL url = LookUpClass.class.getClass().getResource("/LookUpTables/LookUpTable1.txt");
File file = new File(url.toURI());
BufferedReader br = new BufferedReader(new FileReader(file));
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine;
}
In my project structure the "java" folder is marked as "source", while "resources" is marked as, well, "resources".
My test setup is very simple:
public static void main(String[] args) throws URISyntaxException, IOException {
String c = LookUpClass.getLineFromLUT(5);
System.out.println("Color of line 5: " + c);
}
Output:
Color of line 5: 0 0 38
(Which is correct.)
I added the exact same lines to PlotterClass.java and it works fine, too.
Problem:
Now, If I try the same in MainClass.java I get an error with url being null. It seems the resource/resource folder can't be found.
I read through various postings on SO already and tried out several proposed solutions, which all failed so far:
If using LookUpClass.class.getClassLoader().getResource("/LookUpTables/LookUpTable1.txt") both callings from MainClass.java and LookUpClass.java fail (url is null).
I tried using following paths (all not working in either of the classes):
"LookUpTables/LookUpTable1.txt" (removing starting "/")
"/subpackage/LookUpTables/LookUpTable1.txt"
"../subpackage/LookUpTables/LookUpTable1.txt"
Since using Idea IntelliJ, I checked "Settings > Build, Execution, Deployment > Compiter > Resource patterns" and added "*.txt" to the patterns. Nothing changed.
If adding Class c = LookUpClass.class.getClass();, in Debug mode c is "class.java.lang.Class". I was expecting something like "main.package.com.subpackage.LookUpClass".
At some point I tried using getResourceAsStream(), but I didn't understand how to get my (e.g.) 5th line, so I discarded it. I'm willing to read up on this, if it solves my problem though.
I have no idea how to solve this problem. And I realize that at this point I'm just trying out things, not even understanding why it could or could not work.
For me, it just seems LookUpClass.java is run from a different location than MainClass.java. But the "resources"-folder and respective text file location never change. How can the file be found in one case, but not in the other?

Maven has a standard directory layout. The directory src/main/resources is intended for such application resources. Place your text files into it.
You now basically have two options where exactly to place your files:
The resource file belongs to a class.
An example for this is a class representing a GUI element (a panel) that needs to also show some images.
In this case place the resource file into the same directory (package) as the corresponding class. E.g. for a class named your.pkg.YourClass place the resource file into the directory your/pkg:
src/main
+-- java/
| +-- your/pkg/
| | +-- YourClass.java
+-- resources/
+-- your/pkg/
+-- resource-file.txt
You now load the resource via the corresponding class. Inside the class your.pkg.YourClass you have the following code snippet for loading:
String resource = "resource-file.txt"; // the "file name" without any package or directory
Class<?> clazz = this.getClass(); // or YourClass.class
URL resourceUrl = clazz.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Note: You can also load the resource via the class' class loader:
String resource = "your/pkg/resource-file.txt";
ClassLoader loader = this.getClass().getClassLoader(); // or YourClass.class.getClassLoader()
URL resourceUrl = loader.getResource(resource);
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
Choose, what you find more convenient.
The resource belongs to the application at whole.
In this case simply place the resource directly into the src/main/resources directory or into an appropriate sub directory. Let's look at an example with your lookup file:
src/main/resources/
+-- LookupTables/
+-- LookUpTable1.txt
You then must load the resource via a class loader, using either the current thread's context class loader or the application class loader (whatever is more appropriate - go and search for articles on this issue if interested). I will show you both ways:
String resource = "LookupTables/LookUpTable1.txt";
ClassLoader ctxLoader = Thread.currentThread().getContextClassLoader();
ClassLoader sysLoader = ClassLoader.getSystemClassLoader();
URL resourceUrl = ctxLoader.getResource(resource); // or sysLoader.getResource(resource)
if (resourceUrl != null) {
try (InputStream input = resourceUrl.openStream()) {
// load the resource here from the input stream
}
}
As a first suggestion, use the current thread's context class loader. In a standalone application this will be the system class loader or have the system class loader as a parent. (The distinction between these class loaders will become important for libraries that also load resources.)
You should always use a class loader for loading resource. This way you make loading independent from the place (just take care that the files are inside the class path when launching the application) and you can package the whole application into a JAR file which still finds the resources.

I tried to reproduce your problem given the MWE you provided, but did not succeed. I uploaded my project including a pom.xml (you mentioned you used maven) here: http://www.filedropper.com/stackoverflow
This is what my lookup class looks like (also showing how to use the getResourceAsStream method):
public class LookUpClass {
final static String tableName = "resources/LookUpTables/LookUpTable1.txt";
public static String getLineFromLUT(final int line) {
final URL url = LookUpClass.class.getResource(tableName);
if (url.toString().startsWith("jar:")) {
try (final URLClassLoader loader = URLClassLoader
.newInstance(new URL[] { url })) {
return getLineFromLUT(
new InputStreamReader(
loader.getResourceAsStream(tableName)), line);
} catch (final IOException e) {
e.printStackTrace();
}
} else {
return getLineFromLUT(
new InputStreamReader(
LookUpClass.class.getResourceAsStream(tableName)),
line);
}
return null;
}
public static String getLineFromLUT(final Reader reader, final int line) {
try (final BufferedReader br = new BufferedReader(reader)) {
for (int i = 0; i < line; ++i)
br.readLine();
return br.readLine();
} catch (final IOException e) {
e.printStackTrace();
}
return null;
}
}

Related

How to let plugin access file in resource folder of any project where it runs

I have created a plugin. It needs to access 2 files from res folder. Now the trick here is, res folder is not inside plugin. For example, i have published plugin locally, so it now visible under any project you create, inside Tools Menu. What i want is, any new project i create, it will have 2 files facility.json & groups.json inside res folder, now my plugin should be able to access these files. I have tried different approach like as shown below, but it always fails, saying "File not found" exception. If anyone can help me out in this. Its appreciated. Thank you.
private static File getFileFromResource(String fileName) throws URISyntaxException {
ClassLoader classLoader = Validator.class.getClassLoader();
URL resource = classLoader.getResource(fileName);
if (resource == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
// failed if files have whitespaces or special characters
//return new File(resource.getFile());
return new File(resource.toURI());
}
}
private static InputStream getFileFromResourceAsStream(String fileName) {
// The class loader that loaded the class
ClassLoader classLoader = Validator.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(fileName);
// the stream holding the file content
if (inputStream == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
return inputStream;
}
}
That's the neat part, you don't.
you have to add them by yourself each time you make a new project since res folder isn't a plugin, instead res is for resource (assuming you use res as resource)
Try this by manually add each facility.json & groups.json with
InputStream IS = getClass().getResourceAsStream("/res/file name");
or
InputStream IS = getClass().getResourceAsStream("root/dir/file name");
your plugin already published locally so maybe adding address might be help
if still not, try to save your clean project that only have facility.json & groups.json inside res folder as your project template. it depends on your IDE,
Intelij IDEA -Jetbrain : https://www.jetbrains.com/help/idea/saving-project-as-template.html
NetBeans IDE -Apache : https://netbeans.apache.org/tutorials/nbm-filetemplates.html
as my experience, im creating my own netbeans template for new project

How to set a txt-file so that it can be used internally in the .jar file? [duplicate]

I want to read an XML file that is located inside one of the jars included in my class path. How can I read any file which is included in the jar?
If you want to read that file from inside your application use:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
The path starts with "/", but that is not the path in your file-system, but in your classpath. So if your file is at the classpath "org.xml" and is called myxml.xml your path looks like "/org/xml/myxml.xml".
The InputStream reads the content of your file. You can wrap it into an Reader, if you want.
Ah, this is one of my favorite subjects. There are essentially two ways you can load a resource through the classpath:
Class.getResourceAsStream(resource)
and
ClassLoader.getResourceAsStream(resource)
(there are other ways which involve getting a URL for the resource in a similar fashion, then opening a connection to it, but these are the two direct ways).
The first method actually delegates to the second, after mangling the resource name. There are essentially two kinds of resource names: absolute (e.g. "/path/to/resource/resource") and relative (e.g. "resource"). Absolute paths start with "/".
Here's an example which should illustrate. Consider a class com.example.A. Consider two resources, one located at /com/example/nested, the other at /top, in the classpath. The following program shows nine possible ways to access the two resources:
package com.example;
public class A {
public static void main(String args[]) {
// Class.getResourceAsStream
Object resource = A.class.getResourceAsStream("nested");
System.out.println("1: A.class nested=" + resource);
resource = A.class.getResourceAsStream("/com/example/nested");
System.out.println("2: A.class /com/example/nested=" + resource);
resource = A.class.getResourceAsStream("top");
System.out.println("3: A.class top=" + resource);
resource = A.class.getResourceAsStream("/top");
System.out.println("4: A.class /top=" + resource);
// ClassLoader.getResourceAsStream
ClassLoader cl = A.class.getClassLoader();
resource = cl.getResourceAsStream("nested");
System.out.println("5: cl nested=" + resource);
resource = cl.getResourceAsStream("/com/example/nested");
System.out.println("6: cl /com/example/nested=" + resource);
resource = cl.getResourceAsStream("com/example/nested");
System.out.println("7: cl com/example/nested=" + resource);
resource = cl.getResourceAsStream("top");
System.out.println("8: cl top=" + resource);
resource = cl.getResourceAsStream("/top");
System.out.println("9: cl /top=" + resource);
}
}
The output from the program is:
1: A.class nested=java.io.BufferedInputStream#19821f
2: A.class /com/example/nested=java.io.BufferedInputStream#addbf1
3: A.class top=null
4: A.class /top=java.io.BufferedInputStream#42e816
5: cl nested=null
6: cl /com/example/nested=null
7: cl com/example/nested=java.io.BufferedInputStream#9304b1
8: cl top=java.io.BufferedInputStream#190d11
9: cl /top=null
Mostly things do what you'd expect. Case-3 fails because class relative resolving is with respect to the Class, so "top" means "/com/example/top", but "/top" means what it says.
Case-5 fails because classloader relative resolving is with respect to the classloader. But, unexpectedly Case-6 also fails: one might expect "/com/example/nested" to resolve properly. To access a nested resource through the classloader you need to use Case-7, i.e. the nested path is relative to the root of the classloader. Likewise Case-9 fails, but Case-8 passes.
Remember: for java.lang.Class, getResourceAsStream() does delegate to the classloader:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
so it is the behavior of resolveName() that is important.
Finally, since it is the behavior of the classloader that loaded the class that essentially controls getResourceAsStream(), and the classloader is often a custom loader, then the resource-loading rules may be even more complex. e.g. for Web-Applications, load from WEB-INF/classes or WEB-INF/lib in the context of the web application, but not from other web-applications which are isolated. Also, well-behaved classloaders delegate to parents, so that duplicateed resources in the classpath may not be accessible using this mechanism.
Check first your class loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Class.class.getClassLoader();
}
classLoader.getResourceAsStream("xmlFileNameInJarFile.xml");
// xml file location at xxx.jar
// + folder
// + folder
// xmlFileNameInJarFile.xml
A JAR is basically a ZIP file so treat it as such. Below contains an example on how to extract one file from a WAR file (also treat it as a ZIP file) and outputs the string contents. For binary you'll need to modify the extraction process, but there are plenty of examples out there for that.
public static void main(String args[]) {
String relativeFilePath = "style/someCSSFile.css";
String zipFilePath = "/someDirectory/someWarFile.war";
String contents = readZipFile(zipFilePath,relativeFilePath);
System.out.println(contents);
}
public static String readZipFile(String zipFilePath, String relativeFilePath) {
try {
ZipFile zipFile = new ZipFile(zipFilePath);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry) e.nextElement();
// if the entry is not directory and matches relative file then extract it
if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) {
BufferedInputStream bis = new BufferedInputStream(
zipFile.getInputStream(entry));
// Read the file
// With Apache Commons I/O
String fileContentsStr = IOUtils.toString(bis, "UTF-8");
// With Guava
//String fileContentsStr = new String(ByteStreams.toByteArray(bis),Charsets.UTF_8);
// close the input stream.
bis.close();
return fileContentsStr;
} else {
continue;
}
}
} catch (IOException e) {
logger.error("IOError :" + e);
e.printStackTrace();
}
return null;
}
In this example I'm using Apache Commons I/O and if you are using Maven here is the dependency:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
Just for completeness, there has recently been a question on the Jython mailinglist where one of the answers referred to this thread.
The question was how to call a Python script that is contained in a .jar file from within Jython, the suggested answer is as follows (with "InputStream" as explained in one of the answers above:
PythonInterpreter.execfile(InputStream)
This also works on spring
ClassPathResource resource = new ClassPathResource("/file.txt", MainApplication.class); //resources folder
InputStream inputStream = resource.getInputStream();
File file = new File("file.txt");
FileUtils.copyInputStreamToFile(inputStream, file);

How to visit all the jar files in a file tree using WalkFileTree [duplicate]

I want to read an XML file that is located inside one of the jars included in my class path. How can I read any file which is included in the jar?
If you want to read that file from inside your application use:
InputStream input = getClass().getResourceAsStream("/classpath/to/my/file");
The path starts with "/", but that is not the path in your file-system, but in your classpath. So if your file is at the classpath "org.xml" and is called myxml.xml your path looks like "/org/xml/myxml.xml".
The InputStream reads the content of your file. You can wrap it into an Reader, if you want.
Ah, this is one of my favorite subjects. There are essentially two ways you can load a resource through the classpath:
Class.getResourceAsStream(resource)
and
ClassLoader.getResourceAsStream(resource)
(there are other ways which involve getting a URL for the resource in a similar fashion, then opening a connection to it, but these are the two direct ways).
The first method actually delegates to the second, after mangling the resource name. There are essentially two kinds of resource names: absolute (e.g. "/path/to/resource/resource") and relative (e.g. "resource"). Absolute paths start with "/".
Here's an example which should illustrate. Consider a class com.example.A. Consider two resources, one located at /com/example/nested, the other at /top, in the classpath. The following program shows nine possible ways to access the two resources:
package com.example;
public class A {
public static void main(String args[]) {
// Class.getResourceAsStream
Object resource = A.class.getResourceAsStream("nested");
System.out.println("1: A.class nested=" + resource);
resource = A.class.getResourceAsStream("/com/example/nested");
System.out.println("2: A.class /com/example/nested=" + resource);
resource = A.class.getResourceAsStream("top");
System.out.println("3: A.class top=" + resource);
resource = A.class.getResourceAsStream("/top");
System.out.println("4: A.class /top=" + resource);
// ClassLoader.getResourceAsStream
ClassLoader cl = A.class.getClassLoader();
resource = cl.getResourceAsStream("nested");
System.out.println("5: cl nested=" + resource);
resource = cl.getResourceAsStream("/com/example/nested");
System.out.println("6: cl /com/example/nested=" + resource);
resource = cl.getResourceAsStream("com/example/nested");
System.out.println("7: cl com/example/nested=" + resource);
resource = cl.getResourceAsStream("top");
System.out.println("8: cl top=" + resource);
resource = cl.getResourceAsStream("/top");
System.out.println("9: cl /top=" + resource);
}
}
The output from the program is:
1: A.class nested=java.io.BufferedInputStream#19821f
2: A.class /com/example/nested=java.io.BufferedInputStream#addbf1
3: A.class top=null
4: A.class /top=java.io.BufferedInputStream#42e816
5: cl nested=null
6: cl /com/example/nested=null
7: cl com/example/nested=java.io.BufferedInputStream#9304b1
8: cl top=java.io.BufferedInputStream#190d11
9: cl /top=null
Mostly things do what you'd expect. Case-3 fails because class relative resolving is with respect to the Class, so "top" means "/com/example/top", but "/top" means what it says.
Case-5 fails because classloader relative resolving is with respect to the classloader. But, unexpectedly Case-6 also fails: one might expect "/com/example/nested" to resolve properly. To access a nested resource through the classloader you need to use Case-7, i.e. the nested path is relative to the root of the classloader. Likewise Case-9 fails, but Case-8 passes.
Remember: for java.lang.Class, getResourceAsStream() does delegate to the classloader:
public InputStream getResourceAsStream(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResourceAsStream(name);
}
return cl.getResourceAsStream(name);
}
so it is the behavior of resolveName() that is important.
Finally, since it is the behavior of the classloader that loaded the class that essentially controls getResourceAsStream(), and the classloader is often a custom loader, then the resource-loading rules may be even more complex. e.g. for Web-Applications, load from WEB-INF/classes or WEB-INF/lib in the context of the web application, but not from other web-applications which are isolated. Also, well-behaved classloaders delegate to parents, so that duplicateed resources in the classpath may not be accessible using this mechanism.
Check first your class loader.
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = Class.class.getClassLoader();
}
classLoader.getResourceAsStream("xmlFileNameInJarFile.xml");
// xml file location at xxx.jar
// + folder
// + folder
// xmlFileNameInJarFile.xml
A JAR is basically a ZIP file so treat it as such. Below contains an example on how to extract one file from a WAR file (also treat it as a ZIP file) and outputs the string contents. For binary you'll need to modify the extraction process, but there are plenty of examples out there for that.
public static void main(String args[]) {
String relativeFilePath = "style/someCSSFile.css";
String zipFilePath = "/someDirectory/someWarFile.war";
String contents = readZipFile(zipFilePath,relativeFilePath);
System.out.println(contents);
}
public static String readZipFile(String zipFilePath, String relativeFilePath) {
try {
ZipFile zipFile = new ZipFile(zipFilePath);
Enumeration<? extends ZipEntry> e = zipFile.entries();
while (e.hasMoreElements()) {
ZipEntry entry = (ZipEntry) e.nextElement();
// if the entry is not directory and matches relative file then extract it
if (!entry.isDirectory() && entry.getName().equals(relativeFilePath)) {
BufferedInputStream bis = new BufferedInputStream(
zipFile.getInputStream(entry));
// Read the file
// With Apache Commons I/O
String fileContentsStr = IOUtils.toString(bis, "UTF-8");
// With Guava
//String fileContentsStr = new String(ByteStreams.toByteArray(bis),Charsets.UTF_8);
// close the input stream.
bis.close();
return fileContentsStr;
} else {
continue;
}
}
} catch (IOException e) {
logger.error("IOError :" + e);
e.printStackTrace();
}
return null;
}
In this example I'm using Apache Commons I/O and if you are using Maven here is the dependency:
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
Just for completeness, there has recently been a question on the Jython mailinglist where one of the answers referred to this thread.
The question was how to call a Python script that is contained in a .jar file from within Jython, the suggested answer is as follows (with "InputStream" as explained in one of the answers above:
PythonInterpreter.execfile(InputStream)
This also works on spring
ClassPathResource resource = new ClassPathResource("/file.txt", MainApplication.class); //resources folder
InputStream inputStream = resource.getInputStream();
File file = new File("file.txt");
FileUtils.copyInputStreamToFile(inputStream, file);

Can't Access Resources In Executable Jar

Can someone please point out what I'm doing wrong here.
I have a small weather app that generates and sends an HTML email. With my code below, everything works fine when I run it from Eclipse. My email gets generated, it's able to access my image resources and it sends the email with the included attachment.
However, when I build the executable jar by running mvn install and run the jar using java -jar NameOfMyJar.jar I get java.io.FileNotFound Exceptions for my image resource.
I know that I have to be doing something wrong with how I'm accessing my image resources, I just don't understand why it works fine when it's not packaged, but bombs out whenever I package it into a jar.
Any advice is very much appreciated it.
My project layout
How I'm accessing my image resource
//Setup the ATTACHMENTS
MimeBodyPart attachmentsPart = new MimeBodyPart();
try {
attachmentsPart.attachFile("resources/Cloudy_Day.png");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
The StackTrace
Exception in thread "main" java.lang.RuntimeException: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:139)
at Utilities.SendEmailUsingGmailSMTP.SendWeatherEmail(SendEmailUsingGmailSMTP.java:66)
at Weather.Main.start(Main.java:43)
at Weather.Main.main(Main.java:23)
Caused by: javax.mail.MessagingException: IOException while sending message;
nested exception is:
java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1167)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at Utilities.SendEmailUsingGmailSMTP.SendTheEmail(SendEmailUsingGmailSMTP.java:134)
... 3 more
Caused by: java.io.FileNotFoundException: resources/Cloudy_Day.png (No such file or directory)
at java.io.FileInputStream.open(Native Method)
at java.io.FileInputStream.<init>(FileInputStream.java:146)
at javax.activation.FileDataSource.getInputStream(FileDataSource.java:97)
at javax.activation.DataHandler.writeTo(DataHandler.java:305)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:865)
at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:462)
at com.sun.mail.handlers.multipart_mixed.writeTo(multipart_mixed.java:103)
at javax.activation.ObjectDataContentHandler.writeTo(DataHandler.java:889)
at javax.activation.DataHandler.writeTo(DataHandler.java:317)
at javax.mail.internet.MimeBodyPart.writeTo(MimeBodyPart.java:1485)
at javax.mail.internet.MimeMessage.writeTo(MimeMessage.java:1773)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1119)
... 6 more
Others are correct with the use of getResourceAsStream, but the path is a little tricky. You see the little package icon in the resources folder? That signifies that all the files in the resource folder will be put into the root of the classpath. Just like all the packages in src/main/java are put in the root. So you would take out the resources from the path
InputStream is = getClass().getResourceAsStream("/Cloudy_Day.png");
An aside: Maven has a file structure conventions. Class path resources are usually put into src/main/resources. If you create a resources dir in the src/main, Eclipse should automatically pick it up, and create the little package icon for a path src/main/resource that you should see in the project explorer. These files would also go to the root and could be accessed the same way. I would fix the file structure to follow this convention.
Note: A MimeBodyPart, can be Constructed from an InputStream (As suggested by Bill Shannon, this is incorrect). As mentioned in his comment below
"You can also attach the data using"
mbp.setDataHandler(new DataHandler(new ByteArrayDataSource(
this.getClass().getResourceAsStream("/Cloudy_Day.png", "image/png"))));
You can't access resources inside a JAR file as a File, only read them as an InputStream: getResourceAsStream().
As the MimeBodyPart has no attach() method for an InputStream, the easiest way should be to read your resources and write them to temp files, then attach these files.
Try this
new MimeBodyPart().attachFile(new File(this.getClass().getClassLoader().getResource("resources/Cloudy_Day.png").toURI());
I don't know if this will help anyone or not. But, I have a similar case as the OP and I solved the case by finding the file in the classpath using recursive function. The idea is so that when another developer decided to move the resources into another folder/path. It will still be found as long as the name is still the same.
For example, in my work we usually put our resources outside the jar, and then we add said resources path into our classpath, so here the classpath of the resources will be different depending on where it is located.
That's where my code comes to work, no matter where the file is put, as long as it's in the classpath it will be found.
Here is an example of my code in action:
import java.io.File;
public class FindResourcesRecursive {
public File findConfigFile(String paths, String configFilename) {
for (String p : paths.split(File.pathSeparator)) {
File result = findConfigFile(new File(p), configFilename);
if (result != null) {
return result;
}
}
return null;
}
private File findConfigFile(File path, String configFilename) {
if (path.isDirectory()) {
String[] subPaths = path.list();
if (subPaths == null) {
return null;
}
for (String sp : subPaths) {
File subPath = new File(path.getAbsoluteFile() + "/" + sp);
File result = findConfigFile(subPath, configFilename);
if (result != null && result.getName().equalsIgnoreCase(configFilename)) {
return result;
}
}
return null;
} else {
File file = path;
if (file.getName().equalsIgnoreCase(configFilename)) {
return file;
}
return null;
}
}
}
Here I have a test case that is coupled with a file "test.txt" in my test/resources folder. The content of said file is:
A sample file
Now, here is my test case:
import org.junit.Test;
import java.io.*;
import static org.junit.Assert.fail;
public class FindResourcesRecursiveTest {
#Test
public void testFindFile() {
// Here in the test resources I have a file "test.txt"
// Inside it is a string "A sample file"
// My Unit Test will use the class FindResourcesRecursive to find the file and print out the results.
File testFile = new FindResourcesRecursive().findConfigFile(
System.getProperty("java.class.path"),
"test.txt"
);
try (FileInputStream is = new FileInputStream(testFile)) {
int i;
while ((i = is.read()) != -1) {
System.out.print((char) i);
}
System.out.println();
} catch (IOException e) {
fail();
}
}
}
Now, if you run this test, it will print out "A sample file" and the test will be green.

How to reference files in a Java Pacakage

I have MyClassin package X, Also in package X there are packages Y and Z like this:
X - MyClass
X - Y - Some Files
X - Z - Some Files
How do I get a list of all the files in packages Y and Z from MyClass?
Java packages mirror directory structure. You can use the File class. In particular, see the listFiles() method.
EDIT
You can dynamically find your executing location. Here is code from a project I've recently worked on; I wanted to be able to find the directory I'm running the JAR from (if I'm running the JAR), or else the directory of the JAR if I'm running from the class files. In my case, my JAR is in <project root>/bin and my classes are in <project root>/classes.
final URL location;
final String classLocation = JavaPlanner.class.getName().replace('.', '/') + ".class";
final ClassLoader loader = JavaPlanner.class.getClassLoader();
if(loader == null)
{
try { throw new ClassNotFoundException("class loaded with bootstrap loader"); }
catch (ClassNotFoundException cnfe) { throw new InitializationException(cnfe); }
}
else
{
location = loader.getResource(classLocation);
}
if(location.toString().startsWith("file:/")) // Line 14
{
// Running from .class file
String path;
try { path = URLDecoder.decode(location.toString().substring(6), "UTF-8"); }
catch(UnsupportedEncodingException uee) { throw new InitializationException(uee); }
// Move up package folders to root, add /bin/
File package_ = new File(path).getParentFile();
binPath = package_.getParentFile().getParentFile().getParentFile().getParentFile() + File.separator + "bin" + File.separator;
}
else // Line 25
{
// Running from .jar file
String jarURL = JavaPlanner.class.getResource("/" + JavaPlanner.class.getName().replaceAll("\\.", "/") + ".class").toString();
jarURL = jarURL.substring(4).replaceFirst("/[^/]+\\.jar!.*$", "/");
try
{
File dir = new File(new URL(jarURL).toURI());
jarURL = dir.getAbsolutePath();
}
catch(MalformedURLException mue) { throw new InitializationException(mue); }
catch(URISyntaxException use) { throw new InitializationException(use); }
binPath = jarURL;
}
At line 14, I've found that I'm running the application from a class file. String path initially is set to the file path of JavaPlanner (the class containing my main method). I know the package structure JavaPlanner is in, so I use getParentFile an appropriate number of times to find the project root, and then append bin/.
At line 25, I've found that I'm running the application from a JAR. The block simply gets the path to the folder containing that executable JAR.
Obviously, this code is not 100% adapted to your purpose (most specifically, I'm calling getParentFile a specific number of times for my package structure), but I think it should help.
The entire purpose of the above code was to be able to find the correct resource files for my application. In the production version, only the JAR would be available to the user, but I didn't want to have to rebuild the JAR every time I needed to test some code, and I didn't want to duplicate my resource files, and I didn't want to pollute my bin/ folder with the class files (because everything in bin/ was meant to be sent to the user).
It depends on the source of the class. If they are from a JAR file, then you can use the JarFile class to get a list of entries.
If you're only looking for classes in the package, consider
Package.getPackage(String name)
Package.getPackages()
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Package.html#getPackage%28java.lang.String%29
http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/java/lang/Package.html#getPackages%28%29

Categories

Resources