How does Java find a specification implementation? - java

I don't understand how java knows an implementation of any spec..
For example, I have a Spring App with JSF, if I place the Mojarra jar on classpath the app works, but I have not done nothing but that add it to classpath, all without configuration
If I take out the Mojarra jar, then my app doesn't works.
Even, How it can differenciate between Mojarra or MyFaces without any change?
I just want to know how Java finds the implementations, not why it doesn't work if I take out the jars ;)

Usually the Java spec classes are divided in two parts:
An API part(jar) that contains mainly interfaces usually provided by the spec guys.
An implementation part(jar) that contain the implementations of these interfaces.
An example of the above is JDBC: javax.sql.* classes are provided by sun/oracle, but the implementation is done in the JDBC drivers provided by each db vendor. In this case some kind of configuration is needed in order to "map" the API to its implementation because you use API classes only.
Your example with JSF is a little different in that both Mojarra and MyFaces contains the API classes from javax.faces.* package, basically there are different classes with the same names. So there is no need for configuration, the classes have the same name in both libraries and are loaded by the class loader whenever needed from the Mojarra or MyFaces jars whichever is on the classpath.

I have found MyFaces and Mojarra Implementation for JSF. I have realized that both has same pachage structure so it means that all are compliance with JSF spec. In other word which implementation jar is given into classpath classpath loader will handle it.
It is all about Java Class Loader mechanism of JVM. You can find detailed discussion at Java Class Loaders
Here is the picture of both JSF implemantation package structure.

I've seen the mojarra jar (JSF Reference Implementation) and I found that it uses The Service Loader API, since it places the javax.servlet.ServletContainerInitializer, javax.enterprise.inject.spi.Extension and com.sun.faces.spi.injectionprovider inside the /META-INF/services folder in the javax.faces-2.2.0.jar.
This is how java distinguishes between an implementation and another (mojarra or myfaces).

Related

Classloader problem with JAXB internal implementation interface com.sun.xml.bind.namespacePrefixMapper

I need help for the following problem: I use Websphere Liberty 19.0.0.9 with Oracle and IBM Java 1.8 an run an older application (EAR) containing an EJB, which serializes XML with JAXB. The application needs to control XML namespace definitions and prefixes and does this by providing an implementation of com.sun.xml.bind.namespacePrefixMapper to javax.xml.bind.Marshaller.setProperty with property "com.sun.xml.bind.namespacePrefixMapper".
At runtime the error java.lang.NoClassDefFoundError: com/sun/xml/bind/marshaller/NamespacePrefixMapper occurs when loading the implementation class.
The server.xml contains feature javaee-8.0, and the liberties’ JAXB implementation wlp-19.0.0.9\lib\com.ibm.ws.jaxb.tools.2.2.10_1.0.32.jar contains the class com.sun..xml.bind.marshaller.NamespacePrefixMapper.
I tried to solve it by putting the jaxb-impl-2.2.4.jar to the EAR/lib (which is the wrong way because JAXB is provided by JEE) but then an error occurred in the com.sun.xml.bind.v2.runtime.MarshallerImpl.setProperty(MarshallerImpl.java:511) because the check if(!(value instanceof NamespacePrefixMapper)) failed, because the Classloader (AppClassLoader) of the implementation provided another class object for class NamespacePrefixMapper than the MarshallerImpls’ classloader (org.eclipse.osgi.internal.loader.EquinoxClassLoader). But this showed that the liberty can access the the NamespacePrefixMapper.
I made several attempts to use the same classloader for the implementation and the MarschallerImpl when loading them, and I tried to solve it by classloder settings in the server.xml. No success.
I know that it is not recommended to use such JAXB implementation specific classes, but the application was developed this way and cannot be changed easily.
Any help is appreciated which tells me how to convince liberty to either provide the NamespacePrefixMapper class to the application classloader, or to use the application classloaders NamespacePrefixMapper also in the MarschallerImpl.
Thank you.
//The implementation class looks for example like this:
public class MyNamespacePrefixMapperImpl extends com.sun.xml.bind.marshaller.NamespacePrefixMapper {...}
JAXBContext c = JAXBContext.newInstance(some mapped class);
Marshaller m = c.createMarshaller();
com.sun.xml.bind.marshaller.NamespacePrefixMapper mapper = new MyNamespacePrefixMapperImpl();// Here the NoClassDefFoundError occurs.
m.setProperty("com.sun.xml.bind.namespacePrefixMapper", mapper); // Here the instanceof check fails if jaxb-impl.jar is in EAR/lib.
this is a precarious situation without an easy solution. Liberty attempts to "hide" internal packages to avoid scenarios where users want a slightly different version of the implementation than what the framework provides - the most glaring example of this problem was in traditional WAS where users wanted to use a different version of Jakarta Commons Logging than what was shipped with WAS - this required users to provide their own, either in an isolated shared library, or use other parent-last classloading hacks to make it work. Liberty avoids those issues by isolating the internal implementations from the user applications.
So that works great when a user wants to use a different version of a third party library than what Liberty provides, but as you have discovered, that doesn't work so great when your legacy application depends on those hidden/isolated third party libraries.
The most ideal solution would be to refactor the application code so as to not depend on internal JAXB classes - somebody with more JAXB expertise may be able to help with this... But it sounds like that may not be feasible, so another alternative would be to create a user feature. A user feature is essentially an extension to Liberty's runtime - so it has access to packages that user applications do not. It also allows you to add packages as APIs for the user applications - so you could use a user feature to add the com.sun.xml.bind.marshaller as a public API - then your user application could extend it freely. You could also include your MyNamespacePrefixMapperImpl class in your user feature and register it there so that it would automatically apply to all applications in your server.
You can find more information on user features here:
https://www.ibm.com/support/knowledgecenter/en/SSEQTP_liberty/com.ibm.websphere.wlp.doc/ae/twlp_feat_example.html
Hope this helps, Andy

Including JSTL implementation jar only

Following this answer, below is a simple JSP demo that includes only JSTL implementation jar(javax.servlet.jsp.jstl-1.2.1.jar), but not JSTL API jar(javax.servlet.jsp.jstl-api-1.2.1.jar),
My understanding is, JSTL implementation jar holds both API(mostly Java interfaces) and it's implementation. This is the reason test.jsp got compiled and executed successfully.
Further, same approach would work with servlets using API implementation jar provided by Tomcat container without using API(servlet-api.jar).
Is this the right understanding?
Api contains only interfaces you need to compile your code. The implementation could be in different library.
Tomcat and any other Java web servers provide implementation at runtime, so you don't need to package implemented classed and carry on them with your app.
You could see in the logs if implementation is already loaded if you deploy your application that contains classes impl.

Do I have to compile my java web app classes against a certain servlet container?

I'm a long time ASP.NET developer trying to teach myself java. I've got Jetty downloaded and a basic web app setup. The tutorials in Head First Servlets and JSP tell me to reference the container's servlet-api.jar (or servlet-api-3.0.jar in Jetty's case) file when compiling, which makes sense since I'm extending the servlet classes and all, but doesn't this tie my application to a specific container's servlet implementation? If I compile my app against Jetty, can I still deploy the app under Tomcat or any of the EE servers (glassfish, jboss, etc...)?
No, this shouldn't be a problem because you aren't referencing servlet-specific classes. servlet-api.jar is a well-documented specification in the form of several interfaces and abstract classes.
Every container has to have a copy of this JAR (possibly compiled using different Java version, or compiler) because it implements the specification, but the API itself never changes. However note that you don't really have to reference container-provided JARs. You can safely use maven's version or any other you can find. They are all compatible. Sometimes they are not bundled due to various licensing incompatibilities.
That being said: write once, run everywhere applies here as well.
You aren't coding to the jar, you are coding to a specification which the jar happens to contain. Any server providing a web container will have an implementation of this specification, the jar which it is contained in is totally irrelevant.
As long as you only code to the specification, then you are not bound to any server implementation.
The jars are used at compile and runtime to resolve the necessary class dependencies you have. You can use any jar which provides the necessary API dependencies at compile time, but at runtime you will implicitly be using the implementation provided by the specific server. I say implicitly since you do not have to do any specific configuration for your own webapp to include the standard API or it's implementation, the server will already provide that for you, unlike a standalone app.

JAX-RS in relation to Jersey and JSRs

I'm trying to get my head around some concepts in Java:
JSR(s): describe specifications, but carry no actual implementations. E.g. http://jsr311.java.net/ is the "home" for "Java™ API for RESTful Web Services". It serves as a common reference for all implementations of JSR-311.
One can download the interfaces (?) of JSR-311 from http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, however, unless you are implementing JSR-311 by yourself these have no particular value?
JSR(s) will usually/always have a reference implementation. To find it you'll have to google "JSR XXX reference implementation" or see the specifications home page (e.g. http://jsr311.java.net/)
For JSR-311 this reference implementation is Jersey. Using maven you can get the jersey server from http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9. Since
Jersey provides an implementation according to the interfaces found in http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api, you only need to add Jersey as a dependency in your project and not the jsr311-api itself. (this applies to all JSR technologies?)
Putting both http://mvnrepository.com/artifact/javax.ws.rs/jsr311-api and http://mvnrepository.com/artifact/com.sun.jersey/jersey-server/1.9 as dependencies in your project will possibly cause classpath problems?
Am I completely off or onto someting?
Yes, this isn't anything new. Think about JDBC, java provides the
interfaces (Connection, Statement, ResultSet etc) but it is up
to database vendors to provide implementations.
If you're using a JSR-311 implementation like Jersey or Apache CXF
then you'll annotate your classes with the javax.ws.rs annotations, such as #Path, #GET, #Produces etc. This is why you need to explicitly have JSR-311 as a maven dependency.
Yes, usually. Have a look at the JSR list on wiki.
You need both the JSR and the implementation. The annotations are in the JSR, the implementation provides supporting classes, such as com.sun.jersey.spi.container.servlet.ServletContainer.
No, it is necessary to have both as dependencies (see point 4); you won't get classpath conflicts.
—
One can download files from a variety of sources. To get the most official version of the JSR-311 specification go to its JCP download page. It's quite possible that you can't get a JAR file (with all the interfaces and stuff) from JCP pages, but still, this is the official source. (There are always nice PDFs of public drafts also!)
—
You're right, because Jersey contains the API defined by JSR-311, however I would add a compile dependency to the jsr311-api JAR file and add Jersey as runtime dependency. This creates a nice separation between API and implementation and you can swap out your JSR-311 implementation anytime [sic]. If you intend to use Jersey all the way include only Jersey. One less dependency in your POM.
If Jersey packages the same API as the jsr311-api JAR contains, it won't. If it packages something different, well, that would be awful! Maven will probably bark at compile time if one has a corrupt JSR-311 API on its classpath (I've already seen lots of java.lang.ClassFormatError: Absent Code attribute in method that ... errors, so it won't go unnoticed, that's for sure).
Other than these, you're right.

Runtime code injection

SLF4J has a nice mechanism, where the implementation is chosen at runtime, depending of what is available in the classpath. I would like to use such feature in several projects, for example to choose the communication layer or to choose a mock implementation.
I had a look at slf4j source to see how it's done and I could just write something similar. Before I start, I would like to know if some lightweight FOSS library exists for this kind of injection.
Unless you need specific configuration abilities as provided by Pico or Guice, you may get what you need from java.util.ServiceLoader.
Basically, all you have to do is to package your service implementation in a JAR file, include a text file with a list of all implementation classes in "META-INF/services/" and on you go.
Have you looked at Weld, CDI is part of the EE6 spec but the Weld implementation also supports running in a Java SE environment. It has exactly what you are looking for, here is a link to the relative documentation:
http://seamframework.org/Weld one maven dependency for your SE app.
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/environments.html#d0e5333 bootstrapping the Weld container in SE.
Producer methods to vary implementation at runtime:
http://docs.jboss.org/weld/reference/1.1.0.Final/en-US/html/producermethods.html
Plus (in my very biased opinion) Weld rocks ;)
SLF4J's "mechanism" is simply that its API jar is compiled with code that refers to a class that is only provided by one of its "implementation" jars. No framework or library of any kind is needed for this. Simply write one module which is compiled against a class not in that module. Then your "implementation" modules provide that class when included in the project.
Edit: Oh, and this is basically OSGi writ small (very, very small). If you're going to use this kind of thing on a large scale, look to an OSGi container or Eclipse Virgo.
Every java programmer should know how to use Spring.

Categories