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

Don't cast public interface MutableVersionConstraint to internal internal implementations (DefaultMutableVersionConstraint). #22557

Open
yogurtearl opened this issue Oct 29, 2022 · 4 comments

Comments

@yogurtearl
Copy link
Contributor

I want to implement a custom implementation of the VersionCatalog interface, I may also need to also implement MinimalExternalModuleDependency and VersionConstraint

But this causes error like this:

Caused by: java.lang.ClassCastException: class com.example.MyCustomVersionConstraint cannot be cast to class org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint (com.example.MyCustomVersionConstraint is in unnamed module of loader org.gradle.internal.classloader.VisitableURLClassLoader @41a95ba7; org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint is in unnamed module of loader org.gradle.initialization.MixInLegacyTypesClassLoader @1f760b47)
        at org.gradle.api.internal.artifacts.dependencies.AbstractExternalModuleDependency.<init>(AbstractExternalModuleDependency.java:54)
        at org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency.<init>(DefaultExternalModuleDependency.java:35)
        at org.gradle.api.internal.artifacts.dependencies.DefaultExternalModuleDependency_Decorated.<init>(Unknown Source)
        at jdk.internal.reflect.GeneratedConstructorAccessor79.newInstance(Unknown Source)
        at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at org.gradle.internal.instantiation.generator.AsmBackedClassGenerator$InvokeConstructorStrategy.newInstance(AsmBackedClassGenerator.java:1913)
        at org.gradle.internal.instantiation.generator.AbstractClassGenerator$GeneratedClassImpl$GeneratedConstructorImpl.newInstance(AbstractClassGenerator.java:506)
        at org.gradle.internal.instantiation.generator.DependencyInjectingInstantiator.doCreate(DependencyInjectingInstantiator.java:64)
        ... 214 more

This is because gradle is casting the public interface (MutableVersionConstraint) to an internal implementation (org.gradle.api.internal.artifacts.dependencies.DefaultMutableVersionConstraint) here:

It defeats the purpose of the interface if you assume that it is always an instance of DefaultMutableVersionConstraint (internal API)

If you change that line to:

        this.versionConstraint = new DefaultMutableVersionConstraint(version);

that should fix it.

@jbartok
Copy link
Member

jbartok commented Nov 14, 2022

Could you please explain to us what your use case is?
MutableVersionConstraint is annotated with @HasInternalProtocol, which means it's not something designed to be implemented by build authors.

@yogurtearl
Copy link
Contributor Author

@HasInternalProtocol is not visible in the javadocs:
https://docs.gradle.org/7.6-rc-3/javadoc/org/gradle/api/artifacts/MutableVersionConstraint.html

For doing a custom implementation of VersionCatalog, you need to be able to implement this:

Optional<Provider<MinimalExternalModuleDependency>> findLibrary(String alias);

MinimalExternalModuleDependency needs an impl of:

VersionConstraint getVersionConstraint();

If you try to just implement VersionConstraint you hit issue #22718 , which means you need to implement MutableVersionConstraint instead.

If #22718 is fixed, this issue becomes less relevant.

@ljacomet
Copy link
Member

Can you explain why you are implementing a custom version catalog?
Is it a missing feature? A migration from an internal alternative? Something else?

@yogurtearl
Copy link
Contributor Author

Mostly working around issues like these:

But implementing public interfaces is also useful for making Fake objects for use in tests.

You can avoid these types of issues if you wrap the interfaces with internal impls instead of casting them to internal impls, to avoid these type of issues.

As noted above, wrapping instead of casting solves this issue:

this.versionConstraint = new DefaultMutableVersionConstraint(version);

@jbartok jbartok removed their assignment Nov 21, 2022
@eskatos eskatos added the a:bug label Nov 23, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants