generate jar without dependencies - java

I am generating a jar inside a java program by using the jdk system-compiler.
I have some class files which I add into a jar:
JarOutputStream target = new JarOutputStream(jarStream, manifest);
addClassFilesToJar(new File(classDirectory), target);
I have some dependencies which I added into the manifest as:
lib/dependency1.jar
lib/dependency2.jar
...
Now the jar looks up in a sub-folder lib for the dependencies.
The jar itself should not be a runnable standalone jar. I want to include the jar in a project where all the dependencies are already present.
MyApp/ <-- Root folder of project
MyApp/MyJar <-- folder for the generated jar lies
MyApp/dependencies <-- folder for dependencies from MyApp and MyJar
So what do I have to do, to generate the jar in a manner that the classpath argument itself given to the jvm will handle the dependencies? (wanted solution)
Is it possible or do I have to create the manifest so that it points to the MyApp/dependencies folder? (not wanted solution)

Related

Keep resource file on root level in repackaged JAR file

I'm using the Spring Boot Maven Plugin in my pom.xml and more precisely the repackage goal to create an executable jar: https://docs.spring.io/spring-boot/docs/1.4.1.RELEASE/maven-plugin/examples/repackage-classifier.html
This moves all application classes under BOOT-INF/classes in the JAR file.
In my case I have a file under my src/main/resources path, let's say it's src/main/resources/my-file.txt.
In a normal JAR file the above my-file.txt would be placed at root level in the JAR.
When I repackage the JAR however, the file goes to BOOT-INF/classes/my-file.txt. This is a problem for me as I really need this file on root level in the JAR.
Is there a way to achieve what I'm looking for with maven somehow as I don't want to have to manually insert the file on root level into the JAR with a command afterwards?
Thanks!

How do I package this maven project or Java Application?

I'm creating a new project that run as a Java application(.jar), but I am confused about how to package the lib folder into the final jar file.
And I try to use Maven, but did not found some eligable plugins.
The project structure is here
first, I try to package with IDEA's build Artifact. it will extract all jar file into final jar and create a MANIFEST file, but the impact is there are some file like "*.SF, *.RSA", it destory the java -jar xxx.jar, But we can solve it by delete these .sf/.rsa file. Next problem occur, cause I use some springframework dependency, when extract these jar file, they will create a file like spring.handles, but its not complete.
second, I try to use MAVEN. I use the maven-jar-plugin maven-compiler-plugin maven-dependency-plugin to copy all jar file into final jar, and create the correct MANIFEST file. BUT a java.lang.NoClassDefFoundError occur, I am DEAD!!!
So, the actual question is how can I package the lib folder into final executable jar???

Java export running jar w/ project

So, I've added a git repo to my project (sjxlsx). I've then right-clicked the repo and imported into the package explorer. I then went to Project->Build path in order to make sure it's on "Required projects on the build path".
When I debug on Eclipse, works just fine.
I'm now trying to export as a running jar and when I execute it outside of Eclipse, it somehow is giving an error (empty.xlsx not found). That is, because in the XLSXWriterSupport, the open method is fetching this empty.xlsx file. On debug, it's working as expected but on converting to a running jar, it's giving me this error.
This is due to this 'empty.xlsx' file being on the resources of the other project. How can I solve this?
https://github.com/davidpelfree/sjxlsx/blob/master/src/main/java/com/incesoft/tools/excel/support/XLSXWriterSupport.java
This is because a resource on the class path is not a File on the file system.
Here it is packed in a jar (zip format).
The wrong code:
if (getClass().getResource("/empty.xlsx") == null) {
throw new IllegalStateException("no empty.xlsx found in classpath");
}
workbook = new SimpleXLSXWorkbook(new File(getClass().getResource("/empty.xlsx").getFile()));
As SimpleXLSXWorkbook has only a File constructor (AFAIK), you need to create a temporary file.
Path tempPath = Files.createTempFile("sjxlsx-", ".xlsx");
Files.copy(getClass().getResourceAsStream("/empty.xlsx"), tempPath);
workbook = new SimpleXLSXWorkbook(tempPath.toFile());
Better have some provision to delete temp files, for instance creating them in a specific directory, see Files.
You probably have the Eclipse Project build path configured to use absolute library references. When you try to run your runnable jar, the jvm cannot find the required dependencies.
Edit:
If you want to export your software as a RUNNABLE jar file, then the jar must contain a MANIFEST file which specifies the dependencies and main class. Example:
Manifest-Version: 1.0
Main-Class: com.example.Main
Class-Path: lib1.jar lib2.jar
(assuming your main class is com.example.Main)
In order to run your runnable jar file, place lib1 and lib2 on the same directory as your runnable jar and run:
java -jar myJar.jar
Otherwise you could just compile your main class and run it like this (assuming lib1 and lib2 are copied into a lib/ dir on your main class root path):
java -cp '.:/libs/*.jar' com.example.Main
You could also use a dependency manager tool such as maven and configure your build to create an "uberJar":https://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
uberJars contain all your software dependencies in one heavy runnable jar file.
Hope this helps.

ClassNotFoundException when using a self-created jar file

Using Eclipse I created some parser classes I want to provide to another project as a jar archive for validation purposes. So the parser project look like this:
ParserProject
- src
-- com.package.x
--- ClassA
--- ClassB
- lib
-- external1.jar
-- external2.jar
The ClassA and ClassB use the external jar archives, like Jackson or some Apache commons. To provide the functionality to another project, I exported the entire project as jar archive and executable jar archive (Right click on project > Export... > Java > JAR file > Select all files and "Export generated class files and resources" > Finish).
The jar file is created without any errors. When I use the parserproject.jar in my validation project, I can access all my methods using auto completion, but when I run the validation project, I get a java.lang.ClassNotFoundException: com.fasterxml.jackson.core.JsonParseException.
Now three strange things:
All jackson jars are included in the parser project. Besides, I can run a main() method in the parser project and everything works fine, no ClassNotFoundException occurs.
When I add the parserproject.jar to my validation project in the class path and open the jar archive in the Package Explorer, the parserproject.jar seems to contain all jars it needs.
For the executable jar archive, all required external jars are contained in the MANIFEST.MF (Package Explorer > validation project > Referenced Libraries > + besides parserproject.jar > META-INF > MANIFEST.MF). It looks like this:
Manifest-Version: 1.0
Rsrc-Class-Path: ./ json-20140107.jar jackson-annotations-2.5.4.jar ja
ckson-core-2.5.4.jar jackson-databind-2.5.4.jar commons-io-2.4.jar co
mmons-validator-1.3.1.jar slf4j-api-1.7.5.jar slf4j-log4j12-1.7.5.jar
json-schema-validator-2.2.6.jar jackson-module-jsonSchema-2.4.4.jar
juniversalchardet-1.0.3.jar snakeyaml-1.15.jar commons-beanutils-1.7.
0.jar commons-digester-1.6.jar commons-logging-1.0.4.jar joda-time-2.
8.1.jar jopt-simple-4.6.jar jsr305-3.0.0.jar json-schema-core-1.2.5.j
ar libphonenumber-6.2.jar jackson-coreutils-1.8.jar commons-lang-2.6.
jar guava-16.0.1.jar msg-simple-1.1.jar btf-1.2.jar mailapi-1.4.3.jar
uri-template-0.9.jar
Class-Path: .
Rsrc-Main-Class: com.package.SchemeValidator
Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
I get the exception if and only if I use the generated jar file in my validation project. In case I get rid of the parserproject.jar and define a dependency to the ecplise parser project instead (Right click on validation project > Properties > Java Build Path > Projects) I do not get the ClassNotFoundException.
So now my question is, how I should export the jar so that every class is found. Thank you!
Eclipse only takes care of the compile-time dependencies while generating a .jar
Since your generated .jar can be moved to virtually anywhere, the dependencies must again be present during execution time.
You have two options:
Execute your jar with the -jar option, while leaving all
dependencies in the same folder. Since your manifest uses "./" as classpath, this means all dependencies must be on the same directory you are executing your jar from. NOTE classpath is relative to the directory you are executing from, not the directory the file is on.
Execute your jar withour the -jar option, and specify the -cp option to point to the dependencies, and the specify the main class.
java -cp "<path to your jar>;<path to dependency 1>;<path to dependency 3>[;...]" <your main class>
You might consider creating a so called fat jar which will contain all the needed classes. For example: http://fjep.sourceforge.net/
If you do not want to go through the hassle of managing all the depencencies by yourself, consider using a build tool like
Maven https://maven.apache.org/ or Gradle https://gradle.org/.

Creating a merged executable Jar from many jar files(used in classpath)

I have a desktop application , which is packaged as a self-executable jar file, but my code needs to access many jar files , which i have set in the class-path in the manifest file. But the problem that I am encountering is that all the jars to be used in the class-path I have to keep them in the same directory as my executable jar file.What I need is to somehow merge all the various jars so that I can specify this single jar in my class-path in .mf file.
The .mf file is-->
Class-Path: poi-3.7-20101029.jar poi-examples-3.7-20101029.jar poi-ooxml-3.7-20101029.jar poi-ooxml-schemas-3.7-20101029.jar poi-scratchpad-3.7-20101029.jar jfreechart-1.0.14.jar jcommon-1.0.17.jar jfreechart-1.0.14-experimental.jar jfreechart-1.0.14-swt.jar junit.jar servlet.jar swtgraphics2d.jar gnujaxp.jar iText-2.1.5.jar
Main-Class: gui/GUILauncher
Kindly suggest me a solution, so that I can achieve my objective...
You could specify a path to each at file in the manifest
Class-Path: lib/poi-3.7-20101029 ...
And store the library jars here.
While I like the idea of combining all he classes into a single Jar, you need to be careful of resources that might share the same path. We have this issue in our app, all our Jars contain a Version file we use as a marker and read via Class.getResources(...)
You need not keep all these jars in executable jar directory. Instead you could specify relative path of dependent jars in Manifest.mf file.
e.g.
You have kept your executable jar under bin folder and dependent jars under lib folder.
app-root
+
+ \bin
+ + GuiLauncher.jar
+
+ \lib
+ junit.jar
+ servlet.jar
Manifest.mf Classpath will be
Class-Path: ..\lib\junit.jar ..\lib\servlet.jar

Categories