Real title (that the forum software does not like): How to use PolymorphicDomainObjectContainer?
Probably I am just missing some dark magic, but I am not able to get PolymorphicDomainObjectContainer references working the way that the Gradle documentation says they should. E.g. I have the following:
interface Extension {
...
}
class StandardExtension implements Extension {
}
class HibernateOrmExtension implements Extension {
}
/**
* A Grade extension (not my Extension contract) registered as "myDsl"
*/
class MyDsl {
private final PolymorphicDomainObjectContainer<Extension> extensions;
MyDsl(Project project) {
...
this.extensions = project.getObjects().polymorphicDomainObjectContainer( Extension.class );
// register factories
extensions.registerFactory( HibernateOrmExtension.class, ... );
...
// register the "default" factory
extensions.registerFactory( Extension.class, ... );
}
public void extensions(Action<PolymorphicDomainObjectContainer<Extension>> action) {
action.execute( extensions );
}
/**
* Solely here to be able to disambiguate `extensions` as-in Gradle's woven ExtensionContainer.
* Oddy, Kotlin scripts seem to not have problems understanding that `extensions {}` refers to
* {@link #extensions}. Groovy builds for whatever reason try to map that to
* `ExtensionContainer#getExtensions()`. Grr...
*/
public void myExtensions(Action<PolymorphicDomainObjectContainer<Extension>> action) {
action.execute( extensions );
}
}
Given all of that, based on the documentation, I believe I should be able to say something like:
Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method doesNot() for arguments [com.github.sebersole.gradle.quarkus.extension.StandardExtension@5b647277, build_efel1wrxisx65esciz2niim8a$_run_closure4$_closure6$_closure7@1b5d6573] on Extension container of type org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer.
at org.gradle.internal.metaobject.AbstractDynamicObject.methodMissingException(AbstractDynamicObject.java:182)
at org.gradle.internal.metaobject.ConfigureDelegate.invokeMethod(ConfigureDelegate.java:86)
Any idea what I am doing wrong here?
There seems to be some things really strange highlighted in that error message. How does it already have an Extension reference (what it thinks is the first arg)?
So I assume that PolymorphicDomainObjectContainer simply do not work for end-users.
Sadly it is an incubating feature, so I guess I cannot complain too much. But man it really stinks that an exposed feature (incubating or not) simply does not work or do anything
That’s roughly what I tried initially, as I thought that is how it is supposed to work. However, this gives me errors about being unable to find a method with the given domain object name (a, b, … in your example):
org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'simple'.
...
Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method orm() for arguments [com.github.sebersole.gradle.quarkus.dsl.StandardExtensionSpec@3e697228, build_efel1wrxisx65esciz2niim8a$_run_closure4$_closure7$_closure8@36037961] on ExtensionSpec container of type org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer
“orm” would be like your “a”. Maybe something to do with your “code” being groovy and mine being Java?
Just to rule out any additional issues, have you tried it after moving away from the name “extensions”? In case there’s some remaining collision with ExtensionAware.
Do your extension classes have a getName() method? Can you show more about how you implemented the registered factories? Instead, could you create a simple project on github/etc that reproduces the issue? I’m happy to give it some debug time, but I’m not certain how to fill in the blanks from your given example.
Yes the ExtensionSpec objects implement Gradle’s Named contract.
Another consideration that I just considered… could this be related to TestKit? The error happens in one of my TestKit tests for the plugin. I know the official tagline is that TestKit operates just like a normal run, but that has been anything but my experience.
As far as Gradle version, I use 6.1 via wrapper.
I’ll work on committing and pushing the changes as a branch to the plugin GitHub repo for you to see.
For sure it does not like the “HibernateOrmExtensionSpec” part. I changed that to orm("HibernateOrmExtensionSpec") {...} and it at least now recognizes the correct spec type:
* What went wrong:
A problem occurred evaluating root project 'simple'.
> Could not find method orm() for arguments [com.github.sebersole.gradle.quarkus.dsl.HibernateOrmExtensionSpec, build_efel1wrxisx65esciz2niim8a$_run_closure4$_closure7$_closure8@5fbff902] on ExtensionSpec container of type org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer.
It is now an instance of HibernateOrmExtensionSpec where the previous error showed StandardExtensionSpec. So it is at least getting the ExtensionSpec type right.
But its not recognizing “orm” as the extension name. I am probably just missing something obvious, but looking at PolymorphicDomainObjectContainer it does not have any create methods for name+type+closure or name+type+action.
Where I started getting into trouble was breaking the DSL pieces out of the TestKit build script into the plugin’s src/main/java.
At least part of the problem is that I guess I do not know the proper syntax for referring to a packaged Java class from a Groovy build script - extensions.create( 'quarkus', QuarkusSpec ) no longer works once those classes have been broken out.
So it is clear that at least part of the problem is the classes not being available to the script - aka not added to the script’s (buildscript) classpath. Even though TestKit says it adds the plugin to the script’s classpath, my experience is that it does not. Another one of those limitations of TestKit.
So I started thinking of ways I could get the classes added to the script’s classpath. So I went the buildSrc route. That “works” - the script can now at least see the classes. However, other things break down, mainly the @Inject stuff you had:
@javax.inject.Inject
public QuarkusSpec(ObjectFactory objectFactory) {
...
}
// I tried both:
extensions.create( 'quarkus', QuarkusSpec, project.objects )
extensions.create( 'quarkus', QuarkusSpec )
This fails with
> No service of type ObjectFactory available in DefaultServiceRegistry.
Though why I get that failure when I explicitly pass the ObjectFactory makes no sense to me…
I’m again going to assert that it seems like PolymorphicDomainObjectContainer does not work the way it is designed to work in all cases. I wish I knew the boundary of these cases, but I simply do not. Clearly as soon as the named-objects are defined outside the script it starts getting dicey. Beyond that…