Include library for JAXB into JAR file without using Maven - java

I have a Java project in Eclipse that uses javax.xml.bind.JAXB classes.
Starting the application from inside Eclipse works perfectly.
However, when I export the project as (runnable) jar file and run it using java -jar myfile.jar it terminates with a java.lang.NoClassDefFoundError: javax/xml/bin/JAXBException.
Also playing around with the three options for Library handling in Eclipse Runnable JAR File Specification (extract, package, sub-folder) does not solve the problem - in fact, no libraries are exported in any case.
It seems that the library for JAXB (it seems to be rt.jar) is not considered as required library to be included into the jar file. However, when running the jar file, it is not found nevertheless.
I have read that the library must be added to the classpath but this seems strange to me as rt.jar is part of the standard libraries. Is there something special about this library?
Currently, I do not use Maven or something similar for dependency and build management and if possible I want to avoid it for the future. I think, there also must be a way without Maven.
I found several posts here on SO and in Google but was not able to work out a solution for me.
Thank you very much!

As remarked in the comments, Eclipse probably uses a different Java version than your system (by default). The JAXB API and implementation is not available in JRE 11.
To work on all versions of Java, your best option is:
Download the JAXB RI distribution. Nowadays I'll choose version 3.0 (which is binary incompatible with the one in Java 8, since it uses jakarta.xml instead of javax.xml for the packages name) as in Juliano's answer:
https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/3.0.0/jaxb-ri-3.0.0.zip
Copy the 4 files jakarta.activation.jar, jakarta.xml.bind-api.jar, jaxb-core.jar and jaxb-impl.jar from the mod folder into the library folder of your project (let's say lib),
Add the 4 libraries to the project's "Build Path",
Make sure you use JAXB 3.0 throughout your code (the packages of the annotations and classes start with jakarta.xml)
Run the application once in Eclipse, so it updates the Run Configuration (or update the classpath of the Run Configuration yourself),
Export the project to a JAR file.
Among the three export options proposed by Eclipse: "extract required libraries" will create a so-called fat jar (everything in one JAR-file). It works, but it deletes the licence notices in the JAXB jars (so it can not be distributed). "copy required libraries" is your best option, but then you have to move the jar file together with the subfolder. _". "package required libraries" will not work, since jars in a jar are not read by the JVM (unlike JARs in a WAR package).
Edit by the author of the question:
The above worked for me well except that I experienced small differences how the two libraries (javax.xml in Java 8 and jakarta.xml in version 3.0) handle #XmlAttribute annotations. In javax.xml, I could place an annotation without further arguments on the public getter-method, e.g.
#XmlAttribute
public String getDescription() {
return "";
}
And this worked when the attribute name in the xml file is description. However, with jakarta.xml I had to add the name of the attribute:
#XmlAttribute(name="description")
public String getDescription() {
return "";
}
Just in the case, that others experience the same problem.

I thought about this myself too, since I am new to java.
There is a description of a Extension Mechanism in the java tutorials (SE), but it is no longer used since deprecated by Oracle. See, just to know of what I am talking about: https://docs.oracle.com/javase/tutorial/ext/index.html
What was this Extension thing in a nutshell: just drop your jar files inside the jdk lib and you could use the import keyword in all your classes to use the new jar file.
However, others had to do the same thing in their computers to run a class which imported your own update to the jdk.
Maven do something like the above. It searches on the pom file which other jar files it should include in your jar when you build an application. Hence, it may run anywhere.
Another way of looking into this is the answer which you should try to do.
A clunckier way of doing what Maven does without its pom structure is to create a new folder inside your src folder and copy the jakarta.xml.bind-api.jar. Just like when you create an object (aJavaBean) and need to use it in another class.
The file you need to include in your library is available at:
https://repo1.maven.org/maven2/com/sun/xml/bind/jaxb-ri/3.0.0/jaxb-ri-3.0.0.zip
Finally, extract the classes inside this newly created folder and use the import keyword in the classes that depend on it just like when you create your own classes.
Another thing you should try is to use the manifest file when making your jar.
https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
This tutorial shows how to include a classpath to the files you need to run as a dependency. Make sure that everything you need is inside the newly created jar file.
Also, set the entry point in the manifest, so your application can run just using
java -jar MyJar.jar
in the command line.

The easiest way is to use JDK 8 (or older JDK) that has embedded the required jaxb library. The hard way requires that you set your CLASSPATH variable pointing to each required jaxb jar file.
From spec at https://javaee.github.io/jaxb-v2/doc/user-guide/release-documentation.html#a-2-3-0, the following jars are required using a java version 11 or above.
jaxb-api.jar
jaxb-core.jar
jaxb-impl.jar
A good article on this question is https://www.jesperdj.com/2018/09/30/jaxb-on-java-9-10-11-and-beyond/

Related

Class-Path setting in executable jar doesn't seem to work for plugins

I've looked here and the wider web to find a solution to this. There's related material, but I've been unable to find anything useful about my specific question.
I'm working on some Java software that needs to accept plugins. I don't want to use a fancy framework like OSGi, and ServiceLoader seems to offer the right level of support. I've basically got it working but am having a problem with classpaths. My directory structure is as follows:
progfolder
|___________ plugintest.jar
|___________/plugins
|________ plugin1.jar
|________ plugin2.jar
If I run plugintest.jar with java -jar plugintest.jar then it doesn't find the plugins even if I add ./plugins/ (or variations of this) to the Class-Path: in the manifest. Reading suggests that this only works for classes, not jars, so I've tried putting the classes from the two plugins inside plugins both directly and within their full path of directories, but with no success.
I'm not allowed to add -cp plugins/* to add the plugins folder to the classpath if I'm using the -jar option. To get round this, I can run using java -cp plugintest.jar;plugins/* com.plugin.test.Main and this works as expected - the two plugins are detected and accessible via code, but the command line is a bit clunky, although I could live with it, if it's the best option.
I found another solution where I create a classloader for jars found in plugins, which works in this simple case, but reading suggests I might run into security issues in a more complex application.
Is there a way to fix things so I can simply run with java -jar plugintest.jar without having to do my own class loading or is this just the way it is?
Ok, so at least a partial answer, following more experimentation. Putting the class files in the plugins directory does work, after all, but you have to remember to include the META-INF directory and META-INF/services. The file in the services directory has to include references to all the plugins.
It would be nice if there was a solution that allowed the plugin jar files to be used directly, but creating a class loader seems to be the only way to do this (that I've found, at least), and this may cause security issues, as previously noted.
last time I faced with similar problem [1]. I found answer in java documentation [2]:
Note: The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over Internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's manifest to load classes in MyUtils.jar into the class path.
[1] https://github.com/narvi-blog/01-exec-jar#dependency-jar-files-within-an-executable-jar-are-not-so-easy
[2] https://docs.oracle.com/javase/tutorial/deployment/jar/downman.html

How to add external third party jar in Notes Xpages application?

I am Java developer, recently working on Xpages project. we are using Notes 9.0.1. I created Java agent to send email and I want to use some third party jar, something like org.apache.commons.lang3 , end up this issue. how to add third party jar, like commons-lang3-3.4.jar, in my Xpages project?
I tried different ways
add jar under /jvm/lib/ext folder, restart DDE.the I can see it in
my project JRE system libray, but could not import in my Java code.
Maybe this is the way for server deployment.
add jar under /Code/Jars and then DDE generated with new name added in /Webcontent/WEB-INF/lib, but...
Add jar directly under /Webcontent/WEB-INF/lib, but not appeared /Code/Jars in Application view
add jar under the Java agent Archive folder, but...
None of them allows me import the package in my Java code.
Anything I did wrong, or is there any good way to add third party jar in XPages project.
Thanks
If you add a JAR to your project by importing it into /Code/JARs, it should be added so as to be accessible by your build path(2,3). The same is true of your /WebContent/WEB-INF/lib, but that may not be automatically defined in your version of DDE; for example, Domino Designer 9 has the design elements of /Code/Java and /Code/JARs, which didn't previously exist (these are separate folders/paths from /WebContent/WEB-INF/src or /WebContent/WEB-INF/lib, either can be in the build path). In either case, if your approach is to have the JAR in your NSF, make sure your build path has the path with your JARs. Separately you could add each JAR individually.
You can get to the Build Path via Project > Properties, then for the part of your build path concerning JARs, go to "libraries":
individual JARs in Project Build Path
JAR class path in Build Path (ex- /WebContent/WEB-INF/lib)
As for the path of using the /jvm/lib/ext folder approach, I've covered that in a blog post and it's important to remember to have the JARs in the appropriate relative path both on the server and in your Designer/local path (otherwise your local, DDE, may not pick up the change).(1)
For both, if you keep build automatically turned off, you'll want to make sure you perform another build to see the changes.
As for a Java Agent archive, this should just work and again I'm wondering whether your build automatically setting is enabled/disabled. The /jvm/ext/lib path ought to work for this as well (shown in my linked blog post).(4) *Note: as Paul Withers points out in the comments, importing a JAR to a Java Agent can introduce memory leak issues, making the /jvm/ext/lib/ path preferable.

Adding a class to an exisiting Jar files - Eclipse

I think this is a super easy question, but im new to this and not sure what to do. So I have added an external jar file into one of my projects, and was able to decompile the classes using JAD to see some of the class files, the thing is I want to add a new class to one of the directories in same JAR file, compile it and update the jar file. I was googling and I came up with things like an 'ANT build file' but not sure how that would work?
Thanks!
First of all i would check out if the developper of that JAR has provided the source to the classes. This reduces the possibility of JAD not beeing able to fully decompile all the class information.
However once you have all the .java files (including your changed or added class) you can let eclipse build the jar file as follows:
1.) Compile the .java files (Project -> clean..)
2.) File -> Export -> Java -> Jar file (click next)
3.) Select anything that belongs to the jar, input a name and click finish (Note the checkbox that says to export generated class files and resources).
Regarding Ant/ Maven and stuff: Those are just tools that help you. The same result you can archive by opening a console and use javac.exe to compile you can use ant or maven to compile your classes. Its just a matter of configuration.
I recomend you skip Ant right here and directly do the Maven in 5 Minutes tutorial :)
Your approach works. But you can have two classes with same name and package. This will remove the necessarily of updating the jar file.
You must set the loading order to make sure that your new modified version will be used instead of the one which is in the jar file.
Possible to use two java classes with same name and same package?
Before any tweak and class loader, test this approach, may be the default class loader behavior will do what you want.

How to load a resource from compound JAR?

I have the following problem:
I am writing an application that uses some of the JARs from the Netbeans Platform. To be exact, I am only using the Netbeans Visual Library for creating some graphs. This can be done without using the Netbeans Platform by extracting 3 JARs from the platform. This is all working well, except for 1 problem.
Some Background
I am using the Java Simple Plugin Framework (JSPF) to handle my plugin management. So I have an application that basically consists of a skeleton framework, and then depending on which plugin JARs it finds, it can do various things, one of which is drawing graphs. The JAR plugin for this functionality has all it's dependant libraries inside. This is done by exporting the JAR as an artifact in IntelliJ, which will unJAR all the dependant libraries and reJAR them inside yours (so everything you need is there).
The Problem
What seems to be happening though, is that when it tries to start use the classes from the embedded libraries, it works fine, but when it needs resources (.png specifically in my case), it complains that it cannot find it.
My Thoughts
The only thing I can think of why it is not working, is that it could be since the plugin JAR is not in a classpath. Could this be it?
Is there anyway to specify a classpath directory in the MANIFEST maybe? Otherwise must I create my own ClassLoader and manually load all the JARs in the plugins directory?
Thank you!
UPDATE:
I have subsequently pinpointed that it is indeed a problem with the classpath. If I place my compound library on the classpath, everything works perfectly. The problem I experience now though is:
If I copy the library to /Library/Java/Home/lib/ext/ it works fine. If I execute the application with java -cp "/path/to/plugins/myLib.jar" -jar Application.jar it does not work.
How can I load all the jars in the plugins directory into my application so the resources inside them can be used?
Thanks again!
So I have finally figured out what was happening. When creating a executable jar, the MANIFEST.MF file overrides any classpath you specify in the command-line, which basically renders it useless if you want to specify external jars. This seems to be a general problem that has been logged since Java 1.3 already.
My simple solution is to simply not create a executable jar, and then launch the application with a script:
java -cp App.jar:plugins/* my.package.structure.App
which works perfectly.
The default classloader's do not load classes in nested jars. You'll need to write your own classloader to get the classes in the nested jars.
You can check out this jspf article...
"I forgot: Adding dependencies as JARs inside JARs is not possible, because it would not work in all scenarios (e.g., applets); IIRC also tools like Eclipse would have problems if you used classes with unresolved (read: runtime-resolved-dependencies). To my knowledge there is no established way yet to gracefully handle nested JARs in all circumstances."
http://code.google.com/p/jspf/wiki/UsageGuide

searching through .jar files eclipse

I'm porting a few java gwt projects into eclipse and the projects depends on many external .jar files, some of the dependencies seem to be dynamically linked so eclipse isn't picking up the missing links while running the ide.
At run time, I often get exceptions that say for example 'import bar.foo.XML' is missing or some FooBar class definition is missing and it always takes me a while to figure out which .jar file these classes/libraries belong to so I can add them to the run path.
Is there a quick way to search which .jar files contain what classes and what other library they depend on?
An oldie, but still good, and integrated into eclipse:
JarClassFinder:
Update 2013: the project still exists in a different form as an independent app JarClassFinder.
In term of Eclipse plugin, it is no longer maintained, and you only have variant like "BundleclassFinder".
Other (manual) ways to find a class within jars: "Java: How do I know which jar file to use given a class name?"
You need a tool like Jar Analyzer
Can't you just mark all the jar-files in Eclipse and right-click->add to Build Path?

Categories

Resources