Trouble migrating web application from Java 8 to 11 and JEE to JakartaEE - trouble with jaxb - spring

I encountered big trouble when trying to migration a web application from Java 8 to Java 11.
The web application:
The web application provides SOAP web services (using Spring WS), is written in Java 8 and runs on Tomcat 9. Spring 4.3 is used for database access, OXM, MVC and dependency injection.
To build the web services, multiple XSD files are used to auto-generate the class files and WSDL document for the web service interface using the xjc tool from the JDK.
My goal:
Migrate the application to Java 11, Tomcat 10 and JakartaEE.
What I have done so far:
In the first step, the compiled web application is migrated using Apache migration tool (version 1.0.0) to get it running on Tomcat 10. There is no problem.
Java migration:
The next step is, to migrate the source code from Java 8 to 11.
Java 11 does not longer include the tools and libraries for XML binding, which makes it necessary to include the XML bind library from JakartaEE.
Rebuilding the auto-generated class files from the XSD files with xjc, that comes with the library, creates source code, which imports from jakarta.xml.bind instead of javax.xml.bind. (Which should be the correct package).
Using JakartaEEs library also requires some minor changes in the code (changing imports to use jakarta.xml.bind instead of javax.xml.bind)
That's the point, where the trouble begins...
The IDE shows no errors and the code is compiled with no errors. Running the web application shows me the error, that javax.xml.bind.JAXBException was not found.
Since there is no source file, that refers to javax.xml.bind I assume, that a library is the cause. I found many references to that package in the Spring OXM library. But: In the master branch of that library, that these references are still there.
I tries to run JEE XML bind and JakartaEE XML bind at same time, but then Spring WS complains about multiple object factories of same type in same name space (which is not true by the way. Both object factories are generated by xjc for different name spaces and reside in different packages...)
My questions:
How can one use JakartaEE, when it is not supported by libraries like Spring?
Did I miss something?
Can someone give me some hints how to migrate the code?
Best regards,
Markus

Related

LinkageError on WebSphere 9 for javax.transaction.* classes

I have a web application that used to run fine on many web servers (tomcat, jboss, weblogic and websphere). Now, however, it has an error when deploying on WebSphere 9.
The app contains the jar javax.transaction-api-1.2. Some of its classes, e.g., javax.transaction.xa.XAResource, are also included in Java SE, but not all of them. Some are specific to Java EE and are required by some 3rd-party libraries in my app. The app is always deploying with child-first (parent-last) classloader.
WebSphere 9 throws this error during startup when the app tries to load the Oracle JDBC driver:
java.lang.LinkageError: loading constraint violation: loader "com/ibm/ws/classloader/CompoundClassLoader#7157be44" previously initiated loading for a different type with name
"javax/transaction/xa/XAResource" defined by loader "com/ibm/oti/vm/BootstrapClassLoader#422c7b1b"
Note that we aren't actually using XA transactions in the app, we are using regular transactions.
On other servers, and previous versions of WebSphere, it was never a problem. The server didn't care that we load XAResource from inside the war, even if it was previously loaded somewhere in the server. Now WebSphere 9 is different, it says that the app classloader already loaded this class from the server, but I don't know why or when did this happen.
Any idea how to solve this?
Remove the transaction API from your application. JTA 1.2 is already included in the server and provides no value in your applications. It's always risky to bring Java EE/SE APIs in a parent-last class loader unless you are 100% certain that they are technically necessary, because they can lead to issues like this one.
I can't say how this worked in previous server versions (there have been some Java-level changes in enforcing linkage issues like this), but the solution is reasonably straightforward.
At the end we did two things to solve this problem.
1) We upgraded the jta jar to version 1.3 (link here). This jar solves the problem by avoiding duplicate classes - it contains only J2EE classes and omits the J2SE classes that are already included in the JVM.
2) We upgraded WebSphere server from 9.0.0.7 to 9.0.0.11.
At the time, I suspected just upgrading the jar should suffice, but our QA had some issues with it and they also upgraded the server. Due to lack of time, we didn't investigate it further and just decided to do both.

SpringBoot creating a framework starter library

I am creating a library using spring-boot (v2.1.6.RELEASE) as a starter project that will facilitate as base extension jar responsible for configuring and starting up some of the components based on client project properties file.
The issue I am facing is that if the client project's SpringBoot Application class contains the same package path as library everything works like charm! but when client project contains different package path and includes ComponentScan, it is not able to load or start components from the library.
Did anyone encounter this issue? how to make client application to auto-configure some of the components from library jar?
Note: I am following the library creation example from here: https://www.baeldung.com/spring-boot-custom-starter
There are many things that can go wrong here, without seeing relevant parts of actual code its hard to tell something concrete. Out of my head, here are a couple of points for consideration that can hopefully lead to the solution:
Since we use starters in our applications (and sometimes people use explicit component scanning in there spring applications) and this obviously works, probably the issue is with the starter module itself. Don't think that the fact that the component scan is used alone prevents the starter from being loaded ;)
Make sure the starter is a: regular library and not packaged as a spring boot application (read you don't use spring boot plugin) and have <packaging>jar</packaging> in your pom.xml or whatever you use to build.
Make sure you have: src/main/resources/META-INF/spring.factories file
(case sensitive and everything)
Make sure that this spring.factories file indeed contains a valid reference on your configuration (java class annotated with #Configuration). If you use component scanning in the same package, it will find and load this configuration even without spring factories, in this case, its just kind of another portion of your code just packaged as a separate jar. So this looks especially "suspicious" to me.
Make sure that #Configuration doesn't have #Conditional-something - maybe this condition is not obeyed and the configuration doesn't start. For debugging purposes maybe you even should remove these #Conditional annotations just to ensure that the Configuration starts. You can also provide some logging inside the #Configuration class, like: "loading my cool library".

Null pointer exception from ODataApplicationInitializer in SpringBoot jar

I created my project by using S/4HANA SDK (spring boot archetype), now I need the functionality to provision some ODATA services so I also introduce the dependency com.sap.cloud.servicesdk.provodatav4 to my project and then create metadata file and odata service implementation class. However, after packaging my project into jar file and run it, I get null pointer exception from the class com.sap.cloud.sdk.service.prov.v4.rt.core.web.ODataApplicationInitializer. After seeing the source code of this class, it seems it use "File" object to get metadata file from classpath, but this way doesn't work in a jar file. My question is: does it mean I have to change the packaging way to "war" in order to use this SDK for odata service development? Thanks very much.
The unfortunate answer is that, as of today, the Service SDK (not the S/4HANA Cloud SDK) is only compatible with pure Tomcat environments and assumes the Servlet standard as well as surrounding mechanisms as the default mean. The reasons for this is that the Service SDK is an integral part (the runtime) of the SAP Cloud Application Programming Model which is self-contained and may not be combined with arbitrary frameworks such as Spring Boot.
Adding to Philipp's answer that this is not supported, you may be able to use the traditional deployment here. However, since this is likely not supported officially, I would encourage to consider an alternative approach.

Eclipse Java EE project and Spring : classnotfoundexception

I am trying to build an project in Eclipse (actually I'm using RAD, so basically eclipse, and when I say 'Java EE Project' I mean an 'Enterprise Application Project').
My Enterprise Application Project (the 'EAR' project) has two module projects :
- service
- web
The service project has some stuff in it, all wired up using Spring.
The web project has its own stuff in it, all wired up using Spring. The UI stuff in the web project needs to use the stuff in the service project.
Both projects are included in the EAR project as modules.
The web project lists the 'service' project as a dependent project in the build path, it's checked off for export, and also has it listed as a EE Module Dependency.
I'm having a really hard time to get this working though:
The spring context in the web project is of course what gets loaded when the application is deployed, and it imports the spring config I need from the service project. This seems to be working fine.
When spring tries to instantiate a bean it throws a ClassNotFoundException. On the very first bean.
I tried simply copying the spring config from my service context and pasting it into my web context, but I got the same ClassNotFoundException.
I have tried instantiating an object of that type (the class that spring says cannot be found) in the java controller class in the web project, and it is successful, both at compile time (no compile errors) and at runtime (no exceptions).
So the classes from my service project are not available on the classpath when spring tries to use them.
Any ideas what's going on here and/or what I might be able to do about it?
There is a class loader policy that you should use ParentClass First . That will be managed either through Application.xml or through web.xml . You need to check your xml's then try.
It's a class loader issue.
Since you're using Spring, I'll assume that you don't have EJBs. If that's the case, why do you need an EAR? Deploy the whole thing as a web project, in a single WAR.
Put all your .class and Spring configuration .xml files in WEB-INF/classes. Load the configuration using org.springframework.web.context.ContextLoaderListener.
I seem to have fixed this - I'm not sure exactly what the problem was but there must have been a small typo in my spring config. I decided to just start fresh with a new spring config and when I started building the new one back up things were working fine. There must have been a problem with the old one.
Thanks for the suggestions though.
Unfortunately we're not always able to change project structure. We're working on structures other people have put in place.
I looked into the ParentClassFirst vs ParentClassLast setting - it seems on websphere the ParentClassFirst setting is the default if you don't specify anything, so I'm leaving it without specification to get that functionality.
http://publib.boulder.ibm.com/infocenter/wasinfo/v6r0/index.jsp?topic=/com.ibm.websphere.express.doc/info/exp/ae/crun_classload.html

How do I declare a data source for GlassFish?

I know how I'd do this using JBoss: create a *-ds.xml file, and drop it into my deploy directory.
Is there a declarative way to do the same with GlassFish (v3.1)?
Am I thinking about this the wrong way? (See next question)
Is there a more-Glassfishy way to get my Java EE application to talk to a database?
Other potentially-revelant info:
I want to connect to a SQL Server 2008 database
I'm using Eclipse + GlassFish Server Tools
I know next to nothing about GlassFish. I'm much more familiar with JBoss
You can define it in application.xml or ejb-jar.xml of your EAR. You can even use annotations.
Long answer short: DataSource Resource Definition in Java EE 6.
BalusC is right (+1), with Java EE 6 you can declare datasource definitions either through annotations or through the use of deployment descriptors in a standard and portable way.
Just in case you'd be also interested by creating other resources than datasources like JMS resources, you can also package a glassfish-resources.xml file as part of your application. See:
Supporting glassfish-resources.xml
4.1.3 Application scoped resources

Resources