Confluence 8.8 release EAP available now

When trying to install my app to Confluence 9 eap, I am getting this error

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'htmlAnalyticsListener': Unsatisfied dependency expressed through constructor parameter 6; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.atlassian.confluence.xhtml.api.XhtmlContent' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:801)

Is there any change w.r.t com.atlassian.confluence.xhtml.api.XhtmlContent ? I did not find this in the list here.

1 Like

It’s only changing from Guava to Java, not being replaced entirely, specifically this will be using the Java Supplier variant.

If a plugin still uses Guava that’s okay, they’re compatible. Just be aware that if using lambda notation and compiling against a version of the interface that’s still using Guava then the Guava dependency needs to come from somewhere (either compile scope or OSGi package import) as the Java compiler will compile it using the Guava interface.

The deprecation notices where they make sense to have should be complete. What is probably better though is the upgrade guide

Thanks for flagging it again, this is a mistake IMO. I also raised this for the same reason, let me do it again internally.

This is also a blocker for ScriptRunner, the app UI is dependent on a WRM data provider which currently will not work on this EAP.

I could go make the experience worse by moving that over to REST, but I’m guessing this isn’t an intentional breakage and is an oversight.

@mkemp the package move for WRM will definitely break parts of our app.

It’s not clear to me, is this work done and shipped in the current Confluence 9 EAP? If it is upcoming, do we know when it will be included?

Hi @mkemp,

I really appreciate the clarification, as well as re-flagging the issue to the Confluence team–thanks so much!

You mention that if the plugin still uses Guava, then that’s okay. I assume you mean that’s because the Guava Supplier class extends java.util.function.Supplier, which is what the new <data> interface expects.

If that is the case, this will work fine in Confluence 9.0+, but I don’t see how to make the same code work in 8.0, with or without bundling Guava. Won’t the earlier version of the WRM expect my class to extend the Guava Supplier signature that’s compiled directly into the system bundle?

I agree with @rlander in that my currently cross-major-compatible app will have to be pried out of my cold, dead hands…resulting in this ask:

Since Atlassian is changing the signature of the interface required to implement the <data>, could Atlassian pretty please also consider changing the name of the element so that we can try to manage this?

For example:

<web-resource ...>
   <data class="class.based.on.old.guava.dependency" />
   <data2 class="class.based.on.new.javax.Supplier" />
</web-resource>

Old versions of the product will read <data> and ignore <data2>, new versions will do the opposite, and everyone is happy without classloader conflicts. This would also be really nice to do for any other module type whose signature is being changed in any way.

3 Likes

I’m wondering if we can use pocketknife dynamic modules Bitbucket

And then register different module definitions with different implementation classes at runtime

@rlander You can and I do—although current version doesn’t build/install (Guava deps) and I had to patch. But this is a big ask for all vendors to implement when there is a simpler way. And I really don’t want to have to consider dynamically messing with wrm-webpack-plugin web-resource outputs (can’t those also have data providers? I forget) because the build chain is already complicated enough.

Are there any recommendations on how to replace @PostConstruct and @PreDestroy in EventListeners/Services

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

Java seems to be deprecated with Java 9 => Java 11 build complains now…

We’re also seeing issues similar to this where unit tests fail due to not being able to mock classes we previously could.
Not sure if it’s the same but seems similar enough - could you share some details on how you approached this @clouless ?

Update
Added the c.a.util.concurrent lib as test scope and got passed that error. Now seeing the same com.atlassian.fugue.Maybe errors as mentioned earlier.

Hi @scott.dudley - com.atlassian.json.marshal package has been erroneously removed and will be restored in Confluence 8.8 and 9.0

3 Likes

Hi Dennis,

I am pretty sure the Confluence libs pull in the old com.atlassian.whatever packages instead of the io.atlassian.whatever.
For the Maybe thing and some other things I build myself my own compat lib with the class signature of the missing files but only with “return null” function bodies (since no implementation is needed).

Here is the jar file (you could install it into your maven repo):

https://clouless.github.io/atlassian-community-share/2024-confluence8/confluence-8-8-compat-1.0.0.zip

        <dependency>
            <groupId>io.codeclou</groupId>
            <artifactId>confluence-8-8-compat</artifactId>
            <version>1.0.0</version>
            <scope>test</scope>
        </dependency>

I managed to strip it down to these classed needed:

src/main/java/com/atlassian/util/concurrent/Timeout.java
src/main/java/com/atlassian/util/concurrent/Awaitable.java
src/main/java/com/atlassian/util/concurrent/TimedOutException.java
src/main/java/com/atlassian/fugue/Effect.java
src/main/java/com/atlassian/fugue/Maybe.java
src/main/java/com/atlassian/fugue/Option.java
src/main/java/com/atlassian/fugue/Either.java

In general there were some version problems with power mock and mockito.
I am currently building with Termium JDK 11 against Confluence 8.5.0 (and for test purposes against 8.8.0-beta1) with Atlassian SDK 8.2.8

        <confluence.version>8.5.0</confluence.version>
        <confluence.data.version>8.5.0</confluence.data.version>
        <amps.version>8.10.1</amps.version>
        <plugin.testrunner.version>2.0.1</plugin.testrunner.version>
        <atlassian.spring.scanner.version>2.1.10</atlassian.spring.scanner.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>

I managed to get everything working by using these additional dependencies with scope=test:

        <dependency>
            <!-- somehow fugue and concurrent stuff is missing to mock MacroDefinition -->
            <groupId>io.codeclou</groupId>
            <artifactId>confluence-8-8-compat</artifactId>
            <version>1.0.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <!-- Needed to mock com.atlassian.confluence.api.service.content.ContentService -->
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.12.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <!-- Needed to make Velocity work in unit tests since Confluence 8.8 -->
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <!-- Neded to mock MacroUtils -->
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

and for mockito

        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.6.28</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.hamcrest</groupId>
                    <artifactId>hamcrest-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy</artifactId>
            <version>1.14.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.bytebuddy</groupId>
            <artifactId>byte-buddy-agent</artifactId>
            <version>1.14.5</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-module-junit4</artifactId>
            <version>2.0.9</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.powermock</groupId>
            <artifactId>powermock-api-mockito2</artifactId>
            <version>2.0.9</version>
            <scope>test</scope>
        </dependency>

that was all up until now. I will head to build against Confluence 9 soon and are awaiting similar things :cry:

And what was really annoying that IntelliJ was out of sync all the time. Some “atlas-clean” and restarts of IntelliJ helped a lot :slight_smile:

4 Likes

I’m sorry, I do know it will, but I don’t know when exactly because it’s really a question for the Confluence team. I’ll pass on the feedback that you’d like to see it sooner rather than later and ask them to respond with something more concrete if they can.

The ideal solution I see if you’re trying to make it cross-major-compatible is to optionally package import Guava (so it uses the same classloader as the system in Confluence v8) and compile scope Guava (so in v9 it has a copy). You’d want to match the version of Guava to watch Confluence uses in v8 (off the top of my head 26) probably so you don’t accidentally use newer features. You’d also want to avoid exporting the bundled version of Guava.

The web-resource declaration and the code doesn’t need to change.

The version of the WRM API being compiled against would need to be v5.6.5 (WRM version not Confluence version) because you’d need to compile for language level 8 to have compatibility all the way back to Confluence 7.19 LTS. Targeting Confluence 8.5 LTS would be WRM v6.1.0 and Java 11.

You can try, it’s a bit of work and you still need to optionally import Guava for Confluence v8.

Yes, WRM Webpack plugin almost has feature parity with manual declarations. FWIW you could put the output of it into a folder that isn’t scanned by the plugin system and then dynamically register everything if you really wanted to.

Personally, I tend to avoid dynamic module registration because it has some trade-offs, I think the big ones from the top of my head are:

  • Delayed plugin and application start-up, a lot of caches will be immediately emptied again once the plugin state changes
  • It’s harder for new-engineers and static analysis to pick up what’s happening
  • Greater opportunity for runtime (maybe a better term is post-plugin-startup) errors with something accidentally not being registered - potentially missed in testing and encountered long after the plugin started
1 Like

@turehoefner_appfire and @rr1

I confirmed org.osgi.framework is in the public API of Confluence 9 with the team, if there’s any error it should be resolved in the next EAP release if it hasn’t been already.

Can I please confirm for both of you exactly which versions of Confluence you were talking about? Just compiling? Just at runtime in the product? Some combination?

Thanks @mkemp

My org.osgi.framework dependency came up when I compiled/built against Confluence 8.7.1.

It is used for Spring Java Configuration, in a config class, to export a service like this, where org.osgi.framework.ServiceRegistration is the return type:

@Bean
  public FactoryBean<ServiceRegistration> exportDiscoverableListener(final DiscoverableListener...

I haven’t yet gotten to my compat work for Confluence 8.8 and 9… but I will soon… I’m almost done with a first pass through all of my plugins to get them building against 8.7.1.

Thanks!

I’m running into all the same problems running unit tests. Unable to mock things like MacroDefinition and ConversionContext without some sort of struggle.

I like your idea (@clouless ) of a confluence-test-compat library that could be used only with scope=test to allow unit tests to mock some key Confluence classes. imo, it would be nice if Atlassian could provide something like that.

I think this is a case where “dog fooding” would have helped. If Atlassian were strictly using their own 3rd party macro frameworks for their own Confluence apps then they’d have a large suite of unit tests that broke when upgrading Confluence and they’d have a confluence-test-compat library intended to support mocking commonly used Confluence classes in unit tests.

It might be too late now, Atlassian wouldn’t know which classes are commonly being mocked in unit tests for plugins and how to resolve those with no-op impls for test scope. I don’t think the problem/solution is solvable by analysis. You need to run a diverse set of unit tests to find the problems.

What I am doing is deleting my unit tests that are breaking. I’m in emergency mode right now. I don’t have time to build a confluence-test-compat library and I don’t think it would be reasonable to expect that hundreds of partners are going to have time to do it… therefore, I think that I won’t be the only one deleting unit tests.

5 Likes

@mkemp @scott.dudley

Another approach for the changed signature in the data provider of web modules could be something like this:

<web-resource ...>
    <restrict application="confluence" version="(,9.0.0)" />
    <data class="class.based.on.old.guava.dependency" />
</web-resource>

<web-resource ...>
    <restrict application="confluence" version="[9.0.0,)" />
    <data class="class.based.on.new.javax.Supplier" />
</web-resource>

This way you’d make sure the proper module / data provider is used on each Confluence version. Of course you’d need an optional OSGi import for the guava package for Confluence versions < 9 AND remove any other uses of guava from your code base so you don’t have to bundle it for 9.0.0+

I don’t know if both modules may have the same key - which might be relevant if you manually require it in macros / action templates etc. instead of placing the module in a <context>.

3 Likes

Here’s another subtle 8.8 landmine in which even cross-minor compatibility is broken. If you use PermissionManager for anything, the very act of upgrading your POM to compile against 8.8.0 will potentially break your app on older versions of Confluence. Everything will seem fine when you build, but it will fail at runtime.

In 8.7 and prior, PermissionManager used the User type for almost everything. In 8.8, these methods were marked as @Deprecated for removal. A new set of parallel methods were added in 8.8 that use ConfluenceUser, but these methods do not exist in 8.7 and below.

If you were being good citizens and already using the ConfluenceUser class in your own code, then the following will no longer work at runtime on <=8.7 if you build against 8.8:

ConfluenceUser user = /* ... */;

if (permissionManager.hasPermission(user, Permission.WHATEVER, content)) { 
   /* ... */

That’s because your classes will now be built against the method signature hasPermission(ConfluenceUser, Permission, Object), which does not exist in <=8.7.

You can typecast this to (User) to get it to work cross-version for now, at the cost of getting deprecation warnings, but who knows if this will still work in 9.0 or if we’ll all have to implement some reflection.

Hey, Atlassian (@kmacleod ?), any chance of retaining the User-signature methods here in 9.x? Deprecating starting only in 8.8 and removing in 9.0 is…fast…and it doesn’t seem like there is any particular impact to security here.

7 Likes

Saved us again @scott.dudley !

I use PermissionManager in almost all of the plugins that I maintain and I have quite a pile of them. Perm checks are so fundamental.

Atlassian, can you please consider backwards-compat on these PermssionManager APIs to be a high priority requirement?

8.8 went live yesterday and I have a migraine right now. I’m writing this in case I stroke out… my wife can find me dead at the keyboard and know it wasn’t suicide… it was backward-incompatibility.

Thanks!

Hi @metin I’m sorry I missed your message (I was on leave and am still working through a large pile of stuff). Do you mean what is the point of announcing Betas AND EAPs? We like to keep everyone up to date when we do our releases.

Regarding the LDAP info, see the yellow info box on this page:
https://confluence.atlassian.com/doc/backup-and-restore-163578.html

Finally, the developer changelog can be found here:

You can use the dropdowns at the top to refine the feed.

I am getting the following error when saving the configuration page and few values are not showing up in the view mode after the save, any help is much appreciated.

2024-02-16 14:57:23,109 WARN [http-nio-8090-exec-9 url: /conf880/admin/plugins/latexmath/viewconfig.action; user: automation] [opensymphony.xwork2.ognl.SecurityMemberAccess] checkAllowlist Declaring class [class java.util.LinkedHashMap] of member type [public java.lang.Object java.util.LinkedHashMap.get(java.lang.Object)] is not allowlisted!

Anything I need to change here?

@ParameterSafe
    public Map<String,String> getRenderers() {
        Map<String,String> map = new LinkedHashMap<String,String>();

        map.put(Renderers.internalPng.toString(), "Built-in renderer (MathJax-based)");
        map.put(Renderers.externalPng.toString(), "External renderer (latex+dvipng)");

        return map;
    }