Hey everyone,
As many of you know, we’re preparing to release a completely revamped OpenMRS Platform 3.0.0. This major update will modernize the OpenMRS Core, including a migration to Java 21 as the minimum required version, officially dropping support for older Java versions.
While the OpenMRS Core already compiles with Java 21, most of our community-supported modules are not yet compatible. Here’s a list of key modules that need to be evaluated and updated:
During the recent Platform meeting, it was proposed that instead of blindly migrating all these modules to Java 21, we should review each module individually and make thoughtful decisions:
Should we update the module to support Java 21?
Should we replace it with a more modern or robust alternative?
Should we deprecate the module and migrate its functionality into the OpenMRS Core or another supported module?
We’d love to hear your thoughts on this approach. If you have any suggestions or updates regarding these modules, please feel free to share.
FHIR2 has additional considerations, since it’s heavily dependent on HAPI, but we need to make some adjustments to be able to upgrade to a newer version of HAPI which may be necessary to support Java 9+.
There’s been some noise about completely re-doing the event module, but that hasn’t materialized. However, that embeds a (quite old) ActiveMQ server which may not work on a newer version of Java.
For the REST module, the biggest issue is whether or not we retain support for older versions (going back to 1.8) and, if so, what it means to “update” it to support Java 21 (this is fairly unique in that retaining back to 1.8 also requires a Java 7 baseline instead of Java 8).
I have some concerns regarding the XStream module. While working on the migration, I’ve been encountering test errors like the one below, caused by illegal reflective access:
Caused by: java.lang.reflect.InaccessibleObjectException: Unable to make field private transient java.util.NavigableMap java.util.TreeSet.m accessible: module java.base does not "opens java.util" to unnamed module @473b46c3
This happens because XStream relies on reflective access to internal JDK classes, which is restricted in modern Java versions. we can mitigate this issue using the JVM option --add-opens, I don’t think we should rely on such workarounds for Java 21 migrations.
@ibacher also raised similar concerns in TRUNK-6197.
Unfortunately, that type of reflective access necessary for how XStream works.
I’ve proposed a few times migrating from using XStream to something else like leveraging Jackson to support XML, but that requires a bit of careful attention to ensure we can deserialize things that have been serialized using XStream and the fact that we have multiple XStream serializers probably complicates things a bit too.
tl;dr: transition to Jackson & JSON without trying to support legacy data; create a module to help implementations make the transition
We discussed this a bit on today’s Platform Team call. The general sentiment was that we don’t want to bypass constraints that have been made for security purposes (i.e., adding the JVM option --add-opens is not a viable option). The best way forward seems to be to adopt a widely supported & active library (like Jackson) that can serialize to JSON with the goal of supporting 80% or more of serialization needs (i.e. most cases but not necessarily all the edge cases). Once we have a Jackson JSON-based solution, then we could create a script or module that can do the one-time task of helping an implementation translate Xstream-based XML entries in the database to Jackson-based JSON entries.
Oh! One reason I was looking at Jackson is because it’s capable of serializing and deserializing XML. I kind of hoped that (with appropriate code changes) we could continue to support already-serialized XML data. (Apologies, I had an interfering call or else I’d have been on the platform call).
It would be great if we could identify here the downstream dependencies on SXS - what modules / features are using this that we need to preserve.
The reporting module is likely the biggest user and the most complex, as the definitions that it serializes can basically have any arbitrary Java property.
One thing I’ve had in the back of my head for a while now is to see if we can simplify the reporting module a bit for the future in a new major version, which would remove all of the legacyui dependencies, and all of the serialization.xstream, htmlwidgets, and calculation dependences, and put these into one or more optional add-on modules, so that the reporting module API could be leveraged without as much dependency baggage. This may be something to consider within this initiative.
Many thanks, @wikumc, for your contributions to this work.
As we continue migrating to Java 21 and beyond for both OpenMRS Core and individual modules, it’s important that our CI processes stay aligned with these changes. This requires updates to the existing CI job definitions — particularly in Bamboo and related supporting scripts on GitHub.
Bamboo is currently responsible for managing our builds, test executions, artifact deployments, and version tagging, and it needs to be updated to support the newer JDK versions. Historically, updating Bamboo to use newer Java versions has proven challenging. However, by leveraging Docker-based builds, we’ve already made significant progress in addressing this for OpenMRS Core, thanks to @raff and others on this achievement.
For modules — which are also an essential part of the backend , we fortunately have two complementary paths to support, all the way from Java 8 to 21+ and later Maven versions, while still reusing the existing Bamboo configurations:
Update each module’s Build and Deploy job definition on Bamboo to use Dockerized Maven builds.
Enhance the openmrs-contrib-bamboo scripts (particularly release-prepare-perform.sh) to leverage Dockerized environments and updating relevant plugins to ensure consistent builds across modules.
These changes will ensure that module builds remain consistent, reproducible, and compatible with the newer Java toolchain, without being hindered by host system limitations or unsupported Bamboo configurations.
I’d greatly appreciate any feedback or suggestions on this proposed approach.
Building with Docker on Bamboo makes sense to me @ruhanga . At PIH we have been doing this for a few years now, after making a push back in 2022 to move all of our Bamboo job definitions into Bamboo Specs and all of our builds to use Docker rather than locally installed Java/Maven/etc (or at least the vast majority). So I think this is a good move, and I’d be happy to share any of our work, though it is in a private repository so not easy for me to just send a link into.
That said, one question I’d have is whether we’ve considered moving away from Bamboo entirely for all of these builds and instead doing more of it with Github Actions. There are definitely pros and cons, and I assume we’ve considered it, so it would be good to understand what constraints there might be leading us to maintain these jobs in Bamboo into the future.
We have ~250 build and deploy plans in Bamboo; it’s unlikely we have the bandwidth to replace all of those anytime soon.
“Chaining” GitHub actions builds (so update module → update distribution) is more complex to figure out.
We’ve experienced some instability with GitHub actions build (e.g., builds never launching or being permanently left in “queued” states, actions runners failing, hours of downtime, often with no public status updates — though this one has been getting better in recent months)
This is less objective, but it was a big job migrating things when Travis.CI decided they were no longer supporting a free tier. While I don’t expect GitHub to stop supporting a free tier completely, I’m not sure I trust that they won’t eventually put limits around it.
Mostly, though, it’s just not a priority. That said, if there’s anyone in the community who has some cycles to help us build out some standardized GitHub Actions workflows and start attaching those to repositories, I’d be happy to setup whatever we need to make that work.
Of course. I guess I was working on the assumption that we are comparing updating all of these to build with Docker in Bamboo vs. moving to a Github action, so there is work to do for all 250 regardless.
I agree! This is one of the big benefits of Bamboo. However, these dependency chains are often not correct and lead to lots of unnecessary builds and deploys. For example, the various refapp builds are set up as dependencies of the “EMR API” module. However, none of these actually build against the latest snapshot of EMR API, but rather some older release. So kicking off these refapp builds and deploys is achieving absolutely nothing aside from extra work on the CI server and extra artifacts with zero changes deployed to Maven.
I have recently been piloting an approach to fix this, building on some great work that Mekom did to allow building and publishing artifacts that contain dependency reports. It’s not perfect, but I’d be interested in getting more community brainpower into seeing if we can make it work. See: openmrs-module-pihcore/.github/workflows at master · PIH/openmrs-module-pihcore · GitHub
More than happy to discuss more if anyone is interested or feels like this is a direction worth heading in.
For the 2.x RefApp we do, in fact, use a SNAPSHOT. I think there’s also a job that updates the SNAPSHOT. With the O3 RefApp, we don’t, but none of those jobs are triggered by those updates.
But anything we can do to work on better automated update pipelines sounds good to me.
Here’s a list of modules that are currently confirmed to compile with Java 21. I may have missed a few smaller modules that don’t have an associated JIRA ticket:
Legacy UI Module
UI Framework Module
Event Module
Address Hierarchy Module
Calculation Module
UI Commons Module
HTML Widgets Module
UI Library Module
You can use this ticket to track progress on Java 21 support across modules:
OMRS-341
@ruhanga FYI, the CI builds for the above modules are no longer using the master branch that has the Java 21 changes. We create a backwards compatibility branch for each module and point the current CI build to it. When your changes of compiling modules within docker, are completed, we are going to create new CI builds for the master branch.
@dkayiwa, I’d like to suggest to use Bamboo’s feature branch support. You can continue to build a master branch and create a feature branch e.g. 3.x that is built by Bamboo in addition to the master branch. It is automatically updated with changes from master. I used this approach for the core-2.8 branch in the stockmanagement module: Log in as a Bamboo user - OpenMRS Bamboo
The development can continue on the master branch and changes required to support 3.x are in the feature branch only. Changes from the master branch are automatically applied to the 3.x feature branch or the build fails if it runs into conflict so you can quickly resolve it. It’s a breeze to setup (just create a branch manually in the CI plan and override the development version to include qualifier such as -core-3.0-SNAPSHOT to distinguish it from artifacts from the master build.