Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scala 2.13: Fix weaker access privileges compile error #25191

Conversation

rtyley
Copy link
Member

@rtyley rtyley commented Jul 5, 2022

Compiling Frontend under Scala 2.13, we see two identical compilation errors against the RssAtomModule & GModule traits, which both extend the com.sun.syndication.feed.module.Module interface from ROME (used for processing RSS). The error is this:

weaker access privileges in overriding def clone(): Object (defined in trait Module) override should be public;
(note that def clone(): Object (defined in trait Module) is abstract, and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object))

com.sun.syndication.feed.module.Module is a Java interface that specifies clone() should be public:

public Object clone() throws CloneNotSupportedException;

...but it's just an interface, not a class - and so the java.lang.Object.clone() method, which is assigned protected as an access modifier, is more protected than the Module interface dictates - but it's the only clone() method available on our trait, whether that's RssAtomModule or GModule.

This is a horrible little problem and various people have encountered it over the years:

How to fix?

There is a fairly good suggestion at https://stackoverflow.com/a/8619704/438886 - just define a concrete clone() method in the trait, with a guard implementation that throws a CloneNotSupportedException - your concrete subclasses can override the method with whatever implementation they like. It's a bit of a hack, but it works.

However, looking at the code of these two traits and their solitary implementations:

  • RssAtomModule with its implementation RssAtomModuleImpl
  • GModule with GModuleImpl

...there's no reason to separate the functionality here into a separate trait and class. It's not being used to facilitate testing, and each trait has only a single implementation. Sometimes a trait can be a nice way to decide exactly what limited public API you want people to think about when they use your code, but I don't think that's the case here. Totally fine to just unite each trait & class into a simple class, reducing unnecessary boilerplate, and removing the need to have a dummy public clone method!

The compilation errors in full:

[error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:16:7: weaker access privileges in overriding
[error] def clone(): Object (defined in trait Module)
[error]   override should be public;
[error]   (note that def clone(): Object (defined in trait Module) is abstract,
[error]   and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object))
[error] trait RssAtomModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable {
[error]       ^
[error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:52:7: weaker access privileges in overriding
[error] def clone(): Object (defined in trait Module)
[error]   override should be public;
[error]   (note that def clone(): Object (defined in trait Module) is abstract,
[error]   and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object))
[error] trait GModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable {
[error]       ^

@rtyley rtyley marked this pull request as ready for review July 5, 2022 20:23
@rtyley rtyley requested a review from a team as a code owner July 5, 2022 20:23
@rtyley rtyley changed the title Scala 2.13: Fix weaker access privileges error Scala 2.13: Fix weaker access privileges compile error Jul 5, 2022
Copy link
Contributor

@ioannakok ioannakok left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! 👏

Compiling under Scala 2.13, we see two identical compilation
errors for traits `RssAtomModule` & `GModule`, which both
extend the `com.sun.syndication.feed.module.Module` interface from
ROME (used for processing RSS). The message is of the form:

> weaker access privileges in overriding def clone(): Object (defined in trait Module)
> override should be public;
> (note that def clone(): Object (defined in trait Module) is abstract, and is therefore
> overridden by concrete protected[package lang] def clone(): Object (defined in class Object))

`com.sun.syndication.feed.module.Module` is a Java interface that specifies
`clone()` should be *public*:

```
public Object clone() throws CloneNotSupportedException;
```

...but it's just an interface, not a class - and so the `java.lang.Object.clone()` method,
which is assigned `protected` as an access modifier, is more protected than the interface
dictates - but it's the only `clone()` method available on our _trait_, whether that's
`RssAtomModule` or `GModule`.

This is a horrible little problem and various people have encountered it over the years:

* scala/bug#3946
* https://bugs.openjdk.org/browse/JDK-6946211

How to fix?
-----------

There is a fairly good suggestion at https://stackoverflow.com/a/8619704/438886 - just
define a concrete `clone()` method in the trait, with a guard implmentation that just
throws `CloneNotSupportedException` - your concrete subclasses can override the method
with whatever implementation they like. It's a bit of a hack, but it works.

However, looking at the code of these two traits and their solitary implementations:

* `RssAtomModule` with its implementation `RssAtomModuleImpl`
* `GModule` with `GModuleImpl`

...there's no reason to separate the functionality here into a separate trait and class.
It's not being used to facilitate testing, and each trait has only a single implementation.
Sometimes a trait can be a nice way to decide exactly what limited public API you want
people to think about when they use your code, but I don't think that's the case here.
Totally fine to just unite each trait & class into a simple class, reducing unnecessary
boilerplate, and removing the need to have a dummy `public` clone method!

The compilation errors in full:

```
[error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:16:7: weaker access privileges in overriding
[error] def clone(): Object (defined in trait Module)
[error]   override should be public;
[error]   (note that def clone(): Object (defined in trait Module) is abstract,
[error]   and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object))
[error] trait RssAtomModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable {
[error]       ^
[error] /Users/roberto/guardian/frontend/common/app/common/ShowcaseRSSModules.scala:52:7: weaker access privileges in overriding
[error] def clone(): Object (defined in trait Module)
[error]   override should be public;
[error]   (note that def clone(): Object (defined in trait Module) is abstract,
[error]   and is therefore overridden by concrete protected[package lang] def clone(): Object (defined in class Object))
[error] trait GModule extends com.sun.syndication.feed.module.Module with Serializable with Cloneable {
[error]       ^
```
@rtyley rtyley force-pushed the fix-weaker-access-privileges-in-overriding-clone-compilation-issue-in-scala-2.13 branch from 83bda45 to 1e1863e Compare July 6, 2022 16:01
Copy link
Member

@AshCorr AshCorr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome write up, and a great fix!

@rtyley rtyley merged commit b39ac3d into main Jul 6, 2022
@rtyley rtyley deleted the fix-weaker-access-privileges-in-overriding-clone-compilation-issue-in-scala-2.13 branch July 6, 2022 16:20
@rtyley
Copy link
Member Author

rtyley commented Jul 6, 2022

Thanks!

@prout-bot
Copy link
Collaborator

Seen on PROD (merged by @rtyley 9 hours, 4 minutes and 35 seconds ago)

@rtyley rtyley mentioned this pull request Jul 27, 2022
2 tasks
@rtyley rtyley added the Scala 2.13 See https://github.com/guardian/maintaining-scala-projects/issues/2 label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Scala 2.13 See https://github.com/guardian/maintaining-scala-projects/issues/2 Seen-on-PROD
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants