Whilst trying to understand how to implemenent a new toolchain and browsing the Gradle source, I noticed that there a number of cases where extension objects are created and then added into the model. For instance (shown as simplified code):
This is a way of bridging the gap between old and new model. The primary example here is the publishing plugins, which are configured via a legacy project extension but whose tasks are created via model rules.
For new development, no. This is mainly a way to avoid breaking changes for folks that are used to configuring an existing project extension. It also allows for some interoperability between legacy plugins and rules plugins. In general you should be using model elements for this stuff, and preferably, managed models.
There are some distinct differences here which are important. Most notably the use of new here means there is no decoration done to the ToolChain as would be the case with extensions.create('toolChains', ToolChain.class). Features not available include:
Setter methods. Meaning in the DSL you can no longer do prop 'value'. You must use the assignment (=) operator.
The model element is not itself extensible. Meaning you cannot add properties to it via ext and you can not add extension objects to it.
If you have any reliance on services via @Inject this will no longer function.
The GroovyObject class is no longer mixed in.
For simple extension types this is likely not a problem. Just keep in mind that it’s not necessarily a 1:1 migration path.
Which is fine for simple assignments, but what worries me about that is when one has a list of things i.e a List<String> and would want to append to the list. It is no longer possible to do
I riding my hobby horse now. I like a DSL to be as semantically clear as possible with as little possible punctuation and unnecessary words distracting from the intent.
True for the classic way of doing that, but I don’t see a way of doing that for a managed type.
(It is very possible that someone might go down the same way in migrating their code as what has been discussed in this thread, so at some point they will think that they need to convert their extension to a managed type).
This is correct. Adding some DSL decoration to managed types is still something we want to do. The model DSL in general is still very much a work in progress. The pattern above can still just as well be implemented by just marking that property as @Unmanaged.
Correct, we do generate these methods for managed types. I was previously referring to your example of reusing an existing extension type as an unmanaged model element.
The consequence of this thread is that I realised that it would be useful for people know how to migrate an existing extension to the new model. I have managed to code up and write down the outlines of recipes that demonstrate three stages of migration, the final being a managed version. They will eventually also discuss the caveats of each stage.
The only place where I came unstack is to see if it is possible to create some hybrid (fourth) solution using @Unmanaged as you mentioned. First things is that one cannot simply stick an @Unmanaged annotation on and think that it will work. Adding the following to the ExternalTool interface from a previous posting
will result in something like Invalid managed model type b.n.e.hybrid.ExternalTool: property 'execArgs' is marked as @Unmanaged, but is of @Managed type 'java.util.List<java.lang.String>'. Please remove the @Managed annotation. The very obvious solution is to use a tyoe which is clearly unmanaged and not any of the manageablle ones listed in the docs. In then needs to be accessed via a dot.