In Confluence 8.9, a plugin which needs to use the "blueprints" fails

When a plugin contains blueprints (confluence-create-content-plugin), it fails to load when using the REST API v2.

  • Documentation for this API,
  • The dependency to add in the pom.xml is confluence-create-content-plugin (version 18.9.27),
  • Symptom: When starting with C9.0.0, it refuses to start because we use the package javax.ws.rs.core, which is (errorneously?) exposed by both Confluence and the confluence-create-content-plugin. The error message is below.
  • I have tried Sujay’s solution on C8.9, but it didn’t work at the time, so I reverted to using REST API v1, which worked until C9.0-beta1, and the REST API v1 doesn’t work in C9.0-beta2.
  • Basically, the problem is that confluence-create-content-plugin shouldn’t expose the package javax.ws.rs.core, and/or Atlassian should be configured so that the one exposed by that plugin should be restricted to Atlassian’s plugins, and the only javax.ws.rs.core should be exposed by Atlassian’s REST API plugin.
Caused by: org.osgi.framework.BundleException: Uses constraint violation. Unable to resolve resource com.playsql.requirementyogi [com.playsql.requirementyogi [301](R 301.0)] because it is exposed to package 'javax.ws.rs.core' from resources com.atlassian.plugins.rest.atlassian-rest-v2-plugin [com.atlassian.plugins.rest.atlassian-rest-v2-plugin [172](R 172.0)] and org.apache.felix.framework [org.apache.felix.framework [0](R 0)] via two dependency chains.

Chain 1:
  com.playsql.requirementyogi [com.playsql.requirementyogi [301](R 301.0)]
    import: (&(osgi.wiring.package=javax.ws.rs.core)(version>=0.0.0))
     |
    export: osgi.wiring.package: javax.ws.rs.core
  com.atlassian.plugins.rest.atlassian-rest-v2-plugin [com.atlassian.plugins.rest.atlassian-rest-v2-plugin [172](R 172.0)]

Chain 2:
  com.playsql.requirementyogi [com.playsql.requirementyogi [301](R 301.0)]
    import: (&(osgi.wiring.package=com.atlassian.confluence.plugins.createcontent)(version>=0.0.0))
     |
    export: osgi.wiring.package=com.atlassian.confluence.plugins.createcontent; uses:=com.atlassian.plugins.rest.common.security
  com.atlassian.confluence.plugins.confluence-create-content-plugin [com.atlassian.confluence.plugins.confluence-create-content-plugin [35](R 35.0)]
    import: (osgi.wiring.package=com.atlassian.plugins.rest.common.security)
     |
    export: osgi.wiring.package=com.atlassian.plugins.rest.common.security; uses:=javax.ws.rs.core
  com.atlassian.plugins.rest.atlassian-rest-module [com.atlassian.plugins.rest.atlassian-rest-module [171](R 171.0)]
    import: (&(osgi.wiring.package=javax.ws.rs.core)(version>=1.1.1))
     |
    export: osgi.wiring.package: javax.ws.rs.core
  org.apache.felix.framework [org.apache.felix.framework [0](R 0)] Unresolved requirements: [[com.playsql.requirementyogi [301](R 301.0)] osgi.wiring.package; (&(osgi.wiring.package=com.atlassian.confluence.plugins.createcontent)(version>=0.0.0))]
	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:404)
	... 106 more

We need javax.ws.rs.core because it exposes javax.ws.rs.core.MediaType and javax.ws.rs.core.Response, which are necessary when building answers of REST calls. We also need the following packages, because ContentBlueprintManager#getPluginBackedContentBlueprint() returns a class that is in an impl package. Here is our current Import-Package in MANIFEST.MF:

 com.atlassian.confluence.plugins.createcontent.actions;version="0.0.0",
 com.atlassian.confluence.plugins.createcontent.api.contextproviders;version="0.0.0",
 com.atlassian.confluence.plugins.createcontent.api.events;version="0.0.0",
 com.atlassian.confluence.plugins.createcontent.impl;version="0.0.0",
 com.atlassian.confluence.plugins.createcontent.services.model;version="0.0.0",
 com.atlassian.confluence.plugins.createcontent;version="0.0.0",
 javax.ws.rs.core;version="0.0.0",
 javax.ws.rs;version="0.0.0",

I’ll post my solution, just in case:

  • There was a mistake in the title, it only failed in C8.9 but not C9.0,
  • I was using <rest-migration>, which is not required. If not used, then Confluence 7.19-8.9 will use the old REST v1, and Confluence 9.0 will use the new one, and the createcontent plugin doesn’t fail,

Now, I have:

  • A REST API which is only activated for Confluence 9.0, which contains the REST v2 imports,
  • A REST API which is only activated for Confluence 7.19-to-8.9, which contains the REST v1 imports,
  • A common REST API, which contains other resources which are not sensitive to package names,
  • I’ve created a separate module for each, so that only the correct libraries are included by Maven, and it’s much easier to write code with autocompletion :wink: See this post about polyfills if necessary.
    <rest key="rest" path="/my-rest-prefix/common" version="1" name="REST resources">
        <description>REST API for Requirement Yogi</description>
        <package>com.requirementyogi.datacenter.confluenceapp.rest</package>
    </rest>

    <!-- Remove when Confluence 9.0 is the new minimum -->
    <rest key="rest-c719" path="/my-rest-prefix/compat" version="1" name="REST resources for C7 and C8">
        <description>REST APIs for Confluence 7.19 and above</description>
        <package>com.requirementyogi.datacenter.polyfills.confluence.c719.rest</package>
        <restrict application="confluence" version="(,9)" />
    </rest>
    <rest key="rest-c900" path="/my-rest-prefix/compat" version="1" name="REST resources for C9.0+">
        <description>REST APIs for Confluence 9.0 and above</description>
        <package>com.requirementyogi.datacenter.polyfills.confluence.c900.rest</package>
        <restrict application="confluence" version="(8.9999,)" />
    </rest>

Note the use of <restrict> which is incredibly useful for other situations too.

1 Like