I am using an XML document as a template for multiple, similar documents (monthly reports which are organized identically). I was struggling to find the most generic path to the file. I came up with:
File f1 = new File("src/Statements/TemplateStatement.xml");
where /Statements/ is a folder under the src tab in Eclipse as if it were just another package.
Then:
File TemplateStatement = new File(f1.getAbsolutePath());
if (TemplateStatement.exists()) {
// ...do some stuff
} else {
JOptionPane.showMessageDialog(null, null,
"ERROR: Transaction template not found.", JOptionPane.OK_CANCEL_OPTION);
System.exit(0);
}
When running from Eclipse, it works great and my stuff gets done. When running as a .jar on my desktop (same machine and file system), I hit the else clause every time. I suspect I am missing a very basic yet important property of how jars package up the workspace and run it (as in there is no src directory associated with it anymore?).
I have had no luck finding examples or explanations on how to find the path, access, read, write, copy, etc. files from jarred applications. I really want to avoid hard-coding a full path as it may be the case the code will run on various machines. Any suggestions or pointers would be appreciated.
I've just encounted a similar problem, and it was caused by the java.io.FileReader function which uses platform default encoding.
As for my situation, in Runnable .jar running, java.io.FileReader uses ISO-8859-1 encoding, while in Eclipse it uses UTF-8 encoding. Replacing
new FileReader(filepath)
with
new InputStreamReader(new FileInputStream(filepath), "UTF-8")
solves my problem.
Related
Edit: I solved my problem. (See below.)
The problem
I'm new to NetBeans, and I'm having a problem that involves loading a resource to my servlet application, which runs via NetBeans using Tomcat as the server. Everything is fine until I try to build my response using the Mustache template library (in Java). At that point, an exception is thrown:
com.github.mustachejava.MustacheException: File not under root: /opt/catalina/bin
This exception is thrown right at the point in my code where I try to compile the template file. I feed the path to the resource (the template file) to the compile method of the MustacheFactory. My code looks like this:
MustacheFactory mf = new DefaultMustacheFactory();
Mustache mustache = mf.compile(getFormTemplatePath());
My research
I took a look at the Mustache code, and as best as I can tell, here is what's happening. Mustache does a security check when it loads the resource, trying to ensure that the resource is under the application's root in the file system. Because NetBeans is working some kind of magic to run the code on the Tomcat server, while the project's code is actually somewhere else on the file system, Mustache thinks something fishy is going on.
In other words, it can find the file; it just doesn't like where it's finding it. It seems like Mustache takes /opt/catalina/bin as the application's root, while the template file is actually at a path more like: ~/NetBeansProjects/MyProject/WEB-INF/template_file.mst.
The Mustache code looks like this (just so you can check my reasoning):
try {
// Check to make sure that the file is under the file root or current directory.
// Without this check you might accidentally open a security whole when exposing
// mustache templates to end users.
File checkRoot = fileRoot == null ? new File("").getCanonicalFile() : fileRoot.getCanonicalFile();
File parent = file.getCanonicalFile();
while ((parent = parent.getParentFile()) != null) {
if (parent.equals(checkRoot)) break;
}
if (parent == null) {
throw new MustacheException("File not under root: " + checkRoot.getAbsolutePath());
}
// [Try-catch block continues...]
I found the Mustache code online at the following URL:
https://github.com/spullara/mustache.java/blob/00bd13145f30156cd39aaad7ab046b46b1315275/compiler/src/main/java/com/github/mustachejava/resolver/FileSystemResolver.java#L50
My hypothesized solution
I'm guessing there must be some way to configure the application in NetBeans, when I'm choosing and configuring the server, to reconcile this issue. What I have tried is googling variations of Mustache NetBeans servlet "File not under root" exception and so forth, and nothing much comes up. I'm guessing that I don't even know enough about NetBeans to know what key words I should be searching with. It's even possible that I've found the solution, but don't recognize it when I see it.
Does anybody know what I might try? Thanks.
you can use the other overload API instead
Mustache compile(Reader reader, String name);
just like this and you can prefer to put the mustache template file anywhere
File f = new File(templateFilePath);
Mustache mustache = mf.compile(new InputStreamReader(new FileInputStream(f),Charset.forName("UTF-8")),f.getName());
Where to put the template file?
I solved this on my own, though I solved it by doing something better with the template file. Originally, I was putting the template file in the WEB-INF directory and then building the path to the file using the servlet context. That doesn't seem like best practice.
Taking another look at the Mustache source code I realized that Mustache first tries to use the classloader to get the file. If you let Mustache do it in its preferred way, you don't need to give the full path, only the file's name. But the classloader only looks in certain places, the WEB-INF/lib directory being one. A number of people on the Web recommend putting the Mustache template in the WEB-INF/lib directory.
Since mine is a Maven project, I moved my template file to the src/main/resources directory. (In NetBeans, this is "Other Sources" in the Projects pane.) At build, Maven takes anything in there and dumps it into the WEB-INF/lib. I then only had to change my source code to use the file name, instead of the real path to the file (as I had been doing). Everything works.
So, as far as I'm concerned, my problem stemmed from putting the template file in what turns out to be an awkward location for Mustache. If anyone has a better idea, or anything else to add, I'm all ears.
This code works fine when I run it from Eclipse, but not from an executable jar:
String str = "";
ImageIcon icon = null;
InputStream is = getClass().getResourceAsStream("/images/splash.jpg");
if (is != null) {
icon= new ImageIcon(ImageIO.read(is));
} else {
str = "stream is null";
}
JOptionPane.showMessageDialog(null,str,"A title",JOptionPane.PLAIN_MESSAGE,icon);
The dialog is displayed but no stream is returned from getResourceAsStream, irrespective of how I write the path. Inspection of the jar shows that splash.jpg is located in the images-folder, as it should be. The jar is created using Eclipse's export of "Runnable jar" with "Package required libraries into JAR" selected.
I know this question has been asked before, and I have read many (most?) of the answers and tried many different alternative solutions. But nothing seems to work. Any help would be much appreciated. (I'm using java 8 and Eclipse Mars on OSX Maverick.)
EDIT: Sorry for not listing the alternatives I have tried. It's just that I haven't kept notes and I cannot remember all. As far as path goes I have tried all combinations of "/" and "images" (and "resources"). I have also tried getting a URL via getResource(), both from class and class loader. No matter what I do I get null (no exception thrown in example above).
Here's what the structure looks like in Eclipse: http://i.stack.imgur.com/bIiEi.png
And here's what it looks like in the jar: http://i.stack.imgur.com/JAnmr.png
In your screenshots, the file is named "splash.JPG", and you're asking for "splash.jpg", which is a difference in case. The Mac filesystem is case-insensitive. The JAR entry reading code may not be. Try changing your string in the getResource call to have the same case as the file name or vice versa.
I'm just getting into using "Java Resource Files" and i have a few questions...
I am hoping to distribute my program to others and I'm assuming JAR file isn't the best way. I'd probably go about it by "converting to exe" is this good practice? what are the limitations?
If I convert to an exe does it keep the resource files?
I'm actually just trying to use a resource file. This file is a text file and will just save the users directories for certain files so they don't need set them up every time they open the program. is this even the best way to go about it?
how do you reference the resource file in the code itself?
Here is what I've done.
created a new resource file and since I'm using Netbeans I can see its location under the files tab in the navigator it looks like this:
Mainproject
build
classes
myclass
resources
directories.txt
here is how i'm trying to access it but when i debug it is coming back null.
private void getPaths()//todo
{
try
{
InputStream is = getClass().getResourceAsStream("/resources/directories.txt");
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
br.close();
isr.close();
is.close();
}
catch(Exception e)
{
}
}
"Converting to EXE" is just a fancy way of saying "wrapping the Jar files into an executable container"
"I'm assuming JAR file isn't the best way" not really. It's nice to provide a OS specific means for launching the program at times, but it's not always the best solution.
"what are the limitations?". Well, to start with, you're limiting your self to a single platform. For Mac's you need to bundle the application into a "app" bundle. For linux, I think most people provide scripts to launch their code.
You could also be limiting your self to particular bit depth. If all you supply is a x32 bit executable, then you'll only ever run within a x32 bit environment. This may not be an issue, but you're limiting the available memory to start with...
So yes, generally, your resource files will be safe.
A resource file is generally embedded. What you're describing in part 3 is more akin to a configuration file. This file needs to be stored on the file system (out side of your exe/jar) so it can easily be updated.
"how do you reference the resource file in the code itself?"
For embedded resources you will need to start by using getClass().getResource(...). For you configuration file, I'd say just like any other file...
I would also have a look at Deployment some ideas on the suggest mechanisms for deploying Java programs,
Jar is a perfect format for distribution. You can convert to exe , but the user will still need the JVM installed to run it. Jars are executed with a doubleclick if the JVM is installed AND the jar has a properly formed manifest file.
You can open any file from the JVM, text, binary, XML, property file etc.
To save user settings a good choice is a property file - see http://www.mkyong.com/java/java-properties-file-examples/
First of all, I am aware of Stack Overflow (and any competent forum-like website) policy of "search first, ask last", and, doing my homework, I searched various sources to find a solution to my issue. That said, I, failing to find any suitable answers, was left no choice but to ask this problem personally.
I have somewhat moderate programming skills, especially regarding the Java language. I am working on this 2D game with the default Java SE JDK. More specifically JDK 7u4. In this project, we have a class that manages most I/O operations. One of its methods returns the path to a file:
public static URL load(String resource) {
return ZM.class.getResource(resource);
}
Now, this method works fine when running the project on Netbeans (version 7.1). However, when building and cleaning the project, the resulting .jar file does not seem to agree with its creator. When running the .jar on command line, the JVM caught a NullPointerException. It seemed that the file was not being able to be read inside the .jar. Following my programmers instinct, I started debugging the project. My first attempt was to check whether the load method was the faulty member. I ran some tests and obtained a couple of interesting results:
When running the application on Netbeans and with "ZM.class" as the methods argument, it returned:
/D:/Projects/GeometryZombiesMayhem/build/classes/geometryzombiesmayhem/ZM.class
But when running it from the .jar file, it returned:
file:/D:/Projects/GeometryZombiesMayhem/dist/GeometryZombiesMayhem.jar!/geometryzombiesmayhem/ZM.class
Naturally, I tried removing the initial file: string from it. No effect. Then I tried taking the exclamation mark from [...].jar![...]. Again, nothing. I tried removing all the possible permutations from the path. No luck.
Testing the method against the very own .jar file worked okay. Now, when I try to access the inside of the file, it doesn't let me. On earlier versions of this project it worked just fine. I am not really sure of what is going on. Any help is welcome.
Thank you in advance,
Renato
When loading resources from a jar file, I've always used a classLoader. Everything seems to work the same whether you run from within the IDE, launch the executable jar file or run the program from a web site using JNLP.
Try loading the resource this way instead:
try {
ClassLoader cl = ZM.getClass().getClassLoader();
ImageIcon img = new ImageIcon(cl.getResource("images/programIcon.jpg"));
// do stuff with img.
}
catch(Exception failed) {
System.out.println(failed);
}
One more suggestion - you should create a separate folder for resources. In my example above, images is a folder inside of my src folder. This way it will automatically become part of the jar when I build it, but I am keeping resources separate from source code.
I suppose your problem is in loading an image from your jar file.
Here is how i do it
URL imageurl = Myclassanme.class.getResource("/test/Ergophobia.jpg");
Image myPicture = Toolkit.getDefaultToolkit().getImage(imageurl);
JLabel piclabel = new JLabel(new ImageIcon( myPicture ));
piclabel.setBounds(0,0,myPicture.getWidth(null),myPicture.getHeight(null));
This way I can get the Ergophobia.jpg file inside 'test' package.
I am trying to use IM4J (a Java wrapper for ImageMagick) to create thumbnails of JPEGs and it is my first experience (ever) with both libraries. Please note that this is a hard requirement handed to me by my tech lead (so please don't suggest to use anything other than an IM4J/ImageMagick) solution - my hands are tied on the technology choice here!
I am getting a FileNotFoundException on the and convert command which tells me I don't have one of these libraries (or both) setup correctly.
On my computer, here is my directory structure:
C:/
myApp/
images/ --> where all of my JPEGs are
thumbnails/ --> where I want ImageMagick to send the converted thumbnails to
imageMagickHome/ --> Where I downloaded the DLL to
ImageMagick-6.7.6-1-Q16-windows-dll.exe
...
In my Java project, I make sure that the IM4J JAR (im4java-1.2.0.jar) is on the classpath at runtime. Although I am required to use the 1.2.0 version of IM4J, I have the liberty to use any version of ImageMagick that I want. I simply chose this version because it seemed like the most current/stable version for my Windows 7 (32-bit) machine. If I should use a different version, please send me a link to it from the ImageMagick downloads page in your answer!
As for ImageMagick, I just downloaded that EXE from here and placed it in the folder mentioned above - I didn't do any installation, wizard, MSI, environment variable configuration, etc.
Then, in my Java code:
// In my driver...
File currentFile = new File("C:/myApp/images/test.jpg"); --> exists and is sitting at this location
File thumbFile = new File("C:/myApp/thumbnails/test-thumb.jpg"); --> doesnt exist yet! (destination file)
Thumbnailer myThumbnailer = new Thumbnailer();
myThumbnailer.generateThumbnail(currentFile, thumbFile);
// Then the Thumbnailer:
public class Thumbnailer
{
// ... omitted for brevity
public void generateThumbnail(File originalFile, File thumbnailFile)
{
// Reads appConfig.xml from classpath, validates it against a schema,
// and reads the contents of an element called <imPath> into this
// method's return value. See below
String imPath = getIMPathFromAppConfigFile();
org.im4java.core.IMOperation op = new Operation();
op.colorspace(this.colorSpace);
op.addImage(originalFile.getAbsolutePath());
op.flatten();
op.addImage(thumbnailFile.getAbsolutePath());
ConvertCmd cmd = new ConvertCmd();
cmd.setSearchPath(imPath);
// This next line is what throws the FileNotFoundException
cmd.run(op);
}
}
The section of my appConfig.xml file that contains the imPath:
<imPath>C:/myApp/imageMagickHome</imPath>
Please note - if this appConfig.xml is not well-formed, our schema validator will catch it. Since we are not getting schema validation errors, we can rule this out as a culprit. However, notice my file path delimiters; they are all forward slashes. I did this because I was told that, on Windows systems, the forward slash is treated the same as a *nix backslash, in reference to file paths. Believe it or not, we are developing on Windows
machines, but deploying to linux servers, so this was my solution (again, not my call!).
IM4J even acknowledges that Windows users can have trouble sometimes and explains in this article that Windows developers might have to set an IM4JAVA_TOOLPATH env var to get this library to work. I tried this suggestion, created a new System-wide environmental variable of the same name and set its value to C:\myApp\imageMagickHome. Still no difference. But notice here I am using backslashes. This is because this env var is local to my machine, whereas the appConfig.xml is a config descriptor that gets deployed to the linux servers.
From what I can tell, the culprit is probably one (or more) of the following:
I didn't "install" the ImageMagick EXE correctly and should have used an installer/MSI; or I need to add some other environmental variables for ImageMagick (not IM4J) itself
Perhaps I still don't have IM4J configured correctly and need to add more environmental variables
Could be the Windows/*nix "/" vs. "" issue from my appConfig.xml file as mentioned above
I'm also perplexed as to why I'm getting a FileNotFoundException on a file named "convert":
java.io.FileNotFoundException: convert
I assume this is a batch/shell file living somewhere inside the IM4J jar (since the only thing I downloaded for ImageMagick was the EXE). However, if I extract the IM4J jar I only see classes inside of it. I see "script generator" classes, so I assume these kick off before my cmd.run(op) call and create the convert file, and maybe that's what I'm missing (perhaps I need to manually kick off one of these generators, like CmdScriptGenerator prior to executing my Thumbnailer methods. . Or, maybe my download is incomplete.
Either way, I'm just not versed enough with either library to know where to start.
Thanks for any help with this.
Run the 'ImageMagick-6.7.6-1-Q16-windows-dll.exe' installer first to install the imagemagick libraries. Then make sure your environment path includes the location of the installed binaries ('convert.exe', 'mogrify.exe', etc)
Make sure u have Set the environment-variable IM4JAVA_TOOLPATH.