There have been many versions of Guava that have been released with some
methods that have been removed/modified and many methods that were marked
@Beta. Guava maintainers said from release 23? that they would no longer
make backwards incompatible changes to non beta APIs and released a tool to
help users ensure they aren't using beta APIs [1]. This tool is great but
there are already 1000s of released artifacts that were produced before the
API lockdown and that beta checker was added.

There are a lot of libraries that are still on Guava 19 or older and users
still run into linkage errors[2]. Users regularly run a linkage checker to
help them diagnose diamond dependency issues to get a set of libraries that
work with Beam and their dependencies. For example, the Beam community saw
this issue[3] when Guava decided to overload popular Preconditions[4]
methods which lead to NoSuchMethodErrors. A google search for guava and
NoSuchMethodError/ClassNotFoundException shows many users who have hit
issues with Guava.

Google has worked on helping users via a linkage checking tool[5] and
Beam[6] would like to be in a better place with dependencies by using BOMs
for dependency management but both of these efforts are still relatively
new.

On Thu, Jun 25, 2020 at 9:28 AM Daniel Collins <[email protected]> wrote:

> Hello all,
>
> In https://github.com/apache/beam/pull/11919, there is a concern about
> the fact that the underlying client library's Message class uses guava's
> ListMultimap to represent a String -> Collection<ByteString> mapping, and
> this type is exposed by the interface. A couple of questions:
>
> 1) I'd like to use the same primitive value types as the underlying client
> library for consistency. Given that both the client library and beam io
> have the same maintainers, is this likely to cause long term issues? I'd
> really like to avoid wrapping the client library types in an
> almost-identical-but-not-quite wrapper just to remove guava, and I don't
> think removing guava from the underlying type is reasonable.
>

For designing methods within Beam, it is preferable that you don't make
guava or the underlying client library part of the API surface. If there
are simple substitutes for types that is great but for configuration
objects such as protos it is a judgement call. Most IOs don't use the
underlying configuration object but instead choose to expose certain
properties on a case by case basis since properties may not make sense to
expose.

For return types within the third party lib, casting the type to the
closest type within Java and only using methods that are part of Java core
will reduce the risk that you will invoke a method that has been
changed/removed. For example
ImmutableList<String> getFoos();  // method on object you want to interact
with
ImmutableList<String> foo = getFoos(); // bad, you can invoke a method that
has been removed/modified.
List<String> foo = getFoos();  // good, doesn't depend on Guava exposed APIs

For method arguments in the third party library you don't really have much
of a choice since you will have to call an API to construct the object and
you'll need to validate that you are not using @Beta apis. You can only try
to minimize the API surface you interact with.


> 2) What is the blast radius of guava incompatibility issues? There is a
> presubmit that blocks beam from using unshaded guava, presumably because it
> has caused issues in the past. If I expose this type, and someone tries to
> use it with an incompatible guava version, will they fail if they try to
> use beam or try to use this IO specifically?
>

There are two issues:
1) Users need to solve the diamond dependency problem and provide a version
of Guava that works with Beam and their dependencies. Guava usage within
Beam and its transitive dependency tree makes that more difficult for users
since some users rely on the linkage checker to help figure out a
compatible set of dependencies. This means that the linkage checker will
find faults that may have not existed otherwise.
2) If the user selects a non-compatible version of guava, then it depends:
* any static links between classes will poison all referenced classes if
one of them does something that causes a linkage error (e.g. static block
that calls a method that can't be found or a class that doesn't exist)
* if the code is loaded dynamically via service loaders/reflection, then
the entire application can fail as soon as the object is on the classpath


>
> Thanks! Looking forward to some feedback.
>

In the end, it is a judgement call vs maintenance, ease of use for users,
and user support.

1: https://github.com/google/guava-beta-checker
2: https://jlbp.dev/glossary.html#linkage-error <https://jlbp.dev/glossary>
3: https://issues.apache.org/jira/browse/BEAM-1411
4:
https://github.com/google/guava/commit/892e323fca32945cdfb25395ca6e346dd0fffa5b#diff-fe7358934fa6eba23c2791eb40cec030
5:
https://github.com/GoogleCloudPlatform/cloud-opensource-java/wiki/Linkage-Checker-Enforcer-Rule
6: https://issues.apache.org/jira/browse/BEAM-9444

Reply via email to