An unexpected error occurred while trying to open jar - java

I have a spring batch project exported as a runable Jar file, it has 4 main methods, only one main is working, the other main needs referenced jar jai-codec-1.1.3.jar, but when I put the jar in the classpath, the first main also could not working and it gives error message "An unexpected error occurred while trying to open jar"
here is my mainfest file:
Manifest-Version: 1.0 Class-Path: JARS/spring-jdbc-3.1.1.RELEASE.jar
JARS/spring-context-3.2.3.RELEASE.jar JARS/log4j-1.2.14.jar
JARS/spring-tx-3.2.3.RELEASE.jar JARS/spring-core-3.2.3.RELEASE.jar
JARS/spring-beans-3.2.3.RELEASE.jar JARS/commons-logging-1.1.1.jar
JARS/spring-aop-3.2.3.RELEASE.jar JARS/aopalliance-1.0.jar
JARS/spring-expression-3.2.3.RELEASE.jar JARS/commons-dbcp-1.4.jar
JARS/commons-pool-1.5.4.jar JARS/ojdbc6-11.2.0.3.jar
JARS/commons-lang3-3.0.jar JARS/itextpdf-5.5.1.jar
JARS/jdom2-2.0.5.jar JARS/jai-codec-1.1.3.jar
I found out that it is not because the specific jar file, it is because the length of the classpath is exceeded the limit, is there a way to put more jars in the MAINFEST file classpath?
also I have defined all #autowired service and component classes but it still not working in jar, it only works when I defined those as bean in spring-config.
Anyone can Help me to figure out why?

This error may indicate (in a very unclear way though) an error in MANIFEST.MF. This can be emulated by an invalid empty line in the middle of the file or by lines too long.
MANIFEST.MF is extremely manual-edit-unfriendly:
It must have a final empty line (or final line terminator in other words),
its lines must be 72 bytes (not chars, see the comment) long at most (I bet this was your true problem, you just fixed symptoms)
and continuation line must start with space...
and on top of it, the classpath entries must be URLs, not file paths.
More about its specification can be found here: https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html

Problem solved. I am not sure if it is the limitation of classpath size in MAINFEST file, but it really matters when it was too long, I changed all jar name as 1, 2 , 3... and be able to put all jars in the classpath, and it works. Please leave your comments if you have different opinion on this, Thanks.

I will add that Properties in Manifest MUST NOT be dot separated, either dash or no separator: "myProperty" will work, "my-property" will work too, but "my.property" will fail with "Error: An unexpected error occurred while trying to open file ..." with no explanation at all.
Although "my.property" would work as a Java property in some standalone application, it just breaks the launch of the embedded application inside a JAR when the Manifest is read.

Related

Unable to locate a file in java project running in a executable jar

Both class.getResource(FILE_NAME) and class.getClass().getClassLoader().getResource(FILE_NAME) run perfectly inside my eclipse but the same code getting failed to locate the file which is inside the jar file, when run as an executable jar in windows machine.
I have gone through all related links available for this problem (well, not exactly the same issue but 90% in sync), asked for solution but no reply came from any of those posts, so I'm posting my issue as a separate question hoping for help on this.
In total, 4 cases I have ran to resolve but none worked so far and I'm out of ideas now.
class.getClass().getClassLoader().getResource("/resources/readme.txt");
class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");
class.getResource("resources/readme.txt");
Ouf of all the above 4 cases, only 2 cases ran successfully in eclipse which are as mentioned below.
class.getResource("/resources/readme.txt");
class.getClass().getClassLoader().getResource("resources/readme.txt");
The other 2 cases just throwing me Exception in thread "main" java.lang.NullPointerException
Coming to the executable jar, all 4 cases are throwing me the Exception in thread "main" java.lang.NullPointerException.
So I have created a folder named resources where my jar is residing and placed my files inside this folder and ran the jar. Now the jar is running without any issues referring to the files inside the resources folder I created. So wherever I run this jar (windows, linux etc.,) I need to create a resources folder and place my files under the folder. Now the question is, can it be possible to make my jar refer the resources folder which is inside the jar itself?
Any help on this is much appreciated!
To get your txt file:
File yourFileIsHere = new File("resources/readme.txt");
Where put your file?
In the same location of your jar, example:
myapp/yourjar.jar
myapp/resources/readme.txt
If you want read file inside of your "src" folder:
InputStream yourInputStream = new YourClass().getClass().getClassLoader().getResourceAsStream("readme.txt");
If you are using Spring:
org.springframework.util.ResourceUtils.getFile("classpath:readme.txt")
Otherwise:
import com.google.common.io.Resources
byte[] byteSource = Resources.asByteSource(Resources.getResource("readme.txt")).read()
method class.getClass().getClassLoader().getResource() may take 3 prefixes: url:, classpath: and file: each prefix tells what is your base of search. If you want to search inside your jar use classpath: prefix. That tells your classloader to search everywhere within your classpath. Here is one example how to deal with it with Spring tools. Look also at ResourceLoader class in Spring

JSP compilation fails when using dynamic classpath generated by IntelliJ IDEA on Windows

I have a Spring/MVC/Tomcat website project that I am attempting to run with IntelliJ IDEA. Because I am running on Windows, there is a command-line size limit, which is exceeded by the large classpath. I use IntelliJ's dynamic classpath feature which puts the classpath in a jar file to shorten the command line. Java runs with -classpath <classpath.jar>.
When I try to view a page, the JSP compilation fails with an error to this effect:
org.apache.jasper.JasperException: Unable to compile class for JSP:
An error occurred at line: [-1] in the generated java file: [<removed>.java]
[javac] <removed>.java:11: error: package javax.servlet does not exist
[javac] import javax.servlet.*;
[javac] ^
I ran it in debug and stepped into where the java compilation was being done and found the javac command line used. It was put together in org.apache.tools.ant.taskdefs.compilers.JavacExternal. I ran the javac command myself, with -verbose, and noticed that the dependency path from the search path for class files: log line shows up like:
C:\Users\<removed>\AppData\Local\Temp\file:\C:\Users\<removed>\lib\servlet-api-3.0.jar
Note that it seems like the absolute URI path is being treated as a relative path, resulting in an invalid path. I believe this is why it's not compiling properly.
Intellij's generated pathing jar's MANIFEST.MF lists the classpath with entries that are absolute paths that look like:
file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/charsets.jar file:/C:/Program%20Files/Java/jdk1.8.0_121/jre/lib/deploy.jar [...]
This problem doesn't happen on Mac, using dynamic classpath jar (even though it's not necessary because the command line too long error does not happen) so I believe something about the Windows path or the way that IntelliJ generates the classpath jar on Windows is messing up the JSP compilation.
Also, using an Ant build task that generates a pathing jar with relative paths works too, but I am interested in avoiding the use of Ant here.
How can I get this working, or what else do I need to investigate to get to the root cause?
This is a known bug in JDK.
Javac incorrectly handles absolute paths in manifest classpath headers. It has been fixed in JDK9.
When I investigated this problem, assuming Java8, I found a different root cause in my case.
In short:
The "/org/apache/jasper/servlet/TldScanner.java" on Line 102, attempts to scan locations for potential JARs.
It uses the "/org/apache/tomcat/util/scan/StandardJarScanner.java" to actually search.
Put a breakpoint on Line 221 URL[] urls = ((URLClassLoader) classLoader).getURLs();
You will see this ClassLoader has the "classpath.jar" as a potential JAR to scan (i.e. process).
But it cannot further find JARs referenced by a (classpath.jar) JAR's manifest file. Meaning, the real JAR(s) you need are not going to be checked.
A short fix, a for this is to:
Add "standard-1.1.2.jar" to your web/WEB-INF/lib/ dir.
If you look inside this jar, you will see *.tld files.
Test:
You can put a breakpoint on TldScanner.java Line 311 found = true;.
When it is not working, you will never hit this line.
When it works, with this (or any) fix, it will hit this line.

Error while load-time compiling

I created an Aspectj project and added .aj files and java files. While compiling(Load-time) it shows the error
"Error: Could not find or load main class javaagent:path/aspectjweaver-1.8.2.jar"
I compiled it in eclipse by creating Load time configuration file.
Can any one tell me why
Very simple: Probably you should provide a real file system path instead of the place holder path. Also be sure to use -javaagent:... (note the dash character) instead of something like javaagent:....

Confusion on Uses of Jar Manifest File

I am reading packaging java applications with jar tool. I noticed a manifest file is created under META-INF directory. For a simple application, it felt like, it's serves no purpose. I searched on stackoverflow to understand the usages of Manifest file. I came across UsesOfManifestFile. While reading the answer, i got confused on point 2 and 3 which are :-
What are download extensions? I am not able to understand the concept in the answer.
What does it mean to seal the jar? It has given an example below like this
Name: myCompany/MyPackage/ Sealed: true
What is the use of putting such information? Can someone elaborate on these points.
Thanks.
The manifest file is like the guidance instructions for the java program to run the jar. When the manifest is created it will hold crucial information, for example a reference to the main program. When the java program runs your jar it doesn't know where to start, so it look sin the manifest for a line telling it where the class with the main method is so it has a start point for the program. Another use is a classpath line, which will tell the program where to find any 3rd party library's in the jar are, otherwise again, the java program won't find them.
There is a range of data that can be stored in the manifest file, I would recommend checking out the Oracle information on them and seeing if that clears it up a bit more.
EDIT: From the Oracle site regarding your example:
Packages within JAR files can be optionally sealed, which means that all classes defined in that package must be archived in the same JAR file. You might want to seal a package, for example, to ensure version consistency among the classes in your software.
You seal a package in a JAR file by adding the Sealed header in the manifest, which has the general form:
Name: myCompany/myPackage/
Sealed: true
The value myCompany/myPackage/ is the name of the package to seal.
Note that the package name must end with a "/".
What this appears to mean is that any and all classes that you use in your program must be within the same jar file.
EDIT 2 (For comment response)
A manifest may contain the following line:
Main-Class: com.mkyong.awt.AwtExample
When the javaw.exe (I think) runs your runnable jar, it has no idea where to start from, all java programs run via a main method, but if you have say 50 class files in your jar, it has no idea which one has the main method to start from. It will look at the manifest file, reads your above line and thinks right, the main method is in the package com.mkyong.awt and the class is AwtExample, it then finds this class and runs the program from that main method. It's most basic function within the jar is to tell the java program running the jar where to find the stuff it needs to run your jar.
Note: that example manifest entry came from a little tutorial which shows how to create a simple runnable jar.
Good Luck!

IOException: 'Invalid header field; when creating .jar file with manifest

When I type jar cvfm file_name.jar manifest.txt *.class in command prompt I get this error:
java.io.IOException: invalid header field
at java.util.jar.Attributes.read(Attributes.java:410)
at java.util.jar.Manifest.read(Manifest.java:199)
at java.util.jar.Manifest.<init>(Manifest.java:69)
at sun.tools.jar.Main.run(Main.java:172)
at sun.tools.jar.Main.main(Main.java:1177)
I've never gotten this error before and I can't find anything on it, what does it mean?
Be careful about the order of the parameters:
1) jar cvmf manifest.txt some.jar package/*class
2) jar cvfm some.jar manifest.txt package/*class
Check the name of a header variable in the MANIFEST file. MANIFEST file is not correct.
This tutorial will help to identify the MANIFEST file format and related things, http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
In case you land here and tried everything and still isn't getting rid of the problem, take a look if there are any accidental tabs instead of 4 spaces for indentation in the MANIFEST file.
I was using a maven pom.xml file to auto-generate the MANIFEST and the property line was too big, spanning multiple lines like this:
<Extension-List> item1 item2 item3 item4
item5 item6 item7 item8 <--- these lines are idented with tabs
item9 item10 item11 item12 </Extension-List>
this was corrupting the MANIFEST file in a very hard to see way.
Your Manifest file has to follow the required format. If you're generating the file yourself, then you should be able to figure out where you got the syntax wrong. If the manifest file was generated by some tool or process, however, you'll have to check the tool's documentation to see whether you ran into a bug in the tool.
Read carefully the first line of your manifest, for example :
Main-Class: main.HelloWorld
I had this error because I added a space like this "Main-Class :"
Maybe it is something similar.
My problem was that I had loads of dependencies on one line so I split it up using a simple Find and Replace where each JAR was on a separate line. It turns out that if you have something like:
Class-Path: dependencies/org.apache.commons.cli_1.4.jar (note the space at the end)
dependencies/org.apache.log4j_1.2.15.v201012070815.jar (note the space at the end)
You need to make sure that the line doesn't end with a space, and that the new line begins with a space, like so:
Class-Path: dependencies/org.apache.commons.cli_1.4.jar
dependencies/org.apache.log4j_1.2.15.v201012070815.jar
This problem can also occur if your MANIFEST.MF file begins with some non-printable characters. Tools like notepad and wordpad don't let you see them, so you'll swear you're file looks right and that all your headers are valid.
In my case I got the message:
java.io.IOException: invalid header field name: Built-By
The clue if you are having this situation are those characters occurring before the valid Built-By header. Those are non-printable characters that somehow got into your MANIFEST.MF file. The other clue is to open a command line, navigate to your MANIFEST.MF file and do
>cat MANIFEST.MF
□Build-BY: TSRUT
Bundle-Description: Fragment Controller.
Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
Notice that box character before your 1st header at the beginning of the file. If that's the case, this is the solution to your problem:
Open up your favorite editor, manual select the entire file (do not use the select-all command, as that will also select those hidden characters). Close the file. Open a new instance of your editor, paste your content, and save the new file back to your original MANIFEST.MF file. Select yes to overwrite. Then verify that those hidden character were removed from the beginning of the file.
if your manifest file is having some additional empty lines will also cause this error . Make sure to remove the additional lines.

Categories

Resources