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

Ensure all adapters and decorators can be extended #806

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

victornoel
Copy link
Contributor

I got bitten by #647 again so decided to make a PR directly :)

The constructors could have been made public but the EC way seems to be using the of() static method for this usage, so I left it at that.

@victornoel victornoel force-pushed the 647-adapter-and-decorators-non-final branch from aba4998 to 8edb4d8 Compare March 1, 2020 11:39
Closes eclipse#647

Signed-off-by: Victor Noël <victor.noel@brennus-analytics.com>
@victornoel victornoel force-pushed the 647-adapter-and-decorators-non-final branch from 8edb4d8 to e41bf15 Compare March 1, 2020 15:21
@motlin
Copy link
Contributor

motlin commented Mar 1, 2020

I believe this is technically a security vulnerability, but I'm also kind of open to it. A malicious user could deserialize some custom bytes into a subclass of an unmodifiable wrapper that's not actually unmodifiable. On the other hand, I haven't used serialization in years and if you're security conscious, you probably forbid deserialization. It's something to think about though. We prevented subclassing on purpose at the time. The JDK wrappers do the same thing.

@motlin
Copy link
Contributor

motlin commented Mar 1, 2020

I'm looking around in Guava, and they don't even have concrete classes. Unmodifiable wrappers are all abstract.

I don't fully understand why the concrete classes must have hidden visibility, but I think it's important.

@@ -44,7 +44,7 @@
* {@link #wrapList(Iterable)} factory method. To wrap a collection with the MutableCollection interface alone, use
* the {@link #adapt(Collection)} factory method.
*/
public final class CollectionAdapter<T>
public class CollectionAdapter<T>
extends AbstractCollectionAdapter<T>
Copy link
Contributor

Choose a reason for hiding this comment

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

Note how CollectionAdapter extends AbstractCollectionAdapter. This is the pattern I think we should copy. The superclass is public api.

@@ -64,7 +64,7 @@
extends AbstractUnmodifiableMutableCollection<T>
implements MutableBag<T>, Serializable
{
UnmodifiableBag(MutableBag<? extends T> mutableBag)
protected UnmodifiableBag(MutableBag<? extends T> mutableBag)
Copy link
Contributor

Choose a reason for hiding this comment

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

Note how UnmodifiableBag extends AbstractUnmodifiableMutableCollection. I think the right thing to do here is extract a new superclass AbstractUnmodifiableBag, which becomes part of our public api. I think we should leave the sublcass alone.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what would be left in the UnmodifiableBag class at then end? nothing except being final for security purpose?

Copy link
Contributor

Choose a reason for hiding this comment

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

That's right. I'm not even sure I know why, but I see that the JDK does it and Guava does it, and I think we must have done it for a similar reason.

@victornoel
Copy link
Contributor Author

@motlin in my own projects, I usually use the following pattern to solve this kind of situation:

  • I have only abstract or final classes, and abstract classes have either final or abstract methods
  • I have abstract "envelopes" which are classes whose sole purpose is to implement an interface, wrap an object of that interface and delegate all methods (defined as final) to the object.

With this pattern, I can define any implementation of the interfaces in terms of existing implementations. See https://github.com/victornoel/eo-envelopes for a tooling made and use to simplify my life to apply this pattern.

Writing envelopes for all the interface of EC could be a good alternative to this PR :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants