I have started studying JSF and I would like to know what is the JAR to include within our classpath to start using JSF. Is it jsf-api or jsf-impl? Or we have to include both? And if it is both then why they are not merged?
I'll assume that you're not using a real Java EE application server like WildFly, TomEE, Payara, etc, but a barebones JSP/Servlet container like Tomcat which indeed doesn't ship with JSF out the box and you thus had to manually install it. Otherwise, all this fuss with JARs is unnecessary.
Is it jsf-api or jsf-impl? Or we have to include both?
You need both. The jsf-api.jar contains the API, which exist of almost only abstract classes and interfaces. It are the javax.faces.* types which you are importing and using in your code. The jsf-impl.jar contains the implementation, which exist of the real hard working code. The implementation is internally loaded via factories in API. It are the com.sun.faces.* classes which you are not supposed to import and use directly in your code. If you do, then you wouldn't be able to switch to a different JSF implementation, such as MyFaces.
And if it is both then why they are not merged?
There exist a merged JAR, the javax.faces.jar. You can pick this one instead of the two loose JARs.
See also:
Our JSF wiki page
JSF implementations and component libraries
Difference between Mojarra and MyFaces
In simplest terms, what is a factory?
How to properly install and configure JSF libraries via Maven?
I’m trying to use JAXB 2.2.11 in an osgi environment (Liferay DXP). I am having issues creating a JAXBContext. Based on some other sources found while researching like this and this, I have determined that in an osgi container I need to provide the correct classloader for JAXB to instantiate the context. So I have code like this:
ClassLoader cl package.with.jaxb.objects.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("package.with.jaxb.objects ", cl);
This code causes a null pointer exception with the following stack trace:
Caused by: java.lang.NullPointerException
at javax.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:129)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:201)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:146)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:371)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:446)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:409)
Looking at the source for ContextFinder I can see that context must be null on line 129:
throw handleClassCastException(context.getClass(), JAXBContext.class);
I thought perhaps the problem was that my module has a dependency on jaxb-api 2.2.11 but the jaxb-impl classes are provided by rt.jar at runtime and are probably newer than 2.2.11 because Liferay DXP runs on JDK 1.8. To get around this issue, I have tried including jaxb-impl.jar 2.2.11 as a dependency in my osgi module, thinking then the jaxb-api & jaxb-impl versions would match. After that, trying to create a JAXBContent using the same code as above results in the following error:
ClassCastException: attempting to cast jar:file:/C:/Program%20Files/Java/jdk1.8.0_144/jre/lib/rt.jar!/javax/xml/bind/JAXBContext.class to bundleresource://623.fwk616113009:13/javax/xml/bind/JAXBContext.class. Please make sure that you are specifying the proper ClassLoader.
By the looks of this message, the JAXBContext that is getting instantiated is from the version of JAXBContext that is loaded via rt.jar. This is very confusing to me because I would expect the version of JAXBContext loaded by my module’s classloader to be used since I’ve included jaxb-impl.jar in my module and I’ve specified my module’s classloader is the one to be used in my call to JAXBContext.newInstance. Can anyone shed some light on how I can get jaxb 2.2.11 to work in an osgi container?
*Please note that I can’t upgrade the version of jaxb-api used by my module because the JAXB code is actually in a 3rd party jar that requires jaxb 2.2.11 (I have just eliminated the 3rd party jar from the equation for now by writing some test JAXB code).
After extensive research I found the following solution. Since it seemed like passing the bundle class loader as suggested by the accepted answer in this post had to be correct, I followed the path of figuring out why I was getting a NullPointerException when I tried that. After carefully looking over the source code for jaxb-api to follow the stack trace of the NullPointerException, I could see that the jaxb-api code does things like
classLoader.loadClass("com.sun.xml.internal.bind.v2.ContextFactory")
where classLoader is my bundle's class loader (since that's what I passed in) and ContextFactory is actually a class in jaxb-impl which is loaded by the bootstrap class loader. This is where the problem lies because my
bundle's classloader isn't going to be able to see classes loaded by the bootstrap class loader. This threw me for a while because I'm not used to how class loaders work in osgi. I incorrectly was thinking the classes loaded by the bootstrap class loader would be visible because I'm used to web app class loading where there is delegation. In osgi class loaders
are completely isolated from each other, things are only visible if they are exported. To get around the issue I found some helpful posts talking about similiar issues. It turns out there is a concept
called boot delegation in osgi where you can specify a list of classes/packages to always be loaded via the bootstrap classloader. So the end result is two steps:
1) Switch the thread's class loader to your bundle class loader before calling the code to get the JAXBContext:
ClassLoader currentClassLoader = Thread.currentThread().getContextClassLoader();
try {
// ObjectFactory here is in the same package as my classes to be marshalled
ClassLoader objectFactoryClassLoader = ObjectFactory.class.getClassLoader();
Thread.currentThread().setContextClassLoader(objectFactoryClassLoader);
// JAXB code goes here
} finally {
Thread.currentThread().setContextClassLoader(currentClassLoader);
}
2) Specify packages to be loaded using the boot delegation mechanism. This list needs to include the transitive dependencies of the classes you need loaded. In my case, I'm using Liferay so the list
is specific to Liferay and it goes in portal-ext.properties configuration file. Luckily I found this post where someone had done most of the work for me:
module.framework.properties.org.osgi.framework.bootdelegation=\
__redirected,\
com.liferay.aspectj,\
com.liferay.aspectj.*,\
com.liferay.portal.servlet.delegate,\
com.liferay.portal.servlet.delegate*,\
com.sun.ccpp,\
com.sun.ccpp.*,\
com.sun.crypto.*,\
com.sun.image.*,\
com.sun.jmx.*,\
com.sun.jna,\
com.sun.jndi.*,\
com.sun.mail.*,\
com.sun.management.*,\
com.sun.media.*,\
com.sun.msv.*,\
com.sun.org.*,\
com.sun.syndication,\
com.sun.tools.*,\
com.sun.xml.*,\
com.yourkit.*,\
org.eclipse.persistence.internal.jaxb,\
org.eclipse.persistence.internal.jaxb.*,\
javax.xml.*,\
sun.*
Helpful links:
Why can't JAXB find my jaxb.index when running inside Apache Felix?
What is the difference between bootdelegation and DynamicImport-Package in osgi
https://web.liferay.com/web/user.26526/blog/-/blogs/liferay-dxp-and-weblogic-
https://dev.liferay.com/develop/tutorials/-/knowledge_base/7-0/bundle-classloading-flow
http://apache-felix.18485.x6.nabble.com/Classloading-for-JAXB-td4834670.html
Here is the workaround that worked for me using JDK 11, Liferay DXP/7.2, OSGI, with a sample Jax-RS web service created from Dev Studio. The error I was getting was as follows when trying to access the web service:
JAXBException occurred : Implementation of JAXB-API has not been found
on module path or classpath..
com.sun.xml.internal.bind.v2.ContextFactory cannot be found by
org.apache.aries.jax.rs.whiteboard_1.0.4.
What worked for me was to define the context factory at the system level to override the predefined context factory. Add the following system variable to your system
javax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
For example you can add this in your setenv.sh/bat file in Tomcat, or in eclipse you can access your server Launch Configuration, Arguments tab, under VM arguments
-Djavax.xml.bind.JAXBContextFactory=com.sun.xml.bind.v2.ContextFactory
This worked without adding any extra libraries since Liferay already has those libraries included.
How does this work? Refer to the javadoc for JaxBContext and read the Discovery of JAXB implementation Section. Using the /META-INF/services/javax.xml.bind.JAXBContext file did not work for me.
I hope this helps someone.
One final note for DXP users, if you get a permission denied on your service then you need to read about Service Access Policies
The best place to see how it should be done is Apache Karaf. It doesn't install any JAXB-API bundle - instead it uses org.apache.servicemix.specs.jaxb-api-2.2-2.7.0.jar inside lib/endorsed directory.
This way you won't use JAXB-API provided by rt.jar.
For implementation - it's best to use ServiceMix version of JAXB bundles:
org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxb-impl:2.2.11_1
org.apache.servicemix.bundles:org.apache.servicemix.bundles.jaxb-xjc:2.2.11_1
I have a Spring web app deployed on Jboss AS 7.1 and uses JDK 1.6.
Also use docx4j to deal with ms office word files.
Jboss forces its own jaxb implementation.
However docx4j needed the JDK 1.6's jaxb implementation.
How can i use jdk's jaxb instead of jboss's jaxb?
You can place a jaxb.properties file in the same package as a domain model to override the default JAXB implementation used.
jaxb.properties
As an example below is what the contents of the file would look like to specify EclipseLink MOXy as your JAXB provider. To specify an alternate JAXB (JSR-222) provider you just change the value of the property:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
For More Information
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
Related to Access restriction on class due to restriction on required library rt.jar? jaxb-impl has many classes that are provided by rt.jar, which is the reason behind the warning.
I generated my web service from a WSDL file.
If I'm meant to exclude jaxb-impl in order to get rid of the warning, what is it for then?
Which are the libraries I really need to keep for my web service to run, and which were only useful for generating the code related to it?
jaxb-impl is the JAXB implementation that CXF will use by default. In most cases, you can remove it at runtime (not at wsdl2java time though) and CXF will be ok. However, the jaxb-impl that CXF pulls in is generally newer than the versions found in the JDK and usually has several bugs fixed that would still be present in the in-JDK versions of JAXB. CXF and CXF users tend to stress JAXB pretty hard and find interesting issues that we log with them and eventually get fixed.
I am running into an issue with JAXB 2 when marshaling my objects. I have an XmlJavaTypeAdapter which is working perfectly fine in unit tests, but when I try to marshal the same object graph from a web service (using JAX-WS), the XmlJavaTypeAdapter is being ignored completely. What's the easiest way to debug this problem?
I have a simple standalone project checked into my svn repository that demonstrates this issue. Can somebody please take a look to see if I am doing something obviously wrong? The URL for the project is: http://archfirst.googlecode.com/svn/trunk/java/examples/jaxb-jaxws-sample. There is a readme.txt file in the root folder that describes the issue in detail.
Thanks.
Ok, I finally found the problem. My unit test was picking up the JAXB implementation in the Java runtime, whereas my web service was picking up the JAXB implementation from GlassFish. Apparently the implementation bundled with GlassFish (2.2.1.1) cannot handle my use case. I proved it by forcing my unit test to use jaxb-impl-2.2.1.1.jar. Also it seems that the bug has been fixed in the latest JAXB implementation (2.2.3-1), but I am struggling to figure out how to replace GlassFish's implementation with this new version (see my post here).