Classloading problem in multimodule maven application - spring

I have multimodule maven application. Inside the main directory where parent pom resides I have some modules. I am in the process of adding another one on the same level as the other modules. The application is packages as EAR and deployed into Websphere, this EAR is configured to use shared library which basically is a directory containing jars. In this shared library Apache Crimson resides which is used by some of the modules. I am adding the new module based on Spring Framework 4.0.0.RELEASE. The whole project is a legacy and uses Java 6 and Hibernate 2.1 :( . The problem is that this Crimson make my new module crashing during deployment:
BeanDefinitionStoreException: Parser configuration exception parsing
XML from ServletContext resource [/WEB-INF/spring/root-context.xml];
nested exception is javax.xml.parsers.ParserConfigurationException:
Unable to validate using XSD: Your JAXP provider
[org.apache.crimson.jaxp.DocumentBuilderFactoryImpl#706b4db8] does not
support XML Schema. Are you running on Java 1.4 with Apache Crimson?
Upgrade to Apache Xerces (or Java 1.5) for full XSD support.
So I added to my new module this:
`<dependency>
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.6.2</version>
</dependency`
But application still takes crimson.jar from the shared library. I tried to exclude this crimson.jar from parent pom but still it is taken from shared library.
Crimson is required by some other modules being packaged as jars hence the crimson is present ar EAR/lib level.
Another try was to change classloader order to take jars from the new module first and then go upward in the hierarchy (my new war module then parent ear). But this gave me some other exception.
The question is - how being in WAR module inside EAR module not take the jar from the ear level (it was also included in EAR/lib) and take from the WAR level only?

If parent-last class loading in the WAR doesn't work (perhaps due to something else in the WAR that can't be safely run with that delegation pattern), then I'd recommend an isolated shared library associated with the WAR. In the WAS administrative console, create a shared library with a class path containing the parser jar(s) you need, select the "use an isolated class loader for this shared library" option, then associated that shared library with the web module that needs it.
Isolated shared libraries utilize parent-last class loading, but only for the jars in the library rather than for the entire EAR or WAR. Because of that, you can target it to only the jars that you really NEED to use that type of delegation. The isolated library should allow you to use Xerces in the WAR while still using Crimson in the EAR.

Related

How to control module loading order in Liberty profile

I have an ear file with a web module and a ejb module(just used for message driven beans). The ejb module has dependency on web module and it's classes. I would need to load the web module first and then ejb module. But the liberty always loading the ejb module first causing com.ibm.ws.container.service.state.StateChangeException: java.lang.NoClassDefFoundError:
How to control the order of modules loading within the same ear file? On traditional webshpere there is an option called 'Starting weight'. Whichever module has lowest value takes precedence and loads it first. so the application works good on tradition Websphere. However, this property seems missing on Liberty. I already looked at this. It only talks about deploying the multiple war files and their order.
If your EJB module depends on Web, that is bad design. It should be the other way around.
If you have such situation , proper way would be to extract shared classes in to a common jar file, let say mycommon.jar and then put that into ear\lib folder. In this way they will be visible by both modules ejb and web.
If your EJB module depends on the javax web api (e.g. servletRequest) that is even worse, and you should redesign such classes to POJO DTOs.
As a last resort you could try what is described here and add <initialize-in-order>true</initialize-in-order> in your application.xml.
FRowe's solution will not work, as classes are not shared between the applications, so changing load order of apps will not help. Each Java™ EE application has its own class loader in a running Liberty server.
Consider using the ability to control app start order as described here: https://www.openliberty.io/blog/2020/06/05/graphql-open-liberty-20006.html?_ga=2.4728563.17466047.1620833568-1423690488.1614284842&cm_mc_uid=99965752544816136653536&cm_mc_sid_50200000=61078141620909829332#ORDER
You'll have to deploy the war module as an app instead of packaging it within the ear, but you should be able to achieve the proper ordering.

NoClassDefFoundError: in Web Sphere liberty Profile

I have deployed the one ear inside the dropins folder and one of the war file from the ear is referencing the jar which i kept outside folder (Shared->config->lib->global). External jars which i kept global folder is again referring few jar which resides in the ear and this time i am getting "java.lang.NoClassDefFoundError"
Can you please suggest how to give reference .
server.xml
<webApplication contextRoot="/xyz" id="zyx" location="xyz.ear" name="xyz" type="ear">
<classloader commonLibraryRef="global,filterjars"></classloader>
</webApplication>
Common shared libraries cannot load classes from application binaries. When using common libraries, you can think of them as a one-way connection.
The application's classloader can delegate to common shared libraries, but not the other way around.
Common libraries are implemented as their own classloader so they must contain all dependencies.
On the other hand, private libraries have their classpaths appended to the application classloader's classpath - so they could load classes provided by the application, but this is not a good practice. For example, if a private library depends on ClassA that application1 provides, it will work just fine for application1, but might break in application2 that might not provide ClassA (or might provide an incompatible version of it).
If you have classes in your shared libraries that depend on classes in your application, I would either recommend putting all of those classes in the shared library - or putting all of the shared library classes in the application (or WAR, etc.). I personally prefer the latter - self-contained applications are much more portable and less likely to run into classloader/dependency issues (i.e. app1 needs version X of some dependency, but app2 needs need version X+5...).
Hope this helps,
Andy

WebSphere 7 org.apache.axis2.deployment.WarBasedAxisConfigurator <init> org.apache.commons.fileupload.FileUploadException

This is a strange problem. I have an existing JEE project that is and has been in production on WebSphere 7. It is a multi-module EAR file. It has 2 WARs and 1 shared Java project. Most of it is Spring 4 based, but we have some web services we host using axis2 (1.5.4). This project does not use Maven. It does use a WebSphere deployment.xml (in the EAR) with the warClassloaderPolicy="SINGLE" and the classloader mode="PARENT_LAST". This controls the classloader policies for this EAR. All the jar files that the Java project and the WARs rely on are stored at the EAR level and referenced at the module level via the manifest files. That all works fine and has for several years.
Now I was trying to convert this project to a Maven project after all these years. Initially, I left the deployment.xml file settings as they always have been. But with these settings I was getting:
java.lang.VerifyError at com.sun.xml.bind.v2.model.impl.RuntimeBuiltinLeafInfoImpl "org.springframework.oxm.jaxb.Jaxb2Marshaller".
After much googling on this site and all around and trying 50,000 things, I tried one thing, which worked for most of the app. I switched the classloader mode to "PARENT_FIRST" and all of a sudden the WAR that exclusively uses Spring 4 worked. It started up without error and I was able to run it.
But, the other WAR which hosts the axis2 web services started getting the error:
org.apache.axis2.deployment.WarBasedAxisConfigurator <init> org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.NoClassDefFoundError: org.apache.commons.fileupload.FileUploadException....Caused by: java.lang.ClassNotFoundException: org.apache.commons.fileupload.FileUploadException
This class (org.apache.commons.fileupload.FileUploadException) is in both the compile and runtime classpath. In eclipse I can see it in the "Maven Dependencies" library that the m2e eclipse plugin creates from the POM files. I can also see this jar in the WebSphere runtime module classpath inspector (it shows up in there 3 times! Once under each WAR and once just in a list from the Maven repository location.)
One thing of note is that I've configured the project with a parent POM, where most of the dependencies are declared at the parent and then are inherited for each of the modules. In the EAR project, the POM is using the maven-ear-plugin with skinnyWars=true. However, it appears the skinnyWars directive is not respected when the m2e eclipse plugin deploys the EAR into the local WebSphere server (that is evident because I see these jars showing up in the classpath 3 times). But when I create an EAR using the Maven build, the EAR comes out correctly with each jar only showing up in the EAR one time.
This is my last hope to post something here and see if someone has an idea for something to try, otherwise I can't think of anything else to try.
Thanks...
Is there a particular reason you need to run with a single class loader for all the WAR modules, other than convenience? If not, you could rework the application in order to allow you to run PARENT_FIRST in the Spring WAR and PARENT_LAST in the Axis2 WAR.
If that's not an option for some reason, the path of least resistance might be to go back to PARENT_LAST and remove some libraries from the app or module. The VerifyError generally occurs if you're running with PARENT_LAST and have a library in the app that is also present in the server - in this case, the exception looks like it's coming out of JAXB, so you might want to see if simply removing JAXB (and perhaps JAXP, if present, since it's heavily used by JAXB) from the application resolves the issue with your default setup.
You could also stick with PARENT_FIRST and move the Axis2 jars to an shared library with an isolated class loader, associated with the app. An isolated shared library would make just the stuff in the shared library PARENT_LAST, so you can avoid the VerifyError and still get PARENT_LAST for Axis2. The issue in the PARENT_FIRST case appears to be because you're picking up WebSphere's copy of Axis2 but somehow have a dependency inserted from your app's copy - the failing class load is occurring in a server-level loader, so it doesn't see the copy in your app.

How to add custom launcher to spring-boot-maven's executable jar

How can I add a custom loader to the executable jar?
At the moment i'm doing it manually by opening the jar file, pasting the class and re-signing it the end. -.-
Thanks in advance,
Pedro Silva
Executable jar restrictions
There are 2 types of restrictions that you need to consider when working with a Spring Boot Loader packaged application.
Zip entry compression
The ZipEntry for a nested jar must be saved using the ZipEntry.STORED method. This is required so that we can seek directly to individual content within the nested jar. The content of the nested jar file itself can still be compressed, as can any other entries in the outer jar.
System ClassLoader
Launched applications should use Thread.getContextClassLoader() when loading classes (most libraries and frameworks will do this by default). Trying to load nested jar classes via ClassLoader.getSystemClassLoader() will fail. Please be aware that java.util.Logging always uses the system classloader, for this reason you should consider a different logging implementation.
Alternative single jar solutions
If the above restrictions mean that you cannot use Spring Boot Loader the following alternatives could be considered:
Maven Shade Plugin
JarClassLoader
OneJar
Resource Link:
The executable jar format
spring boot loading jars (application dependencies and external file system jars)

What is the use of converting jars to bundles in WAB(OSGI)?

After exploring the OSGi framework, I had developed a sample web application.The Web Application Bundle(.war or .jar) is packaged inside an eba.
The war file contains a bunch of embedded jar files in its WEB-INF/lib
directory.These jars have been converted to OSGi bundles(using maven-bundle-plugin) with the required export and import packages as per the relation between the jars.
Now I have to even mention all these jars(WEB-INF/lib) in the bundle-classpath.
The above works because a bundle(wab is also a bundle) can include one or more jarfiles within it, and use a Bundle-Classpath manifest.mf entry to point to them.
Incase I dont include the jars in the bundle-classpath I get a ClassNotFoundException.
The question is,then there's no point converting the jars to osgi bundles.Obviously all the jars in the WEB-INF/lib are loaded by the same class loader(i.e wab's class loader) ,so then we are not reaping the major benefits of OSGi which is mainly a per bundle classloader concept?
Putting jars inside the WEB-INF/lib is the old-style normal-java way of handling dependencies, and putting them outside the war is the new-style OSGi way of handling them.
By packaging your war's dependencies in WEB-INF/lib, you're treating them as normal jars (remember a bundle is also a jar). So in that case, you're right that there wasn't much point in using bundles.
One of the benefits of using wabs instead of wars is to get away from the dreaded 100 Mb monolithic war. Rather than packaging the bundles inside WEB-INF/lib, try having the war import the packages it needs using Import-Package:, and package the dependencies inside the eba. (If you don't remember to have the war import the packages it needs, you'll get the class not found exceptions you were seeing, because the OSGi container won't know your war needs those packages.)

Resources