There are many natural ways to express the value for a file in the Gradle DSL. This is formally encoded in the project.file()
method that takes an Object and returns a File, using well defined coercion rules. Furthermore, many tasks and other DSL exposed
objects accept Object parameters which they implicitly coerce to a File internally. This spec is about making such implicit coercion
automatic, implicit and universal.
This may also lay some groundwork for other implicit type coercions.
For API such as:
class MyTask extends DefaultTask {
File someFile
}
The user should be able to set this value flexibly:
myTask {
someFile "project/relative/path"
}
Instead of the long hand:
myTask {
someFile project.file("project/relative/path")
}
There are two user oriented views of this feature:
- The user trying to set a file value
- The build “plugin” author accepting a file value from the “user”
This type coercion should be entirely transparent to group #2 and simple and predictable for group #1. That is, for any object exposed
in the DSL, a user should be able to set File
properties of objects using different (well defined) types.
Story 1: A DSL user specifies the value for a file property with a value supported by project.file() (no deferred evaluation)
A user sets a value for a file property, using a value that can be converted to a File via project.file(). No deferred evaluation is supported. That is, all values are coerced immediately. This will be targeted at DSL (or more precisely, Groovy) users. This story does not include a static Java friendly API for this functionality.
Only property setting is covered, so only setters will be decorated. Arbitrary methods that accept a File are not covered by this story.
The only user visible change will the documentation that states that it is possible to assign different types of values to
File
implicitly in the documentation. There is also no new API or change required by plugin/task etc. authors to leverage this
feature. This implies that any method
The given value may not be coercible to File
. The produced error message should indicate:
- The object that the property-to-be-set belongs to
- The name of the property-to-be-set
- The invalid type
- A description of what the valid types are, or how to find out what the valid types are
- User tries to assign relative path as String to File property (and is resolved project relative)
- User tries to assign absolute path as String to File property
- Variants on #1 and #2 using other values supported by Project.file()
- User tries to assign value using the =-less method variant (e.g. obj.someFileProperty("some/path"))
High level:
- Add a type coercing
DynamicObject
implementation. - In
ExtensibleDynamicObject
(the dynamic object created in decorated classes), wrap the delegate dynamic object in the type coercing wrapper.
Detail:
A complicating factor is that the type coercing dynamic object must be contextual the project that the object belongs to. It is not straightforward to “push the project” down to the ExtensibleDynamicObject which will create the coercing wrapper. We have the same problem with pushing down the instantiator to this level to facilitate extension containers being able to construct decorated objects.
A new type will be created:
interface ObjectInstantiationContext {
ServiceRegistry getServices()
}
When a decorated object is created, there will be a thread local object of this type available for retrieval (like ThreadGlobalInstantiator
or AbstractTask.nextInstance
). MixInExtensibleDynamicObject
will read the thread global ObjectInstantiationContext
and use it when constructing
the backing dynamic objects.
Initially the coercion will be implemented by fetching a FileResolver
from the instantion context service registry and using it to coerce the value.
The "type coercing wrapper" will be implemented as a DynamicObject
implementation that can wrap any DynamicObject
implementation. It will intercept methods and identify coercions based on given argument types and parameter types of the methods provided by the real dynamic object.
Story 2: A static API user (e.g. Java) specifies the value for a file property with a value supported by project.file() (no deferred evaluation)
TBD
TBD
TBD
TBD
This stuff is never done. This section is to keep track of assumptions and things we haven't figured out yet.