Migrate from Guava in UPM 6.0

In anticipation of the upcoming major release of Universal Plugin Manager, we have some important update for apps developers.

Motivation

To limit the possibility of emergence security vulnerabilities Universal Plugin Manager will stop using Guava library since version 6.0. The majority of current usage of Guava library can be easily replaced with Java 8 features.

Impact on other apps

Some methods from com.atlassian.upm.api* and com.atlassian.upm.spi* packages return Guava types and it will be critical for clients of this methods to update their usage. The update will require using new overloaded methods or features from Java 8.

Release plans

UPM 5.0 is planned to be released before end of July 2021, while UPM 6.0 is planned to be released in 2022.

Methods affected

com.atlassian.upm.api.util.Either#fold(com.google.common.base.Function<L,Z>, com.google.common.base.Function<R,Z>)
com.atlassian.upm.api.util.Option#fold(com.google.common.base.Supplier<B>, com.google.common.base.Function<A,B>)
com.atlassian.upm.api.util.Option#getOrElse(com.google.common.base.Supplier<A>)
com.atlassian.upm.api.util.Option#orElse(com.google.common.base.Supplier<com.atlassian.upm.api.util.Option<A>>)
com.atlassian.upm.api.util.Option#filter(com.google.common.base.Predicate<A>)
com.atlassian.upm.api.util.Option#exists(com.google.common.base.Predicate<A>)
com.atlassian.upm.api.util.Option#flatMap(com.google.common.base.Function<A,com.atlassian.upm.api.util.Option<B>>)
com.atlassian.upm.api.util.Option#map(com.google.common.base.Function<A,B>)
com.atlassian.upm.api.util.Option#noneSupplier()
com.atlassian.upm.api.util.Option#option()
com.atlassian.upm.api.util.Options
com.atlassian.upm.api.util.Options#catOptions()
com.atlassian.upm.api.util.Options#isDefined()
com.atlassian.upm.api.util.Options#asNone()
com.atlassian.upm.api.util.Options#asSome()
com.atlassian.upm.api.util.Pair#fromMapEntry()
com.atlassian.upm.api.util.Pair#toFirst()
com.atlassian.upm.api.util.Pair#toSecond()

Risk Mitigation

We are aware of the inconveniences for external vendors and we try to introduce changes as gently as possible. Therefore UPM 5.0 will be backward compatible to give API clients more time to adapt. Incompatible changes will be delivered with next major version and it will not be done before next year.
6 Likes

Thank you for the heads-up!

Would it be possible to let us know exactly which methods that will be affected?

Thank you.

4 Likes

I suppose this will also affect the most important API: com.atlassian.upm.api.license.PluginLicenseManager#getLicense and PluginLicense itself - because it has a lot of methods using the custom Option class, which in turn uses guava.

Would be great if you could provide some examples for common use cases when interacting with the license API.

Thanks (also for the heads-up)!

3 Likes

@MagdalenaWieclawska thanks for the heads up. However, when you start implementing these changes, can you make sure you provide backward compatibility with UPM < 6, so that apps can transparently support all versions of UPM (even if it means calling different methods based on the version of UPM, assuming of course we can easily determine which version of UPM is running)?

3 Likes

I’ve updated the announcement with methods affected.

Since UPM 5.0 Option class will be based on plain Java 8 features and it shouldn’t affected it’s usage.

1 Like

Supporting backward compatibility would prevent UPM from getting rid of the guava dependency therefore we don’t plan to provide backward compatibility.

@MagdalenaWieclawska unless I’m missing something, you have no choice but to support backward compatibility. How otherwise are vendors supposed to build an app that might run on UPM v5 or v6, since customers will have a mix of older and newer versions of UPM? And it’s not even based on the version of Jira, since you can upgrade the UPM in older versions of Jira…

Whatever change you make to UPM, make sure you “eat you own dog food” and build an app on top of it and validate it across a variety of Jira and UPM versions. Otherwise, you’ll end up creating a disaster.

6 Likes

I’d like to echo @david2’s point here. A backwards compatible change is essential here. Even if you prevent older versions applications from installing the newer UPM it will mean that we will have to ship separate binaries or use complex workarounds. Please consider customers and the consumers of the API when looking at this change.

3 Likes

@david2 @jmort I added another section to the main topic:

Blockquote
We are aware of the inconveniences for external vendors and we try to introduce changes as gently as possible. Therefore UPM 5.0 will be backward compatible to give API clients more time to adapt. Incompatible changes will be delivered with next major version and it will not be done before next year.

Alongside UPM major releases products versions will be bumped, UPM compatibility will be set accordingly

2 Likes

Thanks @MagdalenaWieclawska will the major UPM releases correspond with major product releases?

1 Like

@MagdalenaWieclawska Hi, I am using only this part of the HostLicenseInformation of the maven dependency

package com.atlassian.upm.datacentercompatibility;

import com.atlassian.upm.api.util.Option;

public interface HostLicenseInformation {
    Option<String> hostSen();

    boolean isDataCenter();

    Option<Integer> getEdition();

    boolean isEvaluation();
}

My code:

if (hostLicenseInformation.getEdition().isDefined()) {
  // do stuff

What exactly is now changing? Can i no longer use getEdition().isDefined()?

I am using this dependency

        <dependency>
            <groupId>com.atlassian.upm</groupId>
            <artifactId>data-center-licensing-compatibility</artifactId>
            <version>1.0</version>
            <scope>compile</scope>
        </dependency>

I am very confused about what is changing and why you will not keep the method signature of the classes. To me com.atlassian.upm.api.util.Option seems not to be from Guava but an Atlassian class. Even if it uses Guava internally why do you not keep the full Option method signature and simply replace Guava internally but keep all the exists(), orElse() a.s.o Methods?

Can you please explain to me what exactly is chaning with the Option.exists and what actions I have to take, thanks.

And also can you explain what “major UPM version” means in terms of Jira versions? I am building my app against a range of certain Jira versions currently Jira 8.8 up to 8.18 (there was already a breaking change in the Audit API that meant to loose compatibility to version smaller than 8.8).
What does this UPM change now mean to my version range?

Or is this even more complex and someone could have a Jira 8.13 with UPM App Jar smaller version 6 and once he klicks the button “update UPM” my app blows up and can no longer determine the plugin license because UPM is now version 6+?
What exactly happens in these scenarios?

Please explain this to me, since I am very confused about these breaking change and its side effects.

Cheers,
Bernhard

Hi @clouless – Based on the post above, it appears that UPM is deprecating only Options#isDefined, not Option#isDefined (with the latter being what your code snippet uses).

The Options#isDefined method returns a Guava class, whereas the Option class returns a boolean. Atlassian did not cite any changes to the latter method so it presumably remains safe to call.

thanks scott :slight_smile:
I would still be interested in a detailed side effect description of Atlassian if I would use one of those now breaking methods :slight_smile: