Blog
Making your app Jira Data Center 10 compatible

- Marty Henderson
Making your app Jira Data Center 10 compatible like it’s 2024…¶
Oh hey, you may remember me from such stories as Project & Goal status tracking for Jira and scheduling jobs in Jira DC.
In case you’ve missed it, Atlassian has been on a big push to move forward the Data Center platform to improve security, performance and bring it forward.
Having been through a number of these shifts when I worked there, I can appreciate the trickiness of evolving the platform forward while trying to retain some aspect of backwards compatibility without the whole thing falling apart.
Put simply — it’s tough. And I respect the efforts of the people that go into it, it’s a thankless task. So from me to you — thanks for what you do, you’re awesome.
Want to read more about platform 7 and Jira DC 10? Check out:
Platform 7 upgrade in progress: Learn about the first highlights and changes
Hi Developer Community 👋, We recognize there is a lack of clarity around some of the changes that will be shipped as…community.developer.atlassian.com
Automating part of your Platform 7 upgrades with Openrewrite
Learn how to automate some of the changes that Platform 7 brings using Openrewritedeveloper.atlassian.com
Platform 7 upgrade guides
List of upgrade guides for components shipped in Platform 7developer.atlassian.com
There’s a lot in there, it’s worth a read.
What are we doing today?¶
So, as I recently released Project & Goal status tracking for Jira on the Atlassian market place, and given Jira 10 was released not that long ago..
Jira Software and Jira Service Management Data Center 10.0 are now available
Hey there, Data Center community! I'm excited to announce that Jira Software and Jira Service Management Data Center…community.atlassian.com
It’s time to try and upgrade our app to be Jira 10 compatible. Here’s what I did.
Step 1 — Try and run the Jira 8/9 compatible version¶
Appreciate my optimism. We might as well give this a go for funsies.
Unfortunately, it’d didn’t work, we’re getting a bunch of osgi import errors as part of the app starting up. Things like:
project-status-plugin [255](R 255.0)] osgi.wiring.package; (osgi.wiring.package=org.jspecify.annotations) Unresolved requirements: [[com.teamswork.collab.jira-project-status-plugin [255](R 255.0)] osgi.wiring.package; (osgi.wiring.package=org.jspecify.annotations)] at org.apache.felix.framework.Felix.resolveBundleRevision(Felix.java:4398) at org.apache.felix.framework.Felix.startBundle(Felix.java:2308) at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:1006) at org.apache.felix.framework.BundleImpl.start(BundleImpl.java:992) at com.atlassian.plugin.osgi.factory.OsgiPlugin.enableInternal(OsgiPlugin.java:408) ... 95 moreSo we’ll follow the rabbit down the hole and add some stuff to our import package directives in the pom.xml
...... org.python.util, org.jspecify.annotations, <!-- let bind discover the rest --> * </Import-Package>Wait, the app actually loads now? This can’t be right?
And it wasn’t. As soon as we try to do anything the whole app blows up.
Step 2 — follow some guides on what we should actually be doing¶
These are in the links above if you’re interested.
Let’s start be fixing up our pom.xml file. https://community.developer.atlassian.com/t/platform-7-upgrade-in-progress-learn-about-the-first-highlights-and-changes/76945
Add this:
<dependencyManagement> <dependencies> <dependency> <groupId>com.atlassian.platform.dependencies</groupId> <artifactId>platform-public-api</artifactId> <version>${platform.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependencies><dependencyManagement>We’re going to use the supplied versions of the platform artifacts as specified by this public api artifact. Rather then our previous approach of managing the versions of these internally.
You can check out what is actually contained in the public api here: https://packages.atlassian.com/artifactory/maven-atlassian-external/com/atlassian/platform/dependencies/platform-public-api/7.0.4/
Basically you want to use as much of that as you can.
The next step was to reconcile the various platform dependencies:
<!-- ======================================================= --><!-- Atlassian platform dependencies (API) --><!-- ======================================================= --><dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.soy</groupId> <artifactId>soy-template-renderer-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.soy</groupId> <artifactId>soy-template-renderer-plugin-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.audit</groupId> <artifactId>atlassian-audit-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.upm</groupId> <artifactId>licensing-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.upm</groupId> <artifactId>upm-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.plugins.rest</groupId> <artifactId>atlassian-rest-v2-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.inject</groupId> <artifactId>jakarta.inject-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.templaterenderer</groupId> <artifactId>atlassian-template-renderer-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.cache</groupId> <artifactId>atlassian-cache-api</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>com.atlassian.plugin</groupId> <artifactId>atlassian-spring-scanner-annotation</artifactId> <scope>provided</scope> </dependency></dependencies>The key thing to note here, is that we don’t provide any versions to use. Let this be managed by the imported bill of materials in the dependency management block.
Now let’s have a look at https://bitbucket.org/atlassian/atlassian-rest/src/8.0.x/UPGRADE_720.md
There’s a few dependencies here to call out specifically. If you’re using:
- javax.xml.bind
- javax.inject
- javax.servlet
- javax.ws.rs
- javax.annotation
You need to remove these and replace them with the appropriate platform dependencies. These need to be provided by the platform, not your app, otherwise you’re going to run into some dependency resolution issues.
Like this :
<dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <scope>provided</scope></dependency><dependency> <groupId>jakarta.inject</groupId> <artifactId>jakarta.inject-api</artifactId> <scope>provided</scope></dependency><dependency> <groupId>jakarta.servlet</groupId> <artifactId>jakarta.servlet-api</artifactId> <scope>provided</scope></dependency><dependency> <groupId>jakarta.ws.rs</groupId> <artifactId>jakarta.ws.rs-api</artifactId> <scope>provided</scope></dependency><dependency> <groupId>jakarta.annotation</groupId> <artifactId>jakarta.annotation-api</artifactId> <scope>provided</scope></dependency>Ok, great. Now, if you’re anything like me, there’s probably a bunch of other random maven dependencies in your pom with the version specified not as a property. It’s a good time to clean those up too. You’ll thank yourself in the future.
At this point you’re also very likely to run into a bunch more of the osgi import dependency errors — I’d like to say I have a magic way of fixing that but I don’t, you just need to work the issues and add them in one by one. Enjoy the whack-a-mole. If someone else has a better way of doing it, I’d love to hear about it.
Anyhoo, once I’d done this, I had to do some find and replace in the code base to get things to compile. I was using:
import org.codehaus.jackson.annotate.JsonProperty;and I needed to now use:
import com.fasterxml.jackson.annotation.JsonProperty;Easy. Even I can manage that.
Ok, so what’s next? Actually, not that much. We had a go with running with the configuration and amazingly, this loaded up…. but it still didn’t work. There was still a bit more to it. We’re getting this now:
Caused by: java.lang.NoSuchMethodException: Could not find a suitable constructor in com.teamswork.collab.rest.JiraResource class. at org.glassfish.jersey.inject.hk2.JerseyClassAnalyzer.getConstructor(JerseyClassAnalyzer.java:168) [jersey-hk2-2.42.jar:?] at org.jvnet.hk2.internal.Utilities.getConstructor(Utilities.java:156) [hk2-locator-2.6.1.jar:?] at org.jvnet.hk2.internal.Utilities.justCreate(Utilities.java:1042) [hk2-locator-2.6.1.jar:?] ... 328 more , referer=http://192.168.5.15:8080/plugins/servlet/ps/hello, servletErrorMessage=}Let’s have a look at https://bitbucket.org/atlassian/atlassian-rest/src/8.0.x/UPGRADE_720.md#markdown-header-common-problems-and-solutions. Aha. I see it.
One more thing to do. For all the rest resources I needed to add a constructor annotation:
@Injectpublic JiraResource( @ComponentImport final UserSearchService userSearchService, @ComponentImport final AvatarService avatarService, @ComponentImport final JiraAuthenticationContext jiraAuthenticationContext, @ComponentImport final GroupManager groupManager) { this.userSearchService = userSearchService; this.avatarService = avatarService; this.jiraAuthenticationContext = jiraAuthenticationContext; this.groupManager = groupManager;}And…. we’re good! Check it out!¶
Welcome to the application.

Search working well for projects and goals.

And watch us manage dependencies like a pro.

And here we are¶
Yes, indeed. We now have a working version of the app for Jira 10. This is cool.
A few caveats though:
- This approach isn’t backwards compatible, the pom file has changed A LOT. This will not work with Jira 8 or Jira 9. You’d at least need an earlier version of Atlassian platform. Again — if anyone else has found a way to make this work without a bunch of dynamic bridges, I’d like to hear about it. Reach out.
- This means my Jira 10 version is on a branch, and I’ll need to merge features & bug-fixes over. Which is not ideal, but we’ll see how it goes.
- This app is heavy on REST api resources, some background tasks and mail/slack integration. This all seems to work at the mo, but we’ll need to test a bit further. As any good product engineer would….
If you’ve made it this far, thanks for reading. Hopefully this helps someone out there! Toodles.
