diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/dsl/DependencyHandler.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/dsl/DependencyHandler.java index 226419345eea..d6dde425d33b 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/dsl/DependencyHandler.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/dsl/DependencyHandler.java @@ -451,6 +451,42 @@ public interface DependencyHandler extends ExtensionAware { /** * Registers an artifact transform. * + *

+ * The registration action needs to specify the {@code from} and {@code to} attributes. + * It may also provide parameters for the transform action by using {@link TransformSpec#parameters(Action)}. + *

+ * + *

Example: When you have a transform action like this:

+ * + *
+     * abstract class MyTransform implements TransformAction<Parameters> {
+     *     interface Parameters extends TransformParameters {
+     *         {@literal @}Input
+     *         Property<String> getStringParameter();
+     *         {@literal @}InputFiles
+     *         ConfigurableFileCollection getInputFiles();
+     *     }
+     *
+     *     void transform(TransformOutputs outputs) {
+     *         // ...
+     *     }
+     * }
+     *
+     * // Then you can register the action like this:
+     *
+     * def artifactType = Attribute.of('artifactType', String)
+     *
+     * dependencies.registerTransform(MyTransform) {
+     *     from.attribute(artifactType, "jar")
+     *     to.attribute(artifactType, "java-classes-directory")
+     *
+     *     parameters {
+     *         stringParameter.set("Some string")
+     *         inputFiles.from("my-input-file")
+     *     }
+     * }
+     * 
+ * * @see TransformAction * @since 5.3 */ diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/CacheableTransform.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/CacheableTransform.java index 4b1dd5ef91ce..62c404086802 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/CacheableTransform.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/CacheableTransform.java @@ -24,10 +24,34 @@ import java.lang.annotation.Target; /** - *

Attached to an {@link TransformAction} type to indicate that the build cache should be used for artifact transforms of this type.

+ * Attached to a {@link TransformAction} type it indicates that the build cache should be used for artifact transforms of this type. * *

Only an artifact transform that produces reproducible and relocatable outputs should be marked with {@code CacheableTransform}.

* + *

+ * Normalization must be specified for each file parameter of a cacheable transform. + * For example: + *

+ *
+ * import org.gradle.api.artifacts.transform.TransformParameters;
+ *
+ * {@literal @}CacheableTransform
+ * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+ *     {@literal @}PathSensitive(PathSensitivity.NAME_ONLY)
+ *     {@literal @}InputArtifact
+ *     public abstract Provider<FileSystemLocation> getInputArtifact();
+ *
+ *     {@literal @}Classpath
+ *     {@literal @}InputArtifactDependencies
+ *     public abstract FileCollection getDependencies();
+ *
+ *     {@literal @}Override
+ *     public void transform(TransformOutputs outputs) {
+ *         // ...
+ *     }
+ * }
+ * 
+ * * @since 5.3 */ @Incubating diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifact.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifact.java index b36c3d0a7b48..6c7076847478 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifact.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifact.java @@ -29,11 +29,27 @@ import java.lang.annotation.Target; /** - * Attached to a property that should receive the input artifact for an artifact transform. This is the artifact that the transform should be applied to. + * Attached to a property that should receive the input artifact for an artifact transform. + * This is the artifact that the transform is applied to. * - *

- * The input artifact can be injected as a {@link Provider}<{@link org.gradle.api.file.FileSystemLocation}>. - *

+ *

The input artifact can be injected as a {@link Provider}<{@link org.gradle.api.file.FileSystemLocation}>.

+ * + *

Example usage:

+ * + *
+ * import org.gradle.api.artifacts.transform.TransformParameters;
+ *
+ * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+ *
+ *     {@literal @}InputArtifact
+ *     public abstract Provider<FileSystemLocation> getInputArtifact();
+ *     {@literal @}Override
+ *     public void transform(TransformOutputs outputs) {
+ *         File input = getInputArtifact().get().getAsFile();
+ *         // Do something with the input
+ *     }
+ * }
+ * 
* * @since 5.3 */ diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifactDependencies.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifactDependencies.java index eb0d0380c703..8fa1da51be2b 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifactDependencies.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/InputArtifactDependencies.java @@ -29,8 +29,32 @@ /** * Attached to a property that should receive the artifact dependencies of the {@link InputArtifact} of an artifact transform. * - * The order of the files match that of the dependencies in the source artifact view. - * The type of the injected dependencies is {@link org.gradle.api.file.FileCollection}. + *

+ * The order of the files match that of the dependencies in the source artifact view. + * The type of the injected dependencies is {@link org.gradle.api.file.FileCollection}. + * For example, when a project depends on {@code spring-web}, when the project is transformed (i.e. the project is the input artifact), + * the input artifact dependencies are the file collection containing the {@code spring-web} JAR and all its dependencies like e.g. the {@code spring-core} JAR. + *

+ * + *

Example usage:

+ *
+ * import org.gradle.api.artifacts.transform.TransformParameters;
+ *
+ * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+ *
+ *     {@literal @}InputArtifact
+ *     public abstract Provider<FileSystemLocation> getInputArtifact();
+ *
+ *     {@literal @}InputArtifactDependencies
+ *     public abstract FileCollection getDependencies();
+ *
+ *     {@literal @}Override
+ *     public void transform(TransformOutputs outputs) {
+ *         FileCollection dependencies = getDependencies();
+ *         // Do something with the dependencies
+ *     }
+ * }
+ * 
* * @since 5.3 */ diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformAction.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformAction.java index ac6d82026033..3200f577323f 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformAction.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformAction.java @@ -16,6 +16,7 @@ package org.gradle.api.artifacts.transform; +import org.gradle.api.Action; import org.gradle.api.Incubating; import javax.inject.Inject; @@ -23,13 +24,34 @@ /** * Interface for artifact transform actions. * - *

Implementations must provide a public constructor.

+ *

+ * A transform action implementation is an abstract class implementing the {@link #transform(TransformOutputs)} method. + * A minimal implementation may look like this: + *

* - *

Implementations can receive parameters by using annotated abstract getter methods.

+ *
+ * import org.gradle.api.artifacts.transform.TransformParameters;
  *
- * 

A property annotated with {@link InputArtifact} will receive the input artifact location, which is the file or directory that the transform should be applied to. + * public abstract class MyTransform implements TransformAction<TransformParameters.None> { + * {@literal @}InputArtifact + * public abstract Provider<FileSystemLocation> getInputArtifact(); * - *

A property annotated with {@link InputArtifactDependencies} will receive the dependencies of its input artifact. + * {@literal @}Override + * public void transform(TransformOutputs outputs) { + * File input = getInputArtifact().get().getAsFile(); + * File output = outputs.file(input.getName() + ".transformed"); + * // Do something to generate output from input + * } + * } + *

+ * + * * * @param Parameter type for the transform action. Should be {@link TransformParameters.None} if the action does not have parameters. * @since 5.3 @@ -38,7 +60,12 @@ public interface TransformAction { /** - * The object provided by {@link TransformSpec#getParameters()}. + * The object provided by {@link TransformSpec#getParameters()} when registering the artifact transform. + * + *

+ * Do not implement this method in your subclass. + * Gradle provides the implementation when registering the transform action via {@link org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action)}. + *

*/ @Inject T getParameters(); @@ -46,6 +73,8 @@ public interface TransformAction { /** * Executes the transform. * + *

This method must be implemented in the subclass.

+ * * @param outputs Receives the outputs of the transform. */ void transform(TransformOutputs outputs); diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformOutputs.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformOutputs.java index 35757baf651c..ce083571f7ef 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformOutputs.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformOutputs.java @@ -35,7 +35,46 @@ public interface TransformOutputs { /** * Registers an output directory. - * For a relative path, a location for the output directory is provided. + * + *

+ * For an absolute path, the location is registered as an output directory of the {@link TransformAction}. + * The path is required to point to the {@link InputArtifact}, or point inside the input artifact if it is a directory. + * Example: + *

+ *
+     * import org.gradle.api.artifacts.transform.TransformParameters;
+     *
+     * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+     *     {@literal @}InputArtifact
+     *     public abstract Provider<FileSystemLocation> getInputArtifact();
+     *     {@literal @}Override
+     *     public void transform(TransformOutputs outputs) {
+     *         outputs.dir(getInputArtifact().get().getAsFile());
+     *         outputs.dir(new File(getInputArtifact().get().getAsFile(), "sub-dir"));
+     *     }
+     * }
+     * 
+ * + *

+ * For a relative path, a location for the output directory is provided by Gradle, so that the {@link TransformAction} can produce its outputs at that location. + * The directory is created automatically when calling the method. + * Example: + *

+ *
+     * import org.gradle.api.artifacts.transform.TransformParameters;
+     *
+     * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+     *     {@literal @}Override
+     *     public void transform(TransformOutputs outputs) {
+     *         File myOutput = outputs.dir("my-output");
+     *         Files.write(myOutput.toPath().resolve("file.txt"), "Generated text");
+     *     }
+     * }
+     * 
+ * + *

+ * Note: it is an error if the registered directory does not exist when the {@link TransformAction#transform(TransformOutputs)} method finishes. + *

* * @param path path of the output directory * @return determined location of the output @@ -44,9 +83,52 @@ public interface TransformOutputs { /** * Registers an output file. - * For a relative path, a location for the output file is provided. * - * @param path path of the output directory + *

+ * For an absolute path, the location is registered as an output file of the {@link TransformAction}. + * The path is required to point to the {@link InputArtifact} or be inside it if the input artifact is a directory. + * Example: + *

+ *
+     * import org.gradle.api.artifacts.transform.TransformParameters;
+     *
+     * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+     *     {@literal @}InputArtifact
+     *     public abstract Provider<FileSystemLocation> getInputArtifact();
+     *     {@literal @}Override
+     *     public void transform(TransformOutputs outputs) {
+     *         File input = getInputArtifact().get().getAsFile();
+     *         if (input.isFile()) {
+     *             outputs.file(input);
+     *         } else {
+     *             outputs.file(new File(input, "file-in-input-artifact.txt"));
+     *         }
+     *     }
+     * }
+     * 
+ * + *

+ * For a relative path, a location for the output file is provided by Gradle, so that the {@link TransformAction} can produce its outputs at that location. + * The parent directory of the provided location is created automatically when calling the method. + * Example: + *

+ *
+     * import org.gradle.api.artifacts.transform.TransformParameters;
+     *
+     * public abstract class MyTransform implements TransformAction<TransformParameters.None> {
+     *     {@literal @}InputArtifact
+     *     public abstract Provider<FileSystemLocation> getInputArtifact();
+     *     {@literal @}Override
+     *     public void transform(TransformOutputs outputs) {
+     *         File myOutput = outputs.file("my-output.transformed");
+     *         Files.write(myOutput.toPath(), "Generated text");
+     *     }
+     * }
+     * 
+ * + *

The registered file needs to exist when the {@link TransformAction#transform(TransformOutputs)} method finishes.

+ * + * @param path path of the output file * @return determined location of the output */ File file(Object path); diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformParameters.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformParameters.java index 72bc2c266f7a..2fb824c93fa6 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformParameters.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformParameters.java @@ -21,6 +21,22 @@ /** * Marker interface for parameter objects to {@link TransformAction}s. * + *

+ * Parameter types should be interfaces, only declaring getters for {@link org.gradle.api.provider.Property}-like objects. + * All getters must be annotated with an input annotation like {@link org.gradle.api.tasks.Input} or {@link org.gradle.api.tasks.InputFiles}. + * Normalization annotations such as {@link org.gradle.api.tasks.PathSensitive} or {@link org.gradle.api.tasks.Classpath} can be used as well. + * See the table of incremental build property type annotations for all annotations which can be used. + * Example: + *

+ *
+ * public interface MyParameters extends TransformParameters {
+ *     {@literal @}Input
+ *     Property<String> getStringParameter();
+ *     {@literal @}InputFiles
+ *     ConfigurableFileCollection getInputFiles();
+ * }
+ * 
+ * * @since 5.3 */ @Incubating @@ -28,6 +44,8 @@ public interface TransformParameters { /** * Used for {@link TransformAction}s without parameters. * + *

When {@link None} is used as parameters, calling {@link TransformAction#getParameters()} throws an exception.

+ * * @since 5.3 */ @Incubating diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformSpec.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformSpec.java index 1c5b61f3271e..e1b51d532dac 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformSpec.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/TransformSpec.java @@ -23,6 +23,7 @@ /** * Base configuration for artifact transform registrations. * + * @see org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action) * @param The transform specific parameter type. * @since 5.3 */ @@ -30,21 +31,29 @@ public interface TransformSpec { /** * Attributes that match the variant that is consumed. + * + * @see org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action) */ AttributeContainer getFrom(); /** * Attributes that match the variant that is produced. + * + * @see org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action) */ AttributeContainer getTo(); /** * The parameters for the transform action. + * + * @see org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action) */ T getParameters(); /** * Configure the parameters for the transform action. + * + * @see org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(Class, Action) */ void parameters(Action action); } diff --git a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/package-info.java b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/package-info.java index 04f4a630ad16..9c21f9e50946 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/package-info.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/artifacts/transform/package-info.java @@ -15,7 +15,14 @@ */ /** - * Classes that perform artifact transformations. + * Provides classes, interfaces and annotations for registering and implementing artifact transforms. + * + *

+ * To register an artifact transform, use {@link org.gradle.api.artifacts.dsl.DependencyHandler#registerTransform(java.lang.Class, org.gradle.api.Action)}. + * This allows you to register a {@link org.gradle.api.artifacts.transform.TransformAction} using {@link org.gradle.api.artifacts.transform.TransformSpec}. + *

+ * + *

If you want to create a new artifact transform action, have a look at {@link org.gradle.api.artifacts.transform.TransformAction}.

*/ @org.gradle.api.NonNullApi package org.gradle.api.artifacts.transform; diff --git a/subprojects/core-api/src/main/java/org/gradle/api/model/ObjectFactory.java b/subprojects/core-api/src/main/java/org/gradle/api/model/ObjectFactory.java index cc2cf984bd9b..3545dd81c0bd 100644 --- a/subprojects/core-api/src/main/java/org/gradle/api/model/ObjectFactory.java +++ b/subprojects/core-api/src/main/java/org/gradle/api/model/ObjectFactory.java @@ -16,8 +16,11 @@ package org.gradle.api.model; +import org.gradle.api.DomainObjectSet; import org.gradle.api.Incubating; import org.gradle.api.Named; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; @@ -97,6 +100,42 @@ public interface ObjectFactory { */ ConfigurableFileCollection fileCollection(); + /** + *

Creates a new {@link NamedDomainObjectContainer} for managing named objects of the specified type. The specified type must have a public constructor which takes the name as a String parameter.

+ * + *

All objects MUST expose their name as a bean property named "name". The name must be constant for the life of the object.

+ * + * @param elementType The type of objects for the container to contain. + * @param The type of objects for the container to contain. + * @return The container. Never returns null. + * @since 5.5 + */ + NamedDomainObjectContainer container(Class elementType); + + /** + *

Creates a new {@link NamedDomainObjectContainer} for managing named objects of the specified type. The given factory is used to create object instances.

+ * + *

All objects MUST expose their name as a bean property named "name". The name must be constant for the life of the object.

+ * + * + * @param elementType The type of objects for the container to contain. + * @param factory The factory to use to create object instances. + * @param The type of objects for the container to contain. + * @return The container. Never returns null. + * @since 5.5 + */ + NamedDomainObjectContainer container(Class elementType, NamedDomainObjectFactory factory); + + /** + * Creates a new {@link DomainObjectSet} for managing objects of the specified type. + * + * @param elementType The type of objects for the domain object set to contain. + * @param The type of objects for the domain object set to contain. + * @return The domain object set. Never returns null. + * @since 5.5 + */ + DomainObjectSet domainObjectSet(Class elementType); + /** * Creates a {@link Property} implementation to hold values of the given type. The property has no initial value. * @@ -122,7 +161,7 @@ public interface ObjectFactory { * * @param elementType The type of element. * @param The type of element. - * @return The property. Never returns null; + * @return The property. Never returns null. * @since 4.3 */ ListProperty listProperty(Class elementType); @@ -134,7 +173,7 @@ public interface ObjectFactory { * * @param elementType The type of element. * @param The type of element. - * @return The property. Never returns null; + * @return The property. Never returns null. * @since 4.5 */ SetProperty setProperty(Class elementType); diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/NamedDomainObjectContainerIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/NamedDomainObjectContainerIntegrationTest.groovy index 7896b9755539..f3e44b69e9d2 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/api/NamedDomainObjectContainerIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/api/NamedDomainObjectContainerIntegrationTest.groovy @@ -16,6 +16,8 @@ package org.gradle.api +import spock.lang.Issue + class NamedDomainObjectContainerIntegrationTest extends AbstractDomainObjectContainerIntegrationTest { @Override String getContainerStringRepresentation() { @@ -61,4 +63,36 @@ class NamedDomainObjectContainerIntegrationTest extends AbstractDomainObjectCont expect: succeeds "verify" } + + + def "chained lookup of testContainer.withType.matching"() { + buildFile << """ + testContainer.withType(testContainer.type).matching({ it.name.endsWith("foo") }).all { element -> + assert element.name in ['foo', 'barfoo'] + } + + testContainer.register("foo") + testContainer.register("bar") + testContainer.register("foobar") + testContainer.register("barfoo") + """ + expect: + succeeds "help" + } + + @Issue("https://github.com/gradle/gradle/issues/9446") + def "chained lookup of testContainer.matching.withType"() { + buildFile << """ + testContainer.matching({ it.name.endsWith("foo") }).withType(testContainer.type).all { element -> + assert element.name in ['foo', 'barfoo'] + } + + testContainer.register("foo") + testContainer.register("bar") + testContainer.register("foobar") + testContainer.register("barfoo") + """ + expect: + succeeds "help" + } } diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/TaskContainerIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/TaskContainerIntegrationTest.groovy index 741d810b1db3..27e60f38829d 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/api/TaskContainerIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/api/TaskContainerIntegrationTest.groovy @@ -16,7 +16,7 @@ package org.gradle.api -import groovy.transform.NotYetImplemented + import spock.lang.Issue class TaskContainerIntegrationTest extends AbstractDomainObjectContainerIntegrationTest { @@ -37,30 +37,29 @@ class TaskContainerIntegrationTest extends AbstractDomainObjectContainerIntegrat def "chained lookup of tasks.withType.matching"() { buildFile << """ tasks.withType(Copy).matching({ it.name.endsWith("foo") }).all { task -> - assert task.path in [':foo', ':barfoo'] + assert task.path in [':foo'] } tasks.register("foo", Copy) tasks.register("bar", Copy) - tasks.register("foobar", Copy) - tasks.register("barfoo", Copy) + tasks.register("foobar", Delete) + tasks.register("barfoo", Delete) """ expect: succeeds "help" } @Issue("https://github.com/gradle/gradle/issues/9446") - @NotYetImplemented def "chained lookup of tasks.matching.withType"() { buildFile << """ tasks.matching({ it.name.endsWith("foo") }).withType(Copy).all { task -> - assert task.path in [':foo', ':barfoo'] + assert task.path in [':foo'] } tasks.register("foo", Copy) tasks.register("bar", Copy) - tasks.register("foobar", Copy) - tasks.register("barfoo", Copy) + tasks.register("foobar", Delete) + tasks.register("barfoo", Delete) """ expect: succeeds "help" diff --git a/subprojects/core/src/integTest/groovy/org/gradle/api/internal/model/ObjectFactoryIntegrationTest.groovy b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/model/ObjectFactoryIntegrationTest.groovy index 7b0ad84b0a49..5ed28961e588 100644 --- a/subprojects/core/src/integTest/groovy/org/gradle/api/internal/model/ObjectFactoryIntegrationTest.groovy +++ b/subprojects/core/src/integTest/groovy/org/gradle/api/internal/model/ObjectFactoryIntegrationTest.groovy @@ -499,4 +499,61 @@ class ObjectFactoryIntegrationTest extends AbstractIntegrationSpec { expect: succeeds() } + + def "plugin can create NamedDomainObjectContainer instances"() { + given: + buildFile << """ + class NamedThing implements Named { + final String name + NamedThing(String name) { + this.name = name + } + } + + def container = project.objects.container(NamedThing) + assert container != null + def element = container.create('foo') + assert element.name == 'foo' + assert container.size() == 1 + """ + + expect: + succeeds() + } + + def "plugin can create NamedDomainObjectContainer instances with factory"() { + given: + buildFile << """ + class NamedThing implements Named { + final String name + NamedThing(String name) { + this.name = name + } + } + + def container = project.objects.container(NamedThing) { + return new NamedThing("prefix-" + it) + } + assert container != null + def element = container.create("foo") + assert element.name == 'prefix-foo' + assert container.size() == 1 + """ + + expect: + succeeds() + } + + def "plugin can create DomainObjectSet instances"() { + given: + buildFile << """ + def domainObjectSet = project.objects.domainObjectSet(String) + assert domainObjectSet != null + assert domainObjectSet.add('foo') + assert domainObjectSet.size() == 1 + """ + + expect: + succeeds() + } } diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/CollectionCallbackActionDecorator.java b/subprojects/core/src/main/java/org/gradle/api/internal/CollectionCallbackActionDecorator.java index 4335f6a45a0a..6d4d6165c5d3 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/CollectionCallbackActionDecorator.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/CollectionCallbackActionDecorator.java @@ -22,7 +22,6 @@ public interface CollectionCallbackActionDecorator { - @Nullable Action decorate(@Nullable Action action); CollectionCallbackActionDecorator NOOP = new CollectionCallbackActionDecorator() { diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/DefaultDomainObjectCollection.java b/subprojects/core/src/main/java/org/gradle/api/internal/DefaultDomainObjectCollection.java index 56ef2c93824a..3ad793a82390 100755 --- a/subprojects/core/src/main/java/org/gradle/api/internal/DefaultDomainObjectCollection.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/DefaultDomainObjectCollection.java @@ -168,7 +168,7 @@ public void all(Action action) { @Override public void configureEach(Action action) { assertMutable("configureEach(Action)"); - Action wrappedAction = withMutationDisabled(action); + Action wrappedAction = withMutationDisabled(decorate(action)); Action registerLazyAddActionDecorated = eventRegister.registerLazyAddAction(wrappedAction); // copy in case any actions mutate the store @@ -224,12 +224,12 @@ public void whenObjectAdded(Closure action) { private Action addEagerAction(Action action) { store.realizePending(type); - return eventRegister.registerEagerAddAction(type, action); + return eventRegister.registerEagerAddAction(type, decorate(action)); } @Override public Action whenObjectRemoved(Action action) { - eventRegister.registerRemoveAction(type, action); + eventRegister.registerRemoveAction(type, decorate(action)); return action; } @@ -238,6 +238,10 @@ public void whenObjectRemoved(Closure action) { whenObjectRemoved(toAction(action)); } + private Action decorate(Action action) { + return eventRegister.getDecorator().decorate(action); + } + private Action toAction(Closure action) { return ConfigureUtil.configureUsing(action); } diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/collections/CollectionEventRegister.java b/subprojects/core/src/main/java/org/gradle/api/internal/collections/CollectionEventRegister.java index 33578bcfee88..9f171c1cd6ed 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/collections/CollectionEventRegister.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/CollectionEventRegister.java @@ -41,5 +41,6 @@ public interface CollectionEventRegister { CollectionEventRegister filtered(CollectionFilter filter); + // TODO: Migrate this away from here CollectionCallbackActionDecorator getDecorator(); } diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultCollectionEventRegister.java b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultCollectionEventRegister.java index e29db114f4be..88c5e05c0885 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultCollectionEventRegister.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultCollectionEventRegister.java @@ -17,6 +17,7 @@ import org.gradle.api.Action; import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.internal.Cast; import org.gradle.internal.ImmutableActionSet; import java.util.HashSet; @@ -78,17 +79,17 @@ public void fireObjectRemoved(T element) { @Override public Action registerEagerAddAction(Class type, Action addAction) { - return registerEagerAddDecoratedAction(type, decorate(addAction)); + return registerEagerAddDecoratedAction(type, addAction); } @Override public Action registerLazyAddAction(Action addAction) { - return registerLazyAddDecoratedAction(decorate(addAction)); + return registerLazyAddDecoratedAction(addAction); } @Override public void registerRemoveAction(Class type, Action removeAction) { - registerRemoveDecoratedAction(decorate(removeAction)); + registerRemoveDecoratedAction(removeAction); } private Action registerEagerAddDecoratedAction(Class type, Action decorated) { @@ -105,17 +106,9 @@ private void registerRemoveDecoratedAction(Action decorated) { removeActions = removeActions.add(decorated); } - private Action decorate(Action action) { - return decorator.decorate(action); - } - - private Action decorate(Action action, CollectionFilter filter) { - return filter.filtered(decorator.decorate(action)); - } - @Override public CollectionEventRegister filtered(CollectionFilter filter) { - return new FilteredEventRegister(filter); + return new FilteredEventRegister(filter, this); } private void subscribe(Class type) { @@ -135,14 +128,16 @@ private void subscribe(Class type) { private class FilteredEventRegister implements CollectionEventRegister { private final CollectionFilter filter; + private final CollectionEventRegister delegate; - FilteredEventRegister(CollectionFilter filter) { + FilteredEventRegister(CollectionFilter filter, CollectionEventRegister delegate) { this.filter = filter; + this.delegate = Cast.uncheckedCast(delegate); } @Override public CollectionCallbackActionDecorator getDecorator() { - return decorator; + return delegate.getDecorator(); } @Override @@ -167,22 +162,22 @@ public boolean isSubscribed(Class type) { @Override public Action registerEagerAddAction(Class type, Action addAction) { - return registerEagerAddDecoratedAction(type, decorate(addAction, filter)); + return delegate.registerEagerAddAction(type, filter.filtered(addAction)); } @Override public Action registerLazyAddAction(Action addAction) { - return registerLazyAddDecoratedAction(decorate(addAction, filter)); + return delegate.registerLazyAddAction(filter.filtered(addAction)); } @Override public void registerRemoveAction(Class type, Action removeAction) { - registerRemoveDecoratedAction(decorate(removeAction, filter)); + delegate.registerRemoveAction(type, filter.filtered(removeAction)); } @Override public CollectionEventRegister filtered(CollectionFilter filter) { - return new FilteredEventRegister(filter); + return new FilteredEventRegister(filter, (CollectionEventRegister) this); } } diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java new file mode 100644 index 000000000000..c944087af3d5 --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.api.internal.collections; + +import groovy.lang.Closure; +import org.gradle.api.DomainObjectCollection; +import org.gradle.api.DomainObjectSet; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; +import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.CompositeDomainObjectSet; +import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.DynamicPropertyNamer; +import org.gradle.api.internal.FactoryNamedDomainObjectContainer; +import org.gradle.api.internal.MutationGuard; +import org.gradle.api.internal.ReflectiveNamedDomainObjectFactory; +import org.gradle.internal.Cast; +import org.gradle.internal.instantiation.InstantiatorFactory; +import org.gradle.internal.reflect.Instantiator; +import org.gradle.internal.service.ServiceRegistry; + +public class DefaultDomainObjectCollectionFactory implements DomainObjectCollectionFactory { + private final InstantiatorFactory instantiatorFactory; + private final ServiceRegistry servicesToInject; + private final CollectionCallbackActionDecorator collectionCallbackActionDecorator; + private final MutationGuard mutationGuard; + + public DefaultDomainObjectCollectionFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry servicesToInject, CollectionCallbackActionDecorator collectionCallbackActionDecorator, MutationGuard mutationGuard) { + this.instantiatorFactory = instantiatorFactory; + this.servicesToInject = servicesToInject; + this.collectionCallbackActionDecorator = collectionCallbackActionDecorator; + this.mutationGuard = mutationGuard; + } + + @Override + public NamedDomainObjectContainer newNamedDomainObjectContainer(Class elementType) { + // TODO - this should also be using the decorating instantiator but cannot for backwards compatibility + ReflectiveNamedDomainObjectFactory objectFactory = new ReflectiveNamedDomainObjectFactory(elementType, instantiatorFactory.injectLenient(servicesToInject)); + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return Cast.uncheckedCast(instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), objectFactory, mutationGuard, collectionCallbackActionDecorator)); + } + + @Override + public NamedDomainObjectContainer newNamedDomainObjectContainer(Class elementType, NamedDomainObjectFactory factory) { + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return Cast.uncheckedCast(instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), factory, mutationGuard, collectionCallbackActionDecorator)); + } + + @Override + public NamedDomainObjectContainer newNamedDomainObjectContainer(Class type, Closure factoryClosure) { + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return Cast.uncheckedCast(instantiator.newInstance(FactoryNamedDomainObjectContainer.class, type, instantiator, new DynamicPropertyNamer(), factoryClosure, mutationGuard, collectionCallbackActionDecorator)); + } + + @Override + public DomainObjectSet newDomainObjectSet(Class elementType) { + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return Cast.uncheckedCast(instantiator.newInstance(DefaultDomainObjectSet.class, elementType, collectionCallbackActionDecorator)); + } + + @Override + public CompositeDomainObjectSet newDomainObjectSet(Class elementType, DomainObjectCollection... collections) { + return CompositeDomainObjectSet.create(elementType, collectionCallbackActionDecorator, collections); + } +} diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/collections/DomainObjectCollectionFactory.java b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DomainObjectCollectionFactory.java new file mode 100644 index 000000000000..cb0720cdbc11 --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DomainObjectCollectionFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gradle.api.internal.collections; + +import groovy.lang.Closure; +import org.gradle.api.DomainObjectCollection; +import org.gradle.api.DomainObjectSet; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; +import org.gradle.api.internal.CompositeDomainObjectSet; + +public interface DomainObjectCollectionFactory { + /** + * Creates a {@link NamedDomainObjectContainer} for managing named objects of the specified type. + */ + NamedDomainObjectContainer newNamedDomainObjectContainer(Class elementType); + + /** + * Creates a {@link NamedDomainObjectContainer} for managing named objects of the specified type created with the given factory. + */ + NamedDomainObjectContainer newNamedDomainObjectContainer(Class elementType, NamedDomainObjectFactory factory); + + /** + * Creates a {@link NamedDomainObjectContainer} for managing named objects of the specified type. The given closure is used to create object instances. The name of the instance to be created is passed as a parameter to the closure. + */ + NamedDomainObjectContainer newNamedDomainObjectContainer(Class type, Closure factoryClosure); + + /** + * Creates a {@link DomainObjectSet} for managing objects of the specified type. + */ + DomainObjectSet newDomainObjectSet(Class elementType); + + /** + * Creates a {@link CompositeDomainObjectSet} for managing a collection of {@link DomainObjectCollection} of the specified type. + */ + CompositeDomainObjectSet newDomainObjectSet(Class elementType, DomainObjectCollection... collections); +} diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/model/DefaultObjectFactory.java b/subprojects/core/src/main/java/org/gradle/api/internal/model/DefaultObjectFactory.java index 6c990c564370..e58d49634e31 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/model/DefaultObjectFactory.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/model/DefaultObjectFactory.java @@ -16,13 +16,17 @@ package org.gradle.api.internal.model; +import org.gradle.api.DomainObjectSet; import org.gradle.api.Named; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFile; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.file.SourceDirectorySet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.DefaultSourceDirectorySet; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.file.FilePropertyFactory; @@ -56,14 +60,16 @@ public class DefaultObjectFactory implements ObjectFactory { private final DirectoryFileTreeFactory directoryFileTreeFactory; private final FilePropertyFactory filePropertyFactory; private final FileCollectionFactory fileCollectionFactory; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; - public DefaultObjectFactory(Instantiator instantiator, NamedObjectInstantiator namedObjectInstantiator, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory) { + public DefaultObjectFactory(Instantiator instantiator, NamedObjectInstantiator namedObjectInstantiator, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.instantiator = instantiator; this.namedObjectInstantiator = namedObjectInstantiator; this.fileResolver = fileResolver; this.directoryFileTreeFactory = directoryFileTreeFactory; this.filePropertyFactory = filePropertyFactory; this.fileCollectionFactory = fileCollectionFactory; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; } @Override @@ -102,6 +108,21 @@ public RegularFileProperty fileProperty() { return filePropertyFactory.newFileProperty(); } + @Override + public NamedDomainObjectContainer container(Class elementType) { + return domainObjectCollectionFactory.newNamedDomainObjectContainer(elementType); + } + + @Override + public NamedDomainObjectContainer container(Class elementType, NamedDomainObjectFactory factory) { + return domainObjectCollectionFactory.newNamedDomainObjectContainer(elementType, factory); + } + + @Override + public DomainObjectSet domainObjectSet(Class elementType) { + return domainObjectCollectionFactory.newDomainObjectSet(elementType); + } + @Override public Property property(Class valueType) { if (valueType == null) { diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/model/InstantiatorBackedObjectFactory.java b/subprojects/core/src/main/java/org/gradle/api/internal/model/InstantiatorBackedObjectFactory.java index 1d34ed34baee..3a76bde048f1 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/model/InstantiatorBackedObjectFactory.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/model/InstantiatorBackedObjectFactory.java @@ -15,7 +15,10 @@ */ package org.gradle.api.internal.model; +import org.gradle.api.DomainObjectSet; import org.gradle.api.Named; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; @@ -51,6 +54,21 @@ public ConfigurableFileCollection fileCollection() { throw new UnsupportedOperationException("This ObjectFactory implementation does not support constructing file collections"); } + @Override + public NamedDomainObjectContainer container(Class elementType) { + throw new UnsupportedOperationException("This ObjectFactory implementation does not support constructing named domain object container"); + } + + @Override + public NamedDomainObjectContainer container(Class elementType, NamedDomainObjectFactory factory) { + throw new UnsupportedOperationException("This ObjectFactory implementation does not support constructing named domain object container with factory"); + } + + @Override + public DomainObjectSet domainObjectSet(Class elementType) { + throw new UnsupportedOperationException("This ObjectFactory implementation does not support constructing domain object set"); + } + @Override public Property property(Class valueType) { return new DefaultPropertyState(valueType); diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/plugins/DefaultPluginManager.java b/subprojects/core/src/main/java/org/gradle/api/internal/plugins/DefaultPluginManager.java index eafb0b90fa26..261dc34b8139 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/plugins/DefaultPluginManager.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/plugins/DefaultPluginManager.java @@ -23,7 +23,7 @@ import org.gradle.api.DomainObjectSet; import org.gradle.api.Plugin; import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.plugins.AppliedPlugin; import org.gradle.api.plugins.InvalidPluginException; import org.gradle.api.plugins.PluginContainer; @@ -56,7 +56,6 @@ public class DefaultPluginManager implements PluginManagerInternal { private final Instantiator instantiator; private final PluginTarget target; private final PluginRegistry pluginRegistry; - private final CollectionCallbackActionDecorator callbackDecorator; private final DefaultPluginContainer pluginContainer; private final Map, PluginImplementation> plugins = Maps.newHashMap(); private final Map, Plugin> instances = Maps.newLinkedHashMap(); @@ -64,15 +63,16 @@ public class DefaultPluginManager implements PluginManagerInternal { private final BuildOperationExecutor buildOperationExecutor; private final UserCodeApplicationContext userCodeApplicationContext; + private DomainObjectCollectionFactory domainObjectCollectionFactory; - public DefaultPluginManager(final PluginRegistry pluginRegistry, Instantiator instantiator, final PluginTarget target, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator callbackDecorator) { + public DefaultPluginManager(final PluginRegistry pluginRegistry, Instantiator instantiator, final PluginTarget target, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator callbackDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.instantiator = instantiator; this.target = target; this.pluginRegistry = pluginRegistry; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; this.pluginContainer = new DefaultPluginContainer(pluginRegistry, this, callbackDecorator); this.buildOperationExecutor = buildOperationExecutor; this.userCodeApplicationContext = userCodeApplicationContext; - this.callbackDecorator = callbackDecorator; } private T instantiatePlugin(Class type) { @@ -218,7 +218,7 @@ public DomainObjectSet pluginsForId(String id) { PluginId pluginId = DefaultPluginId.unvalidated(id); DomainObjectSet pluginsForId = idMappings.get(pluginId); if (pluginsForId == null) { - pluginsForId = new DefaultDomainObjectSet(PluginWithId.class, callbackDecorator); + pluginsForId = domainObjectCollectionFactory.newDomainObjectSet(PluginWithId.class); idMappings.put(pluginId, pluginsForId); for (PluginImplementation plugin : plugins.values()) { if (plugin.isAlsoKnownAs(pluginId)) { diff --git a/subprojects/core/src/main/java/org/gradle/api/internal/project/DefaultProject.java b/subprojects/core/src/main/java/org/gradle/api/internal/project/DefaultProject.java index e80f8a2b0bf8..c7af5312100d 100644 --- a/subprojects/core/src/main/java/org/gradle/api/internal/project/DefaultProject.java +++ b/subprojects/core/src/main/java/org/gradle/api/internal/project/DefaultProject.java @@ -46,14 +46,12 @@ import org.gradle.api.file.FileTree; import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.DynamicObjectAware; -import org.gradle.api.internal.DynamicPropertyNamer; -import org.gradle.api.internal.FactoryNamedDomainObjectContainer; import org.gradle.api.internal.GradleInternal; import org.gradle.api.internal.MutationGuards; import org.gradle.api.internal.ProcessOperations; -import org.gradle.api.internal.ReflectiveNamedDomainObjectFactory; import org.gradle.api.internal.artifacts.Module; import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.DefaultProjectLayout; import org.gradle.api.internal.file.FileOperations; import org.gradle.api.internal.file.FileResolver; @@ -1318,23 +1316,17 @@ public Object passThrough(Object object) { @Override public NamedDomainObjectContainer container(Class type) { - InstantiatorFactory instantiatorFactory = getServices().get(InstantiatorFactory.class); - // TODO - this should also be using the decorating instantiator but cannot for backwards compatibility - ReflectiveNamedDomainObjectFactory objectFactory = new ReflectiveNamedDomainObjectFactory(type, instantiatorFactory.injectLenient(getServices())); - Instantiator instantiator = instantiatorFactory.decorateLenient(); - return instantiator.newInstance(FactoryNamedDomainObjectContainer.class, type, instantiator, new DynamicPropertyNamer(), objectFactory, MutationGuards.of(getProjectConfigurator()), services.get(CollectionCallbackActionDecorator.class)); + return getServices().get(DomainObjectCollectionFactory.class).newNamedDomainObjectContainer(type); } @Override public NamedDomainObjectContainer container(Class type, NamedDomainObjectFactory factory) { - Instantiator instantiator = getServices().get(InstantiatorFactory.class).decorateLenient(); - return instantiator.newInstance(FactoryNamedDomainObjectContainer.class, type, instantiator, new DynamicPropertyNamer(), factory, MutationGuards.of(getProjectConfigurator()), services.get(CollectionCallbackActionDecorator.class)); + return getServices().get(DomainObjectCollectionFactory.class).newNamedDomainObjectContainer(type, factory); } @Override public NamedDomainObjectContainer container(Class type, Closure factoryClosure) { - Instantiator instantiator = getServices().get(InstantiatorFactory.class).decorateLenient(); - return instantiator.newInstance(FactoryNamedDomainObjectContainer.class, type, instantiator, new DynamicPropertyNamer(), factoryClosure, MutationGuards.of(getProjectConfigurator()), services.get(CollectionCallbackActionDecorator.class)); + return getServices().get(DomainObjectCollectionFactory.class).newNamedDomainObjectContainer(type, factoryClosure); } @Override diff --git a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GlobalScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GlobalScopeServices.java index 778398941dbf..60eb6cde9d56 100755 --- a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GlobalScopeServices.java +++ b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GlobalScopeServices.java @@ -19,8 +19,12 @@ import com.google.common.collect.Iterables; import org.gradle.api.execution.internal.DefaultTaskInputsListener; import org.gradle.api.execution.internal.TaskInputsListener; +import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.MutationGuards; import org.gradle.api.internal.StartParameterInternal; import org.gradle.api.internal.cache.StringInterner; +import org.gradle.api.internal.collections.DefaultDomainObjectCollectionFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.DefaultFilePropertyFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.file.FilePropertyFactory; @@ -246,14 +250,19 @@ FilePropertyFactory createFilePropertyFactory(FileResolver fileResolver) { return new DefaultFilePropertyFactory(fileResolver); } - ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry services, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FileCollectionFactory fileCollectionFactory, FilePropertyFactory filePropertyFactory) { + ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry services, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FileCollectionFactory fileCollectionFactory, DomainObjectCollectionFactory domainObjectCollectionFactory) { return new DefaultObjectFactory( instantiatorFactory.injectAndDecorate(services), NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, - filePropertyFactory, - fileCollectionFactory); + new DefaultFilePropertyFactory(fileResolver), + fileCollectionFactory, + domainObjectCollectionFactory); + } + + DomainObjectCollectionFactory createDomainObjectCollectionFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry services) { + return new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, CollectionCallbackActionDecorator.NOOP, MutationGuards.identity()); } ProviderFactory createProviderFactory() { diff --git a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GradleScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GradleScopeServices.java index 1886c62424c1..d9340db9153b 100644 --- a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GradleScopeServices.java +++ b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/GradleScopeServices.java @@ -21,6 +21,7 @@ import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.GradleInternal; import org.gradle.api.internal.artifacts.dsl.dependencies.ProjectFinder; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.FileResolver; import org.gradle.api.internal.plugins.DefaultPluginManager; import org.gradle.api.internal.plugins.ImperativeOnlyPluginTarget; @@ -260,9 +261,9 @@ PluginRegistry createPluginRegistry(PluginRegistry parentRegistry) { return parentRegistry.createChild(get(GradleInternal.class).getClassLoaderScope()); } - PluginManagerInternal createPluginManager(Instantiator instantiator, GradleInternal gradleInternal, PluginRegistry pluginRegistry, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator) { + PluginManagerInternal createPluginManager(Instantiator instantiator, GradleInternal gradleInternal, PluginRegistry pluginRegistry, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { PluginTarget target = new ImperativeOnlyPluginTarget(gradleInternal); - return instantiator.newInstance(DefaultPluginManager.class, pluginRegistry, instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator); + return instantiator.newInstance(DefaultPluginManager.class, pluginRegistry, instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator, domainObjectCollectionFactory); } FileContentCacheFactory createFileContentCacheFactory(FileContentCacheFactory globalCacheFactory, ListenerManager listenerManager, FileSystemSnapshotter fileSystemSnapshotter, CacheRepository cacheRepository, InMemoryCacheDecoratorFactory inMemoryCacheDecoratorFactory, Gradle gradle, WellKnownFileLocations wellKnownFileLocations) { diff --git a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/ProjectScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/ProjectScopeServices.java index e83fd26d1645..467af8c12054 100644 --- a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/ProjectScopeServices.java +++ b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/ProjectScopeServices.java @@ -21,11 +21,14 @@ import org.gradle.api.component.SoftwareComponentContainer; import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.DomainObjectContext; +import org.gradle.api.internal.MutationGuards; import org.gradle.api.internal.artifacts.DependencyManagementServices; import org.gradle.api.internal.artifacts.Module; import org.gradle.api.internal.artifacts.ProjectBackedModule; import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider; import org.gradle.api.internal.artifacts.dsl.dependencies.ProjectFinder; +import org.gradle.api.internal.collections.DefaultDomainObjectCollectionFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.component.ComponentRegistry; import org.gradle.api.internal.component.DefaultSoftwareComponentContainer; import org.gradle.api.internal.file.BaseDirFileResolver; @@ -183,13 +186,13 @@ protected ToolingModelBuilderRegistry decorateToolingModelRegistry(ToolingModelB return new DefaultToolingModelBuilderRegistry(buildOperationExecutor, projectStateRegistry, buildScopedToolingModelBuilders); } - protected PluginManagerInternal createPluginManager(Instantiator instantiator, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator) { + protected PluginManagerInternal createPluginManager(Instantiator instantiator, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { PluginTarget target = new RuleBasedPluginTarget( project, get(ModelRuleExtractor.class), get(ModelRuleSourceDetector.class) ); - return instantiator.newInstance(DefaultPluginManager.class, get(PluginRegistry.class), instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator); + return instantiator.newInstance(DefaultPluginManager.class, get(PluginRegistry.class), instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator, domainObjectCollectionFactory); } protected ITaskFactory createTaskFactory(ITaskFactory parentFactory, TaskScheme taskScheme) { @@ -312,9 +315,15 @@ protected FileCollectionFactory createFileCollectionFactory(PathToFileResolver f return new DefaultFileCollectionFactory(fileResolver, taskResolver); } - protected ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory) { - Instantiator instantiator = instantiatorFactory.injectAndDecorate(ProjectScopeServices.this); - return new DefaultObjectFactory(instantiator, NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, filePropertyFactory, fileCollectionFactory); + protected ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory, DomainObjectCollectionFactory domainObjectCollectionFactory) { + ServiceRegistry services = ProjectScopeServices.this; + Instantiator instantiator = instantiatorFactory.injectAndDecorate(services); + return new DefaultObjectFactory(instantiator, NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, filePropertyFactory, fileCollectionFactory, domainObjectCollectionFactory); + } + + protected DomainObjectCollectionFactory createDomainObjectCollectionFactory(InstantiatorFactory instantiatorFactory, CollectionCallbackActionDecorator collectionCallbackActionDecorator, CrossProjectConfigurator projectConfigurator) { + ServiceRegistry services = ProjectScopeServices.this; + return new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, collectionCallbackActionDecorator, MutationGuards.of(projectConfigurator)); } } diff --git a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/SettingsScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/SettingsScopeServices.java index 919046fe395c..7fb1d49c3256 100644 --- a/subprojects/core/src/main/java/org/gradle/internal/service/scopes/SettingsScopeServices.java +++ b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/SettingsScopeServices.java @@ -20,6 +20,7 @@ import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.GradleInternal; import org.gradle.api.internal.SettingsInternal; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.BaseDirFileResolver; import org.gradle.api.internal.file.FileResolver; import org.gradle.api.internal.plugins.DefaultPluginManager; @@ -63,9 +64,9 @@ protected PluginRegistry createPluginRegistry(PluginRegistry parentRegistry) { return parentRegistry.createChild(settings.getClassLoaderScope()); } - protected PluginManagerInternal createPluginManager(Instantiator instantiator, PluginRegistry pluginRegistry, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator) { + protected PluginManagerInternal createPluginManager(Instantiator instantiator, PluginRegistry pluginRegistry, InstantiatorFactory instantiatorFactory, BuildOperationExecutor buildOperationExecutor, UserCodeApplicationContext userCodeApplicationContext, CollectionCallbackActionDecorator decorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { PluginTarget target = new ImperativeOnlyPluginTarget(settings); - return instantiator.newInstance(DefaultPluginManager.class, pluginRegistry, instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator); + return instantiator.newInstance(DefaultPluginManager.class, pluginRegistry, instantiatorFactory.inject(this), target, buildOperationExecutor, userCodeApplicationContext, decorator, domainObjectCollectionFactory); } protected ProjectDescriptorRegistry createProjectDescriptorRegistry() { diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/model/DefaultObjectFactoryTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/model/DefaultObjectFactoryTest.groovy index 4850052a1cc6..2d2f692f7c90 100644 --- a/subprojects/core/src/test/groovy/org/gradle/api/internal/model/DefaultObjectFactoryTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/model/DefaultObjectFactoryTest.groovy @@ -16,6 +16,7 @@ package org.gradle.api.internal.model +import org.gradle.api.internal.collections.DomainObjectCollectionFactory import org.gradle.api.internal.file.FileCollectionFactory import org.gradle.api.internal.file.FilePropertyFactory import org.gradle.api.internal.file.FileResolver @@ -26,7 +27,7 @@ import spock.lang.Unroll class DefaultObjectFactoryTest extends Specification { - def factory = new DefaultObjectFactory(Stub(Instantiator), Stub(NamedObjectInstantiator), Stub(FileResolver), Stub(DirectoryFileTreeFactory), Stub(FilePropertyFactory), Stub(FileCollectionFactory)) + def factory = new DefaultObjectFactory(Stub(Instantiator), Stub(NamedObjectInstantiator), Stub(FileResolver), Stub(DirectoryFileTreeFactory), Stub(FilePropertyFactory), Stub(FileCollectionFactory), Stub(DomainObjectCollectionFactory)) def "property has no value"() { expect: diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginContainerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginContainerTest.groovy index 8dbc2d43a9a2..f431d1d58f8a 100644 --- a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginContainerTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginContainerTest.groovy @@ -37,7 +37,7 @@ class DefaultPluginContainerTest extends Specification { def pluginRegistry = new DefaultPluginRegistry(pluginInspector, scope(classLoader)) def target = Mock(PluginTarget) def instantiator = TestUtil.instantiatorFactory().inject() - def pluginManager = new DefaultPluginManager(pluginRegistry, instantiator, target, new TestBuildOperationExecutor(), new DefaultUserCodeApplicationContext(), CollectionCallbackActionDecorator.NOOP) + def pluginManager = new DefaultPluginManager(pluginRegistry, instantiator, target, new TestBuildOperationExecutor(), new DefaultUserCodeApplicationContext(), CollectionCallbackActionDecorator.NOOP, TestUtil.domainObjectCollectionFactory()) @Subject def container = pluginManager.pluginContainer diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginManagerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginManagerTest.groovy index 78c8333c536b..06388820eab5 100644 --- a/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginManagerTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginManagerTest.groovy @@ -38,7 +38,7 @@ class DefaultPluginManagerTest extends Specification { } def registry = new DefaultPluginRegistry(new PluginInspector(new ModelRuleSourceDetector()), classLoaderScope) def target = Mock(PluginTarget) - def manager = new DefaultPluginManager(registry, TestUtil.instantiatorFactory().inject(), target, new TestBuildOperationExecutor(), new DefaultUserCodeApplicationContext(), CollectionCallbackActionDecorator.NOOP) + def manager = new DefaultPluginManager(registry, TestUtil.instantiatorFactory().inject(), target, new TestBuildOperationExecutor(), new DefaultUserCodeApplicationContext(), CollectionCallbackActionDecorator.NOOP, TestUtil.domainObjectCollectionFactory()) Class rulesClass Class hybridClass diff --git a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy index f04b191ae99f..8186bf1dbd8c 100644 --- a/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/api/internal/project/DefaultProjectTest.groovy @@ -42,6 +42,7 @@ import org.gradle.api.internal.ProcessOperations import org.gradle.api.internal.artifacts.Module import org.gradle.api.internal.artifacts.ProjectBackedModule import org.gradle.api.internal.artifacts.configurations.DependencyMetaDataProvider +import org.gradle.api.internal.collections.DomainObjectCollectionFactory import org.gradle.api.internal.file.DefaultProjectLayout import org.gradle.api.internal.file.FileCollectionFactory import org.gradle.api.internal.file.FileOperations @@ -204,10 +205,11 @@ class DefaultProjectTest extends Specification { serviceRegistryMock.get((Type) PluginManagerInternal) >> pluginManager serviceRegistryMock.get((Type) TextResourceLoader) >> textResourceLoader serviceRegistryMock.get(ManagedProxyFactory) >> managedProxyFactory - serviceRegistryMock.get(AttributesSchema) >> attributesSchema - serviceRegistryMock.get(BuildOperationExecutor) >> buildOperationExecutor - serviceRegistryMock.get((Type) ListenerBuildOperationDecorator) >> listenerBuildOperationDecorator - serviceRegistryMock.get((Type) CrossProjectConfigurator) >> crossProjectConfigurator + serviceRegistryMock.get(AttributesSchema) >> attributesSchema + serviceRegistryMock.get(BuildOperationExecutor) >> buildOperationExecutor + serviceRegistryMock.get((Type) ListenerBuildOperationDecorator) >> listenerBuildOperationDecorator + serviceRegistryMock.get((Type) CrossProjectConfigurator) >> crossProjectConfigurator + serviceRegistryMock.get(DomainObjectCollectionFactory) >> TestUtil.domainObjectCollectionFactory() pluginManager.getPluginContainer() >> pluginContainer serviceRegistryMock.get((Type) DeferredProjectConfiguration) >> Stub(DeferredProjectConfiguration) diff --git a/subprojects/core/src/test/groovy/org/gradle/util/NameValidatorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/NameValidatorTest.groovy index 4c848addb433..c59b9b1676dd 100644 --- a/subprojects/core/src/test/groovy/org/gradle/util/NameValidatorTest.groovy +++ b/subprojects/core/src/test/groovy/org/gradle/util/NameValidatorTest.groovy @@ -46,7 +46,7 @@ class NameValidatorTest extends Specification { @Shared def domainObjectContainersWithValidation = [ ["artifact types", new DefaultArtifactTypeContainer(TestUtil.instantiatorFactory().decorateLenient(), AttributeTestUtil.attributesFactory(), CollectionCallbackActionDecorator.NOOP)], - ["configurations", new DefaultConfigurationContainer(null, TestUtil.instantiatorFactory().decorateLenient(), domainObjectContext(), Mock(ListenerManager), null, null, null, null, Mock(FileCollectionFactory), null, null, null, null, null, AttributeTestUtil.attributesFactory(), null, null, null, null, Stub(DocumentationRegistry), CollectionCallbackActionDecorator.NOOP, null)], + ["configurations", new DefaultConfigurationContainer(null, TestUtil.instantiatorFactory().decorateLenient(), domainObjectContext(), Mock(ListenerManager), null, null, null, null, Mock(FileCollectionFactory), null, null, null, null, null, AttributeTestUtil.attributesFactory(), null, null, null, null, Stub(DocumentationRegistry), CollectionCallbackActionDecorator.NOOP, null, TestUtil.domainObjectCollectionFactory())], ["flavors", new DefaultFlavorContainer(TestUtil.instantiatorFactory().decorateLenient(), CollectionCallbackActionDecorator.NOOP)], ["source sets", new DefaultSourceSetContainer(TestFiles.resolver(), null, TestUtil.instantiatorFactory().decorateLenient(), TestUtil.objectFactory(), CollectionCallbackActionDecorator.NOOP)] ] diff --git a/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy index 1f31a911473a..808554b4a317 100644 --- a/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy +++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy @@ -17,7 +17,11 @@ package org.gradle.util import org.gradle.api.Task +import org.gradle.api.internal.CollectionCallbackActionDecorator import org.gradle.api.internal.FeaturePreviews +import org.gradle.api.internal.MutationGuards +import org.gradle.api.internal.collections.DefaultDomainObjectCollectionFactory +import org.gradle.api.internal.collections.DomainObjectCollectionFactory import org.gradle.api.internal.file.DefaultFilePropertyFactory import org.gradle.api.internal.file.FileResolver import org.gradle.api.internal.file.TestFiles @@ -33,6 +37,7 @@ import org.gradle.internal.instantiation.DefaultInstantiatorFactory import org.gradle.internal.instantiation.InjectAnnotationHandler import org.gradle.internal.instantiation.InstantiatorFactory import org.gradle.internal.service.DefaultServiceRegistry +import org.gradle.internal.service.ServiceRegistry import org.gradle.test.fixtures.file.TestDirectoryProvider import org.gradle.test.fixtures.file.TestFile import org.gradle.testfixtures.ProjectBuilder @@ -44,6 +49,7 @@ import static org.gradle.api.internal.FeaturePreviews.Feature.GRADLE_METADATA class TestUtil { public static final Closure TEST_CLOSURE = {} private static InstantiatorFactory instantiatorFactory + private static ServiceRegistry services private final File rootDir @@ -61,6 +67,10 @@ class TestUtil { return instantiatorFactory } + static DomainObjectCollectionFactory domainObjectCollectionFactory() { + return new DefaultDomainObjectCollectionFactory(instantiatorFactory(), services(), CollectionCallbackActionDecorator.NOOP, MutationGuards.identity()) + } + static ObjectFactory objectFactory() { return objFactory(TestFiles.resolver()) } @@ -70,10 +80,16 @@ class TestUtil { } private static ObjectFactory objFactory(FileResolver fileResolver) { - DefaultServiceRegistry services = new DefaultServiceRegistry() - services.add(ProviderFactory, new DefaultProviderFactory()) - services.add(InstantiatorFactory, instantiatorFactory()) - return new DefaultObjectFactory(instantiatorFactory().injectAndDecorate(services), NamedObjectInstantiator.INSTANCE, fileResolver, TestFiles.directoryFileTreeFactory(), new DefaultFilePropertyFactory(fileResolver), TestFiles.fileCollectionFactory()) + return new DefaultObjectFactory(instantiatorFactory().injectAndDecorate(services()), NamedObjectInstantiator.INSTANCE, fileResolver, TestFiles.directoryFileTreeFactory(), new DefaultFilePropertyFactory(fileResolver), TestFiles.fileCollectionFactory(), domainObjectCollectionFactory()) + } + + private static ServiceRegistry services() { + if (services == null) { + services = new DefaultServiceRegistry() + services.add(ProviderFactory, new DefaultProviderFactory()) + services.add(InstantiatorFactory, instantiatorFactory()) + } + return services } static NamedObjectInstantiator objectInstantiator() { diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java index 091a6ca63770..bce08e7f5325 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/DefaultDependencyManagementServices.java @@ -93,6 +93,7 @@ import org.gradle.api.internal.attributes.AttributesSchemaInternal; import org.gradle.api.internal.attributes.DefaultAttributesSchema; import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.component.ComponentTypeRegistry; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.file.FileResolver; @@ -465,7 +466,8 @@ ConfigurationContainerInternal createConfigurationContainer(Instantiator instant ProjectStateRegistry projectStateRegistry, DocumentationRegistry documentationRegistry, CollectionCallbackActionDecorator callbackDecorator, - UserCodeApplicationContext userCodeApplicationContext) { + UserCodeApplicationContext userCodeApplicationContext, + DomainObjectCollectionFactory domainObjectCollectionFactory) { return instantiator.newInstance(DefaultConfigurationContainer.class, configurationResolver, instantiator, @@ -488,7 +490,8 @@ ConfigurationContainerInternal createConfigurationContainer(Instantiator instant projectStateRegistry, documentationRegistry, callbackDecorator, - userCodeApplicationContext + userCodeApplicationContext, + domainObjectCollectionFactory ); } diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java index 38ae463b6bbf..c3135b7e1c87 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfiguration.java @@ -52,7 +52,6 @@ import org.gradle.api.attributes.AttributeContainer; import org.gradle.api.capabilities.Capability; import org.gradle.api.file.FileCollection; -import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.CompositeDomainObjectSet; import org.gradle.api.internal.DefaultDomainObjectSet; import org.gradle.api.internal.DocumentationRegistry; @@ -81,6 +80,7 @@ import org.gradle.api.internal.attributes.ImmutableAttributeContainerWithErrorMessage; import org.gradle.api.internal.attributes.ImmutableAttributes; import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.AbstractFileCollection; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.file.FileCollectionInternal; @@ -217,8 +217,8 @@ public void validateMutation(MutationType type) { private final FileCollection intrinsicFiles; private final DisplayName displayName; - private CollectionCallbackActionDecorator callbackActionDecorator; private UserCodeApplicationContext userCodeApplicationContext; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; private Action beforeLocking; @@ -239,12 +239,12 @@ public DefaultConfiguration(DomainObjectContext domainObjectContext, ImmutableAttributesFactory attributesFactory, RootComponentMetadataBuilder rootComponentMetadataBuilder, DocumentationRegistry documentationRegistry, - CollectionCallbackActionDecorator callbackDecorator, UserCodeApplicationContext userCodeApplicationContext, - DomainObjectProjectStateHandler domainObjectProjectStateHandler + DomainObjectProjectStateHandler domainObjectProjectStateHandler, + DomainObjectCollectionFactory domainObjectCollectionFactory ) { - this.callbackActionDecorator = callbackDecorator; this.userCodeApplicationContext = userCodeApplicationContext; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; this.identityPath = domainObjectContext.identityPath(name); this.name = name; this.configurationsProvider = configurationsProvider; @@ -270,20 +270,20 @@ public DefaultConfiguration(DomainObjectContext domainObjectContext, displayName = Describables.memoize(new ConfigurationDescription(identityPath)); - this.ownDependencies = new DefaultDomainObjectSet(Dependency.class, callbackDecorator); + this.ownDependencies = (DefaultDomainObjectSet)domainObjectCollectionFactory.newDomainObjectSet(Dependency.class); this.ownDependencies.beforeCollectionChanges(validateMutationType(this, MutationType.DEPENDENCIES)); - this.ownDependencyConstraints = new DefaultDomainObjectSet(DependencyConstraint.class, callbackDecorator); + this.ownDependencyConstraints = (DefaultDomainObjectSet) domainObjectCollectionFactory.newDomainObjectSet(DependencyConstraint.class); this.ownDependencyConstraints.beforeCollectionChanges(validateMutationType(this, MutationType.DEPENDENCIES)); this.dependencies = new DefaultDependencySet(Describables.of(displayName, "dependencies"), this, ownDependencies); this.dependencyConstraints = new DefaultDependencyConstraintSet(Describables.of(displayName, "dependency constraints"), ownDependencyConstraints); - this.ownArtifacts = new DefaultDomainObjectSet(PublishArtifact.class, callbackDecorator); + this.ownArtifacts = (DefaultDomainObjectSet)domainObjectCollectionFactory.newDomainObjectSet(PublishArtifact.class); this.ownArtifacts.beforeCollectionChanges(validateMutationType(this, MutationType.ARTIFACTS)); this.artifacts = new DefaultPublishArtifactSet(Describables.of(displayName, "artifacts"), ownArtifacts, fileCollectionFactory); - this.outgoing = instantiator.newInstance(DefaultConfigurationPublications.class, displayName, artifacts, new AllArtifactsProvider(), configurationAttributes, instantiator, artifactNotationParser, capabilityNotationParser, fileCollectionFactory, attributesFactory, callbackDecorator); + this.outgoing = instantiator.newInstance(DefaultConfigurationPublications.class, displayName, artifacts, new AllArtifactsProvider(), configurationAttributes, instantiator, artifactNotationParser, capabilityNotationParser, fileCollectionFactory, attributesFactory, domainObjectCollectionFactory); this.rootComponentMetadataBuilder = rootComponentMetadataBuilder; this.projectStateHandler = domainObjectProjectStateHandler; path = domainObjectContext.projectPath(name); @@ -766,7 +766,7 @@ private synchronized void initAllDependencies() { if (allDependencies != null) { return; } - inheritedDependencies = CompositeDomainObjectSet.create(Dependency.class, callbackActionDecorator, ownDependencies); + inheritedDependencies = domainObjectCollectionFactory.newDomainObjectSet(Dependency.class, ownDependencies); for (Configuration configuration : this.extendsFrom) { inheritedDependencies.addCollection(configuration.getAllDependencies()); } @@ -790,7 +790,7 @@ private synchronized void initAllDependencyConstraints() { if (allDependencyConstraints != null) { return; } - inheritedDependencyConstraints = CompositeDomainObjectSet.create(DependencyConstraint.class, callbackActionDecorator, ownDependencyConstraints); + inheritedDependencyConstraints = domainObjectCollectionFactory.newDomainObjectSet(DependencyConstraint.class, ownDependencyConstraints); for (Configuration configuration : this.extendsFrom) { inheritedDependencyConstraints.addCollection(configuration.getAllDependencyConstraints()); } @@ -822,14 +822,14 @@ private synchronized void initAllArtifacts() { if (canBeMutated) { // If the configuration can still be mutated, we need to create a composite - inheritedArtifacts = CompositeDomainObjectSet.create(PublishArtifact.class, callbackActionDecorator, ownArtifacts); + inheritedArtifacts = domainObjectCollectionFactory.newDomainObjectSet(PublishArtifact.class, ownArtifacts); } for (Configuration configuration : this.extendsFrom) { PublishArtifactSet allArtifacts = configuration.getAllArtifacts(); if (inheritedArtifacts != null || !allArtifacts.isEmpty()) { if (inheritedArtifacts == null) { // This configuration cannot be mutated, but some parent configurations provide artifacts - inheritedArtifacts = CompositeDomainObjectSet.create(PublishArtifact.class, callbackActionDecorator, ownArtifacts); + inheritedArtifacts = domainObjectCollectionFactory.newDomainObjectSet(PublishArtifact.class, ownArtifacts); } inheritedArtifacts.addCollection(allArtifacts); } @@ -968,7 +968,7 @@ private DefaultConfiguration createCopy(Set dependencies, Set childResolutionStrategy = resolutionStrategy != null ? Factories.constant(resolutionStrategy.copy()) : resolutionStrategyFactory; DefaultConfiguration copiedConfiguration = instantiator.newInstance(DefaultConfiguration.class, domainObjectContext, newName, configurationsProvider, resolver, listenerManager, metaDataProvider, childResolutionStrategy, projectAccessListener, projectFinder, fileCollectionFactory, buildOperationExecutor, instantiator, artifactNotationParser, capabilityNotationParser, attributesFactory, - rootComponentMetadataBuilder, documentationRegistry, callbackActionDecorator, userCodeApplicationContext, projectStateHandler); + rootComponentMetadataBuilder, documentationRegistry, userCodeApplicationContext, projectStateHandler, domainObjectCollectionFactory); configurationsProvider.setTheOnlyConfiguration(copiedConfiguration); // state, cachedResolvedConfiguration, and extendsFrom intentionally not copied - must re-resolve copy // copying extendsFrom could mess up dependencies when copy was re-resolved diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainer.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainer.java index 085f649b7b2a..716555315fcb 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainer.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainer.java @@ -40,6 +40,7 @@ import org.gradle.api.internal.artifacts.ivyservice.resolutionstrategy.DefaultResolutionStrategy; import org.gradle.api.internal.artifacts.transform.DomainObjectProjectStateHandler; import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.project.ProjectStateRegistry; import org.gradle.api.internal.tasks.TaskResolver; @@ -78,6 +79,7 @@ public class DefaultConfigurationContainer extends AbstractValidatingNamedDomain private int detachedConfigurationDefaultNameCounter = 1; private final Factory resolutionStrategyFactory; private final DefaultRootComponentMetadataBuilder rootComponentMetadataBuilder; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; public DefaultConfigurationContainer(ConfigurationResolver resolver, final Instantiator instantiator, DomainObjectContext context, ListenerManager listenerManager, @@ -96,7 +98,8 @@ public DefaultConfigurationContainer(ConfigurationResolver resolver, ProjectStateRegistry projectStateRegistry, DocumentationRegistry documentationRegistry, CollectionCallbackActionDecorator callbackDecorator, - UserCodeApplicationContext userCodeApplicationContext) { + UserCodeApplicationContext userCodeApplicationContext, + DomainObjectCollectionFactory domainObjectCollectionFactory) { super(Configuration.class, instantiator, new Configuration.Namer(), callbackDecorator); this.resolver = resolver; this.instantiator = instantiator; @@ -108,6 +111,7 @@ public DefaultConfigurationContainer(ConfigurationResolver resolver, this.fileCollectionFactory = fileCollectionFactory; this.buildOperationExecutor = buildOperationExecutor; this.userCodeApplicationContext = userCodeApplicationContext; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; this.artifactNotationParser = new PublishArtifactNotationParserFactory(instantiator, dependencyMetaDataProvider, taskResolver).create(); this.capabilityNotationParser = new CapabilityNotationParserFactory(true).create(); this.attributesFactory = attributesFactory; @@ -126,7 +130,7 @@ public ResolutionStrategyInternal create() { protected Configuration doCreate(String name) { DefaultConfiguration configuration = instantiator.newInstance(DefaultConfiguration.class, context, name, this, resolver, listenerManager, dependencyMetaDataProvider, resolutionStrategyFactory, projectAccessListener, projectFinder, - fileCollectionFactory, buildOperationExecutor, instantiator, artifactNotationParser, capabilityNotationParser, attributesFactory, rootComponentMetadataBuilder, documentationRegistry, getEventRegister().getDecorator(), userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, context, projectFinder)); + fileCollectionFactory, buildOperationExecutor, instantiator, artifactNotationParser, capabilityNotationParser, attributesFactory, rootComponentMetadataBuilder, documentationRegistry, userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, context, projectFinder), domainObjectCollectionFactory); configuration.addMutationValidator(rootComponentMetadataBuilder.getValidator()); return configuration; } @@ -159,7 +163,7 @@ public ConfigurationInternal detachedConfiguration(Dependency... dependencies) { context, name, detachedConfigurationsProvider, resolver, listenerManager, dependencyMetaDataProvider, resolutionStrategyFactory, projectAccessListener, projectFinder, fileCollectionFactory, buildOperationExecutor, instantiator, artifactNotationParser, capabilityNotationParser, attributesFactory, - rootComponentMetadataBuilder.withConfigurationsProvider(detachedConfigurationsProvider), documentationRegistry, getEventRegister().getDecorator(), userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, context, projectFinder)); + rootComponentMetadataBuilder.withConfigurationsProvider(detachedConfigurationsProvider), documentationRegistry, userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, context, projectFinder), domainObjectCollectionFactory); DomainObjectSet detachedDependencies = detachedConfiguration.getDependencies(); for (Dependency dependency : dependencies) { detachedDependencies.add(dependency.copy()); diff --git a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java index 815e93f13f96..88ecb673284b 100644 --- a/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java +++ b/subprojects/dependency-management/src/main/java/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublications.java @@ -30,11 +30,10 @@ import org.gradle.api.artifacts.PublishArtifactSet; import org.gradle.api.attributes.AttributeContainer; import org.gradle.api.capabilities.Capability; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.FactoryNamedDomainObjectContainer; import org.gradle.api.internal.artifacts.ConfigurationVariantInternal; import org.gradle.api.internal.attributes.AttributeContainerInternal; import org.gradle.api.internal.attributes.ImmutableAttributesFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.internal.DisplayName; import org.gradle.internal.reflect.Instantiator; @@ -56,8 +55,8 @@ public class DefaultConfigurationPublications implements ConfigurationPublicatio private final NotationParser capabilityNotationParser; private final FileCollectionFactory fileCollectionFactory; private final ImmutableAttributesFactory attributesFactory; - private CollectionCallbackActionDecorator collectionCallbackActionDecorator; - private FactoryNamedDomainObjectContainer variants; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; + private NamedDomainObjectContainer variants; private ConfigurationVariantFactory variantFactory; private List capabilities; private boolean canCreate = true; @@ -71,7 +70,7 @@ public DefaultConfigurationPublications(DisplayName displayName, NotationParser capabilityNotationParser, FileCollectionFactory fileCollectionFactory, ImmutableAttributesFactory attributesFactory, - CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + DomainObjectCollectionFactory domainObjectCollectionFactory) { this.displayName = displayName; this.artifacts = artifacts; this.allArtifacts = allArtifacts; @@ -81,7 +80,7 @@ public DefaultConfigurationPublications(DisplayName displayName, this.capabilityNotationParser = capabilityNotationParser; this.fileCollectionFactory = fileCollectionFactory; this.attributesFactory = attributesFactory; - this.collectionCallbackActionDecorator = collectionCallbackActionDecorator; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; this.attributes = attributesFactory.mutable(parentAttributes); } @@ -155,7 +154,7 @@ public NamedDomainObjectContainer getVariants() { if (variants == null) { // Create variants container only as required variantFactory = new ConfigurationVariantFactory(); - variants = new FactoryNamedDomainObjectContainer(ConfigurationVariant.class, instantiator, variantFactory, collectionCallbackActionDecorator); + variants = domainObjectCollectionFactory.newNamedDomainObjectContainer(ConfigurationVariant.class, variantFactory); } return variants; } @@ -196,7 +195,7 @@ private class ConfigurationVariantFactory implements NamedDomainObjectFactory artifactNotationParser, FileCollectionFactory fileCollectionFactory, ImmutableAttributesFactory cache, - CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + DomainObjectCollectionFactory domainObjectCollectionFactory) { this.parentDisplayName = parentDisplayName; this.name = name; attributes = cache.mutable(parentAttributes); this.artifactNotationParser = artifactNotationParser; - artifacts = new DefaultPublishArtifactSet(getAsDescribable(), new DefaultDomainObjectSet(PublishArtifact.class, collectionCallbackActionDecorator), fileCollectionFactory); + artifacts = new DefaultPublishArtifactSet(getAsDescribable(), domainObjectCollectionFactory.newDomainObjectSet(PublishArtifact.class), fileCollectionFactory); } @Override diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerSpec.groovy index cfaf07466385..de5b005d1be4 100644 --- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerSpec.groovy +++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerSpec.groovy @@ -70,13 +70,13 @@ class DefaultConfigurationContainerSpec extends Specification { private DocumentationRegistry documentationRegistry = Mock() private UserCodeApplicationContext userCodeApplicationContext = Mock() - private CollectionCallbackActionDecorator domainObjectCollectioncallbackActionDecorator = Mock() + private CollectionCallbackActionDecorator domainObjectCollectionCallbackActionDecorator = Mock() def immutableAttributesFactory = AttributeTestUtil.attributesFactory() private DefaultConfigurationContainer configurationContainer = new DefaultConfigurationContainer(resolver, instantiator, domainObjectContext, listenerManager, metaDataProvider, - projectAccessListener, projectFinder, metaDataBuilder, fileCollectionFactory, globalSubstitutionRules, vcsMappingsInternal, componentIdentifierFactory, buildOperationExecutor, taskResolver, - immutableAttributesFactory, moduleIdentifierFactory, componentSelectorConverter, dependencyLockingProvider, projectStateRegistry, documentationRegistry, - domainObjectCollectioncallbackActionDecorator, userCodeApplicationContext) + projectAccessListener, projectFinder, metaDataBuilder, fileCollectionFactory, globalSubstitutionRules, vcsMappingsInternal, componentIdentifierFactory, buildOperationExecutor, taskResolver, + immutableAttributesFactory, moduleIdentifierFactory, componentSelectorConverter, dependencyLockingProvider, projectStateRegistry, documentationRegistry, + domainObjectCollectionCallbackActionDecorator, userCodeApplicationContext, TestUtil.domainObjectCollectionFactory()) def "adds and gets"() { 1 * domainObjectContext.identityPath("compile") >> Path.path(":build:compile") diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerTest.groovy index d1361670e9fb..e2222b949a88 100644 --- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerTest.groovy +++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationContainerTest.groovy @@ -76,7 +76,7 @@ class DefaultConfigurationContainerTest extends Specification { listenerManager, metaDataProvider, projectAccessListener, projectFinder, metaDataBuilder, TestFiles.fileCollectionFactory(), globalSubstitutionRules, vcsMappingsInternal, componentIdentifierFactory, buildOperationExecutor, taskResolver, immutableAttributesFactory, moduleIdentifierFactory, componentSelectorConverter, lockingProvider, projectStateRegistry, - documentationRegistry, callbackActionDecorator, userCodeApplicationContext) + documentationRegistry, callbackActionDecorator, userCodeApplicationContext, TestUtil.domainObjectCollectionFactory()) def addsNewConfigurationWhenConfiguringSelf() { when: diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublicationsTest.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublicationsTest.groovy index 2c24444c75da..b88b00fb3db0 100644 --- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublicationsTest.groovy +++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationPublicationsTest.groovy @@ -18,8 +18,6 @@ package org.gradle.api.internal.artifacts.configurations import org.gradle.api.artifacts.PublishArtifact import org.gradle.api.attributes.Attribute -import org.gradle.api.internal.CollectionCallbackActionDecorator -import org.gradle.api.internal.DefaultDomainObjectSet import org.gradle.api.internal.artifacts.DefaultPublishArtifactSet import org.gradle.api.internal.attributes.ImmutableAttributes import org.gradle.api.internal.file.TestFiles @@ -31,8 +29,8 @@ import spock.lang.Specification class DefaultConfigurationPublicationsTest extends Specification { def parentAttributes = ImmutableAttributes.EMPTY - def artifacts = new DefaultPublishArtifactSet("artifacts", new DefaultDomainObjectSet(PublishArtifact, CollectionCallbackActionDecorator.NOOP), TestFiles.fileCollectionFactory()) - def allArtifacts = new DefaultPublishArtifactSet("artifacts", new DefaultDomainObjectSet(PublishArtifact, CollectionCallbackActionDecorator.NOOP), TestFiles.fileCollectionFactory()) + def artifacts = new DefaultPublishArtifactSet("artifacts", TestUtil.domainObjectCollectionFactory().newDomainObjectSet(PublishArtifact), TestFiles.fileCollectionFactory()) + def allArtifacts = new DefaultPublishArtifactSet("artifacts", TestUtil.domainObjectCollectionFactory().newDomainObjectSet(PublishArtifact), TestFiles.fileCollectionFactory()) def artifactNotationParser = Stub(NotationParser) def capabilityNotationParser = Stub(NotationParser) def fileCollectionFactory = TestFiles.fileCollectionFactory() @@ -40,7 +38,7 @@ class DefaultConfigurationPublicationsTest extends Specification { def displayName = Describables.of("") def publications = new DefaultConfigurationPublications(displayName, artifacts, { allArtifacts - }, parentAttributes, TestUtil.instantiatorFactory().decorateLenient(), artifactNotationParser, capabilityNotationParser, fileCollectionFactory, attributesFactory, CollectionCallbackActionDecorator.NOOP) + }, parentAttributes, TestUtil.instantiatorFactory().decorateLenient(), artifactNotationParser, capabilityNotationParser, fileCollectionFactory, attributesFactory, TestUtil.domainObjectCollectionFactory()) def setup() { artifacts.whenObjectAdded { allArtifacts.add(it) } diff --git a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy index f56ee8ca4226..38f40dda6d94 100644 --- a/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy +++ b/subprojects/dependency-management/src/test/groovy/org/gradle/api/internal/artifacts/configurations/DefaultConfigurationSpec.groovy @@ -1759,8 +1759,7 @@ All Artifacts: def publishArtifactNotationParser = NotationParserBuilder.toType(ConfigurablePublishArtifact).toComposite() new DefaultConfiguration(domainObjectContext, confName, configurationsProvider, resolver, listenerManager, metaDataProvider, Factories.constant(resolutionStrategy), projectAccessListener, projectFinder, TestFiles.fileCollectionFactory(), - new TestBuildOperationExecutor(), instantiator, publishArtifactNotationParser, Stub(NotationParser), immutableAttributesFactory, rootComponentMetadataBuilder, Stub(DocumentationRegistry), - domainObjectCollectioncallbackActionDecorator, userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, domainObjectContext, projectFinder)) + new TestBuildOperationExecutor(), instantiator, publishArtifactNotationParser, Stub(NotationParser), immutableAttributesFactory, rootComponentMetadataBuilder, Stub(DocumentationRegistry), userCodeApplicationContext, new DomainObjectProjectStateHandler(projectStateRegistry, domainObjectContext, projectFinder), TestUtil.domainObjectCollectionFactory()) } private DefaultPublishArtifact artifact(String name) { diff --git a/subprojects/distributions/src/changes/accepted-public-api-changes.json b/subprojects/distributions/src/changes/accepted-public-api-changes.json index 4017e1002927..afc5ee79bbb0 100644 --- a/subprojects/distributions/src/changes/accepted-public-api-changes.json +++ b/subprojects/distributions/src/changes/accepted-public-api-changes.json @@ -1,3 +1,10 @@ { - "acceptedApiChanges": [] + "acceptedApiChanges": [ + { + "type": "org.gradle.platform.base.binary.BaseBinarySpec", + "member": "Method org.gradle.platform.base.binary.BaseBinarySpec.create(java.lang.Class,java.lang.Class,org.gradle.platform.base.internal.ComponentSpecIdentifier,org.gradle.model.internal.core.MutableModelNode,org.gradle.model.internal.core.MutableModelNode,org.gradle.internal.reflect.Instantiator,org.gradle.model.internal.core.NamedEntityInstantiator,org.gradle.api.internal.CollectionCallbackActionDecorator,org.gradle.api.internal.collections.DomainObjectCollectionFactory)", + "acceptation": "Change to internal factory method", + "changes": [] + } + ] } \ No newline at end of file diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 73d4690b8297..40eb70748a8a 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -36,6 +36,12 @@ TBD - honors dependencies on `@Input` properties. TBD - added `getLocationOnly()`. +## Building native software with Gradle + +All new C++ documentations including new user manual chapters for [building](userguide/building_cpp_projects.html) and [testing](userguide/cpp_testing.html) C++ projects, [DSL reference for C++ components](dsl/index.html#N10808), [C++ plugins reference chapters](userguide/plugin_reference.html#native_languages) and [Visual Studio and Xcode IDE plugins reference chapters](userguide/plugin_reference.html#ide_integration). +The [C++ guides](https://gradle.org/guides/?q=Native) were also improved to reflect all the new features available to C++ developers. +See more information about the [Gradle native project](https://github.com/gradle/gradle-native/blob/master/docs/RELEASE-NOTES.md#changes-included-in-gradle-55). + ## Promoted features Promoted features are features that were incubating in previous versions of Gradle but are now supported and subject to backwards compatibility. See the User Manual section on the “[Feature Lifecycle](userguide/feature_lifecycle.html)” for more information. diff --git a/subprojects/docs/src/docs/userguide/building_cpp_projects.adoc b/subprojects/docs/src/docs/userguide/building_cpp_projects.adoc index e43efdb050c3..1f9f5cc788e4 100644 --- a/subprojects/docs/src/docs/userguide/building_cpp_projects.adoc +++ b/subprojects/docs/src/docs/userguide/building_cpp_projects.adoc @@ -1,4 +1,4 @@ -// Copyright 2018 the original author or authors. +// Copyright 2019 the original author or authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -65,8 +65,7 @@ You can find a list of them in the <> chapter. +Test sources are configured on each test suite script block. See <> chapter. [[sec:cpp_dependency_management_overview]] == Managing your dependencies @@ -118,7 +117,7 @@ As far as configurations go, the main ones of interest are: You can learn more about these and how they relate to one another in the native plugin reference chapter. -Be aware that the <> creates an additional configuration - `api` - for dependencies that are required for compiling and linking both the module and any modules that depend on it. +Be aware that the <> creates an additional configuration - `api` - for dependencies that are required for compiling and linking both the module and any modules that depend on it. We have only scratched the surface here, so we recommend that you read the dedicated dependency management chapters once you’re comfortable with the basics of building C++ projects with Gradle. @@ -157,7 +156,6 @@ In the future, Gradle will consider source and ABI compatibility when selecting Gradle has general support for the three major tool chains on major operating system: Clang footnote:[Installed with Xcode on macOS], GCC footnote:[Installed through Cygwin and MinGW for 32- and 64-bits architecture on Windows] and Visual C++ footnote:[Installed with Visual Studio 2010 to 2017] (Windows-only). GCC and Clang installed using Macports and Homebrew have been reported to work fine, but this isn’t tested continuously. -// TODO: Check to see if we use any headers ==== Windows To build on Windows, install a compatible version of Visual Studio[4]. @@ -258,19 +256,17 @@ The unique aspect of library projects is that they are used (or "consumed") by o That means the dependency metadata published with the binaries and headers - in the form of a Gradle Metadata - is crucial. In particular, consumers of your library should be able to distinguish between two different types of dependencies: those that are only required to compile your library and those that are also required to compile the consumer. -Gradle manages this distinction via the <>, which introduces an _api_ configuration in addition to the _implementation_ once covered in this chapter. +Gradle manages this distinction via the <>, which introduces an _api_ configuration in addition to the _implementation_ once covered in this chapter. If the types from a dependency appear as unresolved symbols of the static library or within the public headers then that dependency is exposed via your library’s public API and should, therefore, be added to the _api_ configuration. Otherwise, the dependency is an internal implementation detail and should be added to _implementation_. -// FIXME: Ensure the difference between API and implementation is explained -If you’re unsure of the difference between an API and implementation dependency, the <> chapter has a detailed explanation. +If you’re unsure of the difference between an API and implementation dependency, the <> chapter has a detailed explanation. In addition, you can see a basic, practical example of building a C++ library in the corresponding link:{guidesUrl}/building-cpp-libraries[guide]. [[sec:building_cpp_applications]] == Building C++ applications -// TODO: link to C++ application plugin reference chapter -See the C++ Application Plugin chapter for more details, but here’s a quick summary of what you get: +See the <> chapter for more details, but here’s a quick summary of what you get: * `install` create a directory containing everything needed to run it * Shell and Windows Batch scripts to start the application diff --git a/subprojects/docs/src/docs/userguide/cpp_application_plugin.adoc b/subprojects/docs/src/docs/userguide/cpp_application_plugin.adoc index 32c92c2f7582..97a7e05a76e0 100644 --- a/subprojects/docs/src/docs/userguide/cpp_application_plugin.adoc +++ b/subprojects/docs/src/docs/userguide/cpp_application_plugin.adoc @@ -91,30 +91,29 @@ Aggregates tasks that assemble the specific variant of this application. [[sec:cpp_application_lifecycle_tasks]] === Lifecycle Tasks -The {cpp} Application Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Application Plugin applies automatically: +The {cpp} Application Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Application Plugin applies automatically: `assemble` - Task (lifecycle):: Depends on: `linkDebug` :: Aggregate task that assembles the debug variant of the application for the current host (if present) in the project. -This task is added by the <>. +This task is added by the <>. `check` - Task (lifecycle):: Aggregate task that performs verification tasks, such as running the tests. Some plugins add their own verification task to `check`. -For example, the {cpp} Unit Test Plugin attaches a task to this lifecycle task to run tests. -This task is added by the <>. -// TODO: Add link to C++ Unit Test Plugin reference chapter +For example, the <> attaches a task to this lifecycle task to run tests. +This task is added by the <>. `build` - Task (lifecycle):: Depends on: `check`, `assemble` :: Aggregate tasks that perform a full build of the project. -This task is added by the <>. +This task is added by the <>. `clean` - Delete:: Deletes the build directory and everything in it, i.e. the path specified by the `Project.getBuildDir()` project property. -This task is added by the <>. +This task is added by the <>. [[sec:cpp_application_dependency_management]] == Dependency management diff --git a/subprojects/docs/src/docs/userguide/cpp_library_plugin.adoc b/subprojects/docs/src/docs/userguide/cpp_library_plugin.adoc index 11177a333337..28f0cbe83652 100644 --- a/subprojects/docs/src/docs/userguide/cpp_library_plugin.adoc +++ b/subprojects/docs/src/docs/userguide/cpp_library_plugin.adoc @@ -109,30 +109,29 @@ Aggregates tasks that assemble the specific variant of this library. [[sec:cpp_library_lifecycle_tasks]] === Lifecycle Tasks -The {cpp} Library Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Library Plugin applies automatically: +The {cpp} Library Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Library Plugin applies automatically: `assemble` - Task (lifecycle):: Depends on: `linkDebug` when linkage includes `shared` or `createDebug` otherwise. :: Aggregate task that assembles the debug variant of the shared library (if available) for the current host (if present) in the project. -This task is added by the <>. +This task is added by the <>. `check` - Task (lifecycle):: Aggregate task that performs verification tasks, such as running the tests. Some plugins add their own verification task to `check`. -For example, the {cpp} Unit Test Plugin attach his test task to this lifecycle task. -This task is added by the <>. -// TODO: Link to the C++ Unit Test Plugin reference chapter +For example, the <> attach his test task to this lifecycle task. +This task is added by the <>. `build` - Task (lifecycle):: Depends on: `check`, `assemble` :: Aggregate tasks that perform a full build of the project. -This task is added by the <>. +This task is added by the <>. `clean` - Delete:: Deletes the build directory and everything in it, i.e. the path specified by the `Project.getBuildDir()` project property. -This task is added by the <>. +This task is added by the <>. [[sec:cpp_library_dependency_management]] == Dependency management diff --git a/subprojects/docs/src/docs/userguide/cpp_plugins.adoc b/subprojects/docs/src/docs/userguide/cpp_plugins.adoc index f8e65afe12e9..f1b5b9b54b8a 100644 --- a/subprojects/docs/src/docs/userguide/cpp_plugins.adoc +++ b/subprojects/docs/src/docs/userguide/cpp_plugins.adoc @@ -1,3 +1,17 @@ +// Copyright 2019 the original author or authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + NOTE: We improved the {cpp} documentation and the content of <>. Please update your references. ++++ diff --git a/subprojects/docs/src/docs/userguide/cpp_testing.adoc b/subprojects/docs/src/docs/userguide/cpp_testing.adoc index 54e43fd113a5..bf04ea5d4947 100644 --- a/subprojects/docs/src/docs/userguide/cpp_testing.adoc +++ b/subprojects/docs/src/docs/userguide/cpp_testing.adoc @@ -1,4 +1,4 @@ -// Copyright 2018 the original author or authors. +// Copyright 2019 the original author or authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -36,10 +36,9 @@ In order to operate, the link:{groovyDslPath}/org.gradle.nativeplatform.test.tas * Where to find the built test executable (property: link:{groovyDslPath}/org.gradle.nativeplatform.test.tasks.RunTestExecutable.html#org.gradle.nativeplatform.test.tasks.RunTestExecutable:executable[RunTestExecutable.getExecutable()]) -// TODO: Adds link to C++ Unit Test Plugin reference chapter -When you’re using the C++ Unit Test Plugin you will automatically get the following: +When you’re using the <> you will automatically get the following: - * A dedicated `unitTest` extension for configuring test component and its variants + * A dedicated link:{groovyDslPath}/org.gradle.nativeplatform.test.cpp.CppTestSuite.html[unitTest] extension for configuring test component and its variants * A `run` task of type link:{groovyDslPath}/org.gradle.nativeplatform.test.tasks.RunTestExecutable.html[RunTestExecutable] that runs the test executable The test plugins configure the required pieces of information appropriately. diff --git a/subprojects/docs/src/docs/userguide/cpp_unit_test_plugin.adoc b/subprojects/docs/src/docs/userguide/cpp_unit_test_plugin.adoc index 8852f3a4bdca..0b1392476f44 100644 --- a/subprojects/docs/src/docs/userguide/cpp_unit_test_plugin.adoc +++ b/subprojects/docs/src/docs/userguide/cpp_unit_test_plugin.adoc @@ -86,12 +86,12 @@ Run the installed executable. [[sec:cpp_unit_test_lifecycle_tasks]] === Lifecycle Tasks -The {cpp} Unit Test Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Application Plugin applies automatically: +The {cpp} Unit Test Plugin attaches some of its tasks to the standard lifecycle tasks documented in the <> - which the {cpp} Application Plugin applies automatically: `assemble` - Task (lifecycle):: Aggregate task that assembles the debug variant of the tested component for the current host (if present) in the project. For example, the {cpp} Application Plugin and {cpp} Library Plugin attach their link and create tasks to this lifecycle task. -This task is added by the <>. +This task is added by the <>. `test` - Task (lifecycle):: Depends on: `runTest__Variant__` that most closely matches the build host @@ -103,17 +103,17 @@ Depends on: `test` :: Aggregate task that performs verification tasks, such as running the tests. Some plugins add their own verification task to `check`. -This task is added by the <>. +This task is added by the <>. `build` - Task (lifecycle):: Depends on: `check`, `assemble` :: Aggregate tasks that perform a full build of the project. -This task is added by the <>. +This task is added by the <>. `clean` - Delete:: Deletes the build directory and everything in it, i.e. the path specified by the `Project.getBuildDir()` project property. -This task is added by the <>. +This task is added by the <>. [[sec:cpp_unit_test_dependency_management]] == Dependency management diff --git a/subprojects/docs/src/docs/userguide/custom_plugins.adoc b/subprojects/docs/src/docs/userguide/custom_plugins.adoc index 9e87c6440ccf..a962700d624b 100644 --- a/subprojects/docs/src/docs/userguide/custom_plugins.adoc +++ b/subprojects/docs/src/docs/userguide/custom_plugins.adoc @@ -257,9 +257,15 @@ There are several services, such as `ObjectFactory`, that are available for inje [[sec:maintaining_multiple_domain_objects]] === Configuring a collection of objects -Gradle provides some utility classes for maintaining collections of objects, intended to work well with the Gradle DSL. One such type is link:{javadocPath}/org/gradle/api/NamedDomainObjectContainer.html[NamedDomainObjectContainer] which manages a set of objects. Gradle uses this type extensively throughout the API. For example, the `tasks` object used to manage the tasks of a project is a `NamedDomainObjectContainer`. +Gradle provides some utility classes for maintaining collections of objects, intended to work well with the Gradle DSL. +One such type is link:{javadocPath}/org/gradle/api/NamedDomainObjectContainer.html[NamedDomainObjectContainer] which manages a set of objects. +Gradle uses this type extensively throughout the API. +For example, the `tasks` object used to manage the tasks of a project is a `NamedDomainObjectContainer`. -You can create a container instance using the link:{javadocPath}/org/gradle/api/Project.html#container-java.lang.Class-[Project.container()] method. Services are available for injection into the elements of the container. See <>. for details. +You can create a container instance using the link:{javadocPath}/org/gradle/api/Project.html#container-java.lang.Class-[Project.container()] method. +You can also use link:{javadocPath}/org/gradle/api/model/ObjectFactory.html#container-java.lang.Class-[ObjectFactory.container()]. +Services are available for injection into the elements of the container. +See <>. for details. .Managing a collection of objects ==== @@ -267,6 +273,11 @@ include::sample[dir="userguide/customPlugins/customPluginWithDomainObjectContain include::sample[dir="userguide/customPlugins/customPluginWithDomainObjectContainer/kotlin",files="build.gradle.kts[]"] ==== +Another type is link:{javadocPath}/org/gradle/api/DomainObjectSet.html[DomainObjectSet] which maintains a simple set of objects. +Compared to the `NamedDomainObjectContainer`, the `DomainObjectSet` doesn't manage the objects in the collection. +They need to be created and added manually. +You can create an instance using link:{javadocPath}/org/gradle/api/model/ObjectFactory.html#domainObjectSet-java.lang.Class-[ObjectFactory.domainObjectSet()]. + ==== Output of **`gradle -q books`** [source.multi-language-sample,groovy] ---- diff --git a/subprojects/docs/src/docs/userguide/more_about_tasks.adoc b/subprojects/docs/src/docs/userguide/more_about_tasks.adoc index 4228e44a3f0d..e25cd7a01d88 100644 --- a/subprojects/docs/src/docs/userguide/more_about_tasks.adoc +++ b/subprojects/docs/src/docs/userguide/more_about_tasks.adoc @@ -206,7 +206,7 @@ include::sample[dir="userguide/tasks/taskConstructorArgs/onProject/kotlin",files [NOTE] .Prefer creating a task with constructor arguments using the TaskContainer ==== -It's recommended to use the <> APIs to improve configuration time. +It's recommended to use the <> APIs to improve configuration time. ==== In all circumstances, the values passed as constructor arguments must be non-null. diff --git a/subprojects/docs/src/docs/userguide/publishing_ivy.adoc b/subprojects/docs/src/docs/userguide/publishing_ivy.adoc index 246510554e9f..25f256782ffd 100644 --- a/subprojects/docs/src/docs/userguide/publishing_ivy.adoc +++ b/subprojects/docs/src/docs/userguide/publishing_ivy.adoc @@ -117,7 +117,7 @@ Sometimes it is desirable to publish the _resolved_ version instead. Example use cases: * A project uses dynamic versions for dependencies but prefers exposing the resolved version for a given release to its consumers. -* In combination with <>, you want to publish the locked versions. +* In combination with <>, you want to publish the locked versions. * A project leverages the rich versions constraints of Gradle, which have a lossy conversion to Ivy. Instead of relying on the conversion, it publishes the resolved versions. diff --git a/subprojects/docs/src/docs/userguide/publishing_maven.adoc b/subprojects/docs/src/docs/userguide/publishing_maven.adoc index 91444b60b7ac..8e04c2fb69ac 100644 --- a/subprojects/docs/src/docs/userguide/publishing_maven.adoc +++ b/subprojects/docs/src/docs/userguide/publishing_maven.adoc @@ -115,7 +115,7 @@ Sometimes it is desirable to publish the _resolved_ version instead. Example use cases: * A project uses dynamic versions for dependencies but prefers exposing the resolved version for a given release to its consumers. -* In combination with <>, you want to publish the locked versions. +* In combination with <>, you want to publish the locked versions. * A project leverages the rich versions constraints of Gradle, which have a lossy conversion to Maven. Instead of relying on the conversion, it publishes the resolved versions. diff --git a/subprojects/docs/src/samples/eclipse/kotlin/build.gradle.kts b/subprojects/docs/src/samples/eclipse/kotlin/build.gradle.kts index bc57748ed3ca..a9568095cfb0 100644 --- a/subprojects/docs/src/samples/eclipse/kotlin/build.gradle.kts +++ b/subprojects/docs/src/samples/eclipse/kotlin/build.gradle.kts @@ -63,7 +63,7 @@ eclipse.project.file.beforeMerged(Action { eclipse.wtp.facet.file.withXml(Action { fun Element.firstElement(predicate: Element.() -> Boolean) = childNodes - .let { children -> (0..children.length).map { children.item(it) } } + .run { (0 until length).map(::item) } .filterIsInstance() .first { it.predicate() } diff --git a/subprojects/docs/src/samples/idea/kotlin/build.gradle.kts b/subprojects/docs/src/samples/idea/kotlin/build.gradle.kts index 1e9630114bbc..4842c0ba5f58 100644 --- a/subprojects/docs/src/samples/idea/kotlin/build.gradle.kts +++ b/subprojects/docs/src/samples/idea/kotlin/build.gradle.kts @@ -57,7 +57,7 @@ idea.project.ipr { withXml(Action { fun Element.firstElement(predicate: (Element.() -> Boolean)) = childNodes - .let { children -> (0..children.length).map { children.item(it) } } + .run { (0 until length).map(::item) } .filterIsInstance() .first { it.predicate() } diff --git a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppApplication.java b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppApplication.java index 69134e29beb4..cbd885cba4b6 100644 --- a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppApplication.java +++ b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppApplication.java @@ -18,7 +18,6 @@ import org.gradle.api.Action; import org.gradle.api.artifacts.Configuration; -import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.Property; import org.gradle.internal.Describables; @@ -41,12 +40,12 @@ public class DefaultCppApplication extends DefaultCppComponent implements CppApp private final DefaultComponentDependencies dependencies; @Inject - public DefaultCppApplication(String name, ObjectFactory objectFactory, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public DefaultCppApplication(String name, ObjectFactory objectFactory) { super(name, objectFactory); this.objectFactory = objectFactory; this.developmentBinary = objectFactory.property(CppExecutable.class); this.dependencies = objectFactory.newInstance(DefaultComponentDependencies.class, getNames().withSuffix("implementation")); - this.mainVariant = new MainExecutableVariant(collectionCallbackActionDecorator); + this.mainVariant = new MainExecutableVariant(objectFactory); } public DefaultCppExecutable addExecutable(NativeVariantIdentity identity, CppPlatform targetPlatform, NativeToolChainInternal toolChain, PlatformToolProvider platformToolProvider) { diff --git a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppLibrary.java b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppLibrary.java index 52dea6b93136..a1c42d8a98d8 100644 --- a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppLibrary.java +++ b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/DefaultCppLibrary.java @@ -25,7 +25,6 @@ import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; import org.gradle.api.file.FileTree; -import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.artifacts.ArtifactAttributes; import org.gradle.api.internal.attributes.ImmutableAttributesFactory; import org.gradle.api.model.ObjectFactory; @@ -58,7 +57,7 @@ public class DefaultCppLibrary extends DefaultCppComponent implements CppLibrary private final DefaultLibraryDependencies dependencies; @Inject - public DefaultCppLibrary(String name, ObjectFactory objectFactory, ConfigurationContainer configurations, ImmutableAttributesFactory immutableAttributesFactory, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public DefaultCppLibrary(String name, ObjectFactory objectFactory, ConfigurationContainer configurations, ImmutableAttributesFactory immutableAttributesFactory) { super(name, objectFactory); this.objectFactory = objectFactory; this.developmentBinary = objectFactory.property(CppBinary.class); @@ -81,7 +80,7 @@ public DefaultCppLibrary(String name, ObjectFactory objectFactory, Configuration AttributeContainer publicationAttributes = immutableAttributesFactory.mutable(); publicationAttributes.attribute(Usage.USAGE_ATTRIBUTE, apiUsage); publicationAttributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactTypeDefinition.ZIP_TYPE); - mainVariant = new MainLibraryVariant("api", apiUsage, apiElements, publicationAttributes, collectionCallbackActionDecorator); + mainVariant = new MainLibraryVariant("api", apiUsage, apiElements, publicationAttributes, objectFactory); } public DefaultCppSharedLibrary addSharedLibrary(NativeVariantIdentity identity, CppPlatform targetPlatform, NativeToolChainInternal toolChain, PlatformToolProvider platformToolProvider) { diff --git a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainExecutableVariant.java b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainExecutableVariant.java index 45415cc6f5ce..f9f61631fa20 100644 --- a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainExecutableVariant.java +++ b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainExecutableVariant.java @@ -20,18 +20,17 @@ import org.gradle.api.DomainObjectSet; import org.gradle.api.component.ComponentWithVariants; import org.gradle.api.component.SoftwareComponent; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; import org.gradle.api.internal.component.SoftwareComponentInternal; import org.gradle.api.internal.component.UsageContext; +import org.gradle.api.model.ObjectFactory; import java.util.Set; public class MainExecutableVariant implements SoftwareComponentInternal, ComponentWithVariants { private final DomainObjectSet variants; - public MainExecutableVariant(CollectionCallbackActionDecorator collectionCallbackActionDecorator) { - variants = new DefaultDomainObjectSet(SoftwareComponent.class, collectionCallbackActionDecorator); + public MainExecutableVariant(ObjectFactory objectFactory) { + variants = objectFactory.domainObjectSet(SoftwareComponent.class); } @Override diff --git a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainLibraryVariant.java b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainLibraryVariant.java index 1caab831dd10..3836de2c8619 100644 --- a/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainLibraryVariant.java +++ b/subprojects/language-native/src/main/java/org/gradle/language/cpp/internal/MainLibraryVariant.java @@ -24,10 +24,9 @@ import org.gradle.api.attributes.Usage; import org.gradle.api.component.ComponentWithVariants; import org.gradle.api.component.SoftwareComponent; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; import org.gradle.api.internal.component.SoftwareComponentInternal; import org.gradle.api.internal.component.UsageContext; +import org.gradle.api.model.ObjectFactory; import java.util.LinkedHashSet; import java.util.Set; @@ -40,12 +39,12 @@ public class MainLibraryVariant implements ComponentWithVariants, SoftwareCompon private final DomainObjectSet variants; private final AttributeContainer attributeContainer; - public MainLibraryVariant(String name, Usage usage, Configuration dependencies, AttributeContainer attributeContainer, CollectionCallbackActionDecorator decorator) { + public MainLibraryVariant(String name, Usage usage, Configuration dependencies, AttributeContainer attributeContainer, ObjectFactory objectFactory) { this.name = name; this.usage = usage; this.dependencies = dependencies; this.attributeContainer = attributeContainer; - this.variants = new DefaultDomainObjectSet(SoftwareComponent.class, decorator); + this.variants = objectFactory.domainObjectSet(SoftwareComponent.class); } @Override diff --git a/subprojects/performance/src/performanceTest/groovy/org/gradle/performance/regression/corefeature/WorkerApiPerformanceTest.groovy b/subprojects/performance/src/performanceTest/groovy/org/gradle/performance/regression/corefeature/WorkerApiPerformanceTest.groovy index b8ae5710dd84..9cae06c0f38b 100644 --- a/subprojects/performance/src/performanceTest/groovy/org/gradle/performance/regression/corefeature/WorkerApiPerformanceTest.groovy +++ b/subprojects/performance/src/performanceTest/groovy/org/gradle/performance/regression/corefeature/WorkerApiPerformanceTest.groovy @@ -21,7 +21,7 @@ import spock.lang.Unroll class WorkerApiPerformanceTest extends AbstractCrossVersionPerformanceTest { def setup() { - runner.minimumVersion = '4.0' + runner.minimumVersion = '5.0' runner.targetVersions = ["5.5-20190515115345+0000"] runner.testProject = "workerApiProject" } @@ -29,7 +29,7 @@ class WorkerApiPerformanceTest extends AbstractCrossVersionPerformanceTest { @Unroll def "executing tasks with no isolation with work=#workItems / workers=#workers"() { given: - runner.tasksToRun = ['clean', 'noIsolation', "--outputSize=$workItems"] + runner.tasksToRun = ['clean', 'noIsolation', "-PoutputSize=$workItems"] runner.args = [ "--max-workers=$workers" ] when: @@ -53,7 +53,7 @@ class WorkerApiPerformanceTest extends AbstractCrossVersionPerformanceTest { @Unroll def "executing tasks with classloader isolation work=#workItems / workers=#workers"() { given: - runner.tasksToRun = ['clean', 'classloaderIsolation', "--outputSize=$workItems"] + runner.tasksToRun = ['clean', 'classloaderIsolation', "-PoutputSize=$workItems"] runner.args = [ "--max-workers=$workers" ] when: @@ -77,7 +77,7 @@ class WorkerApiPerformanceTest extends AbstractCrossVersionPerformanceTest { @Unroll def "executing tasks with process isolation work=#workItems / workers=#workers"() { given: - runner.tasksToRun = ['clean', 'classloaderIsolation', "--outputSize=$workItems"] + runner.tasksToRun = ['clean', 'classloaderIsolation', "-PoutputSize=$workItems"] runner.args = [ "--max-workers=$workers" ] when: diff --git a/subprojects/performance/src/templates/workerApiProject/build.gradle b/subprojects/performance/src/templates/workerApiProject/build.gradle index 9bd2c685ad1e..c780adc13d2a 100644 --- a/subprojects/performance/src/templates/workerApiProject/build.gradle +++ b/subprojects/performance/src/templates/workerApiProject/build.gradle @@ -1,3 +1 @@ -plugins { - id 'worker-plugin' -} +apply plugin: 'worker-plugin' diff --git a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/UnitOfWork.java b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/UnitOfWork.java index 49384e872923..ed487602f6d7 100644 --- a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/UnitOfWork.java +++ b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/UnitOfWork.java @@ -34,7 +34,7 @@ public UnitOfWork(int index, File outputFile) { @Override public void run() { try (FileWriter fw = new FileWriter(outputFile)) { - fw.append("index is " + index); + fw.append("index is " + index + "\n"); } catch (IOException e) { throw new RuntimeException("could not write to " + outputFile); } diff --git a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerPlugin.java b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerPlugin.java index 190ddb2c5375..9b516931300d 100644 --- a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerPlugin.java +++ b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerPlugin.java @@ -23,7 +23,7 @@ public class WorkerPlugin implements Plugin { @Override - public void apply(Project project) { + public void apply(final Project project) { project.getPluginManager().apply("base"); project.getTasks().create("noIsolation", WorkerTask.class); @@ -40,5 +40,14 @@ public void execute(WorkerTask workerTask) { workerTask.setIsolationMode(IsolationMode.PROCESS); } }); + + project.getTasks().withType(WorkerTask.class, new Action() { + @Override + public void execute(WorkerTask workerTask) { + Object maybeOutputSize = project.findProperty("outputSize"); + int outputSize = Integer.valueOf(maybeOutputSize == null ? "1" : maybeOutputSize.toString()); + workerTask.setOutputSize(outputSize); + } + }); } } diff --git a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerTask.java b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerTask.java index 3a518a715e3c..4e98f52ce781 100644 --- a/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerTask.java +++ b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerTask.java @@ -21,7 +21,6 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.options.Option; import org.gradle.workers.IsolationMode; import org.gradle.workers.WorkerConfiguration; import org.gradle.workers.WorkerExecutor; @@ -66,11 +65,6 @@ public int getOutputSize() { return outputSize; } - @Option(option="outputSize", description="set the number of output files") - public void setOutputSize(String outputSize) { - setOutputSize(Integer.valueOf(outputSize)); - } - public void setOutputSize(int outputSize) { this.outputSize = outputSize; } diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java index 7bff197ce720..a22bc8a27111 100644 --- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java +++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/binary/BaseBinarySpec.java @@ -23,7 +23,7 @@ import org.gradle.api.artifacts.component.LibraryBinaryIdentifier; import org.gradle.api.internal.AbstractBuildableComponentSpec; import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.reflect.ObjectInstantiationException; import org.gradle.internal.component.local.model.DefaultLibraryBinaryIdentifier; import org.gradle.internal.reflect.Instantiator; @@ -79,8 +79,8 @@ public class BaseBinarySpec extends AbstractBuildableComponentSpec implements Bi public static T create(Class publicType, Class implementationType, ComponentSpecIdentifier componentId, MutableModelNode modelNode, @Nullable MutableModelNode componentNode, Instantiator instantiator, NamedEntityInstantiator taskInstantiator, - CollectionCallbackActionDecorator collectionCallbackActionDecorator) { - NEXT_BINARY_INFO.set(new BinaryInfo(componentId, publicType, modelNode, componentNode, taskInstantiator, instantiator, collectionCallbackActionDecorator)); + CollectionCallbackActionDecorator collectionCallbackActionDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { + NEXT_BINARY_INFO.set(new BinaryInfo(componentId, publicType, modelNode, componentNode, taskInstantiator, instantiator, collectionCallbackActionDecorator, domainObjectCollectionFactory)); try { try { return instantiator.newInstance(implementationType); @@ -101,7 +101,7 @@ private BaseBinarySpec(BinaryInfo info) { this.publicType = info.publicType; this.componentNode = info.componentNode; this.tasks = info.instantiator.newInstance(DefaultBinaryTasksCollection.class, this, info.taskInstantiator, info.collectionCallbackActionDecorator); - this.inputSourceSets = new DefaultDomainObjectSet(LanguageSourceSet.class, info.collectionCallbackActionDecorator); + this.inputSourceSets = info.domainObjectCollectionFactory.newDomainObjectSet(LanguageSourceSet.class); MutableModelNode modelNode = info.modelNode; sources = ModelMaps.addModelMapNode(modelNode, LANGUAGE_SOURCE_SET_MODELTYPE, "sources"); @@ -223,8 +223,9 @@ private static class BinaryInfo { private final Instantiator instantiator; private final ComponentSpecIdentifier componentId; private final CollectionCallbackActionDecorator collectionCallbackActionDecorator; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; - private BinaryInfo(ComponentSpecIdentifier componentId, Class publicType, MutableModelNode modelNode, MutableModelNode componentNode, NamedEntityInstantiator taskInstantiator, Instantiator instantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + private BinaryInfo(ComponentSpecIdentifier componentId, Class publicType, MutableModelNode modelNode, MutableModelNode componentNode, NamedEntityInstantiator taskInstantiator, Instantiator instantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.componentId = componentId; this.publicType = publicType; this.modelNode = modelNode; @@ -232,6 +233,7 @@ private BinaryInfo(ComponentSpecIdentifier componentId, Class { private final ProjectIdentifier projectIdentifier; public ComponentSpecFactory(final ProjectIdentifier projectIdentifier, final Instantiator instantiator, final NamedEntityInstantiator taskInstantiator, final ObjectFactory objectFactory, - final CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + final CollectionCallbackActionDecorator collectionCallbackActionDecorator, final DomainObjectCollectionFactory domainObjectCollectionFactory) { super(ComponentSpec.class); this.projectIdentifier = projectIdentifier; registerFactory(DefaultComponentSpec.class, new ImplementationFactory() { @@ -64,7 +65,8 @@ public T create(ModelType publi componentNode, instantiator, taskInstantiator, - collectionCallbackActionDecorator); + collectionCallbackActionDecorator, + domainObjectCollectionFactory); } }); registerFactory(BaseLanguageSourceSet.class, new ImplementationFactory() { diff --git a/subprojects/platform-base/src/main/java/org/gradle/platform/base/plugins/ComponentBasePlugin.java b/subprojects/platform-base/src/main/java/org/gradle/platform/base/plugins/ComponentBasePlugin.java index 352c5f3a2f47..d89248129761 100644 --- a/subprojects/platform-base/src/main/java/org/gradle/platform/base/plugins/ComponentBasePlugin.java +++ b/subprojects/platform-base/src/main/java/org/gradle/platform/base/plugins/ComponentBasePlugin.java @@ -21,9 +21,11 @@ import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.project.ProjectIdentifier; import org.gradle.api.model.ObjectFactory; import org.gradle.internal.reflect.Instantiator; +import org.gradle.internal.service.ServiceRegistry; import org.gradle.language.base.plugins.LifecycleBasePlugin; import org.gradle.model.Model; import org.gradle.model.Mutate; @@ -63,8 +65,9 @@ void components(ComponentSpecContainer componentSpecs) { @Hidden @Model - ComponentSpecFactory componentSpecFactory(ProjectIdentifier projectIdentifier, Instantiator instantiator, ObjectFactory objectFactory, NamedEntityInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { - return new ComponentSpecFactory(projectIdentifier, instantiator, taskInstantiator, objectFactory, collectionCallbackActionDecorator); + ComponentSpecFactory componentSpecFactory(ProjectIdentifier projectIdentifier, Instantiator instantiator, ObjectFactory objectFactory, NamedEntityInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator, ServiceRegistry serviceRegistry) { + DomainObjectCollectionFactory domainObjectCollectionFactory = serviceRegistry.get(DomainObjectCollectionFactory.class); + return new ComponentSpecFactory(projectIdentifier, instantiator, taskInstantiator, objectFactory, collectionCallbackActionDecorator, domainObjectCollectionFactory); } @ComponentType diff --git a/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/binary/BaseBinaryFixtures.groovy b/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/binary/BaseBinaryFixtures.groovy index 1542f8edb126..f5be04bf39ed 100644 --- a/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/binary/BaseBinaryFixtures.groovy +++ b/subprojects/platform-base/src/testFixtures/groovy/org/gradle/platform/base/binary/BaseBinaryFixtures.groovy @@ -32,7 +32,7 @@ class BaseBinaryFixtures { static T create(Class publicType, Class implType, String name, MutableModelNode componentNode) { return BaseInstanceFixtureSupport.create(publicType, BinarySpecInternal, implType, name) { MutableModelNode node -> def identifier = componentNode ? componentNode.asImmutable(ModelType.of(ComponentSpecInternal), null).instance.identifier.child(name) : new DefaultComponentSpecIdentifier("project", name) - return BaseBinarySpec.create(publicType, implType, identifier, node, componentNode, TestUtil.instantiatorFactory().injectLenient(), {} as NamedEntityInstantiator, CollectionCallbackActionDecorator.NOOP) + return BaseBinarySpec.create(publicType, implType, identifier, node, componentNode, TestUtil.instantiatorFactory().injectLenient(), {} as NamedEntityInstantiator, CollectionCallbackActionDecorator.NOOP, TestUtil.domainObjectCollectionFactory()) } } } diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraries.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraries.java index c0b970a6434e..ed294d6c2e1a 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraries.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraries.java @@ -20,6 +20,7 @@ import org.gradle.api.artifacts.repositories.RepositoryContentDescriptor; import org.gradle.api.internal.AbstractNamedDomainObjectContainer; import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.model.ObjectFactory; import org.gradle.internal.reflect.Instantiator; import org.gradle.nativeplatform.PrebuiltLibraries; @@ -28,15 +29,15 @@ public class DefaultPrebuiltLibraries extends AbstractNamedDomainObjectContainer implements PrebuiltLibraries { private final ObjectFactory objectFactory; private final Action libraryInitializer; - private CollectionCallbackActionDecorator collectionCallbackActionDecorator; private String name; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; - public DefaultPrebuiltLibraries(String name, Instantiator instantiator, ObjectFactory objectFactory, Action libraryInitializer, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public DefaultPrebuiltLibraries(String name, Instantiator instantiator, ObjectFactory objectFactory, Action libraryInitializer, CollectionCallbackActionDecorator collectionCallbackActionDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { super(PrebuiltLibrary.class, instantiator, collectionCallbackActionDecorator); this.name = name; this.objectFactory = objectFactory; this.libraryInitializer = libraryInitializer; - this.collectionCallbackActionDecorator = collectionCallbackActionDecorator; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; } @Override @@ -56,7 +57,7 @@ public void content(Action configureAction) @Override protected PrebuiltLibrary doCreate(String name) { - return getInstantiator().newInstance(DefaultPrebuiltLibrary.class, name, objectFactory, collectionCallbackActionDecorator); + return getInstantiator().newInstance(DefaultPrebuiltLibrary.class, name, objectFactory, domainObjectCollectionFactory); } @Override diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibrary.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibrary.java index bda3236761e3..41ee94817786 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibrary.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibrary.java @@ -18,8 +18,7 @@ import org.gradle.api.DomainObjectSet; import org.gradle.api.file.SourceDirectorySet; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.model.ObjectFactory; import org.gradle.nativeplatform.NativeLibraryBinary; import org.gradle.nativeplatform.PrebuiltLibrary; @@ -30,10 +29,10 @@ public class DefaultPrebuiltLibrary implements PrebuiltLibrary { private final SourceDirectorySet headers; private final DomainObjectSet binaries; - public DefaultPrebuiltLibrary(String name, ObjectFactory objectFactory, CollectionCallbackActionDecorator decorator) { + public DefaultPrebuiltLibrary(String name, ObjectFactory objectFactory, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.name = name; headers = objectFactory.sourceDirectorySet("headers", "headers for prebuilt library '" + name + "'"); - binaries = new DefaultDomainObjectSet(NativeLibraryBinary.class, decorator); + binaries = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); } @Override diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocator.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocator.java index f4a05974fcd9..ed80b113675b 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocator.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocator.java @@ -17,8 +17,7 @@ package org.gradle.nativeplatform.internal.resolve; import org.gradle.api.DomainObjectSet; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.nativeplatform.NativeLibraryBinary; import javax.annotation.Nullable; @@ -26,12 +25,15 @@ import java.util.Map; public class CachingLibraryBinaryLocator implements LibraryBinaryLocator { - private static final DomainObjectSet NULL_RESULT = new DefaultDomainObjectSet(NativeLibraryBinary.class, CollectionCallbackActionDecorator.NOOP); + private static DomainObjectSet nullResult; private final LibraryBinaryLocator delegate; private final Map> libraries = new HashMap>(); - public CachingLibraryBinaryLocator(LibraryBinaryLocator delegate) { + public CachingLibraryBinaryLocator(LibraryBinaryLocator delegate, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.delegate = delegate; + if (nullResult == null) { + nullResult = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); + } } @Nullable @@ -41,10 +43,10 @@ public DomainObjectSet getBinaries(LibraryIdentifier librar if (libraryBinaries == null) { libraryBinaries = delegate.getBinaries(library); if (libraryBinaries == null) { - libraryBinaries = NULL_RESULT; + libraryBinaries = nullResult; } libraries.put(library, libraryBinaries); } - return libraryBinaries == NULL_RESULT ? null : libraryBinaries; + return libraryBinaries == nullResult ? null : libraryBinaries; } } diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java index cf491ca60301..5b3c4e0ab7ce 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/NativeDependencyResolverServices.java @@ -15,7 +15,7 @@ */ package org.gradle.nativeplatform.internal.resolve; -import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.resolve.ProjectModelResolver; import org.gradle.nativeplatform.internal.prebuilt.PrebuiltLibraryBinaryLocator; @@ -24,11 +24,11 @@ import java.util.List; public class NativeDependencyResolverServices { - public LibraryBinaryLocator createLibraryBinaryLocator(ProjectModelResolver projectModelResolver, CollectionCallbackActionDecorator callbackActionDecorator) { + public LibraryBinaryLocator createLibraryBinaryLocator(ProjectModelResolver projectModelResolver, DomainObjectCollectionFactory domainObjectCollectionFactory) { List locators = new ArrayList(); - locators.add(new ProjectLibraryBinaryLocator(projectModelResolver, callbackActionDecorator)); + locators.add(new ProjectLibraryBinaryLocator(projectModelResolver, domainObjectCollectionFactory)); locators.add(new PrebuiltLibraryBinaryLocator(projectModelResolver)); - return new CachingLibraryBinaryLocator(new ChainedLibraryBinaryLocator(locators)); + return new CachingLibraryBinaryLocator(new ChainedLibraryBinaryLocator(locators), domainObjectCollectionFactory); } public NativeDependencyResolver createResolver(LibraryBinaryLocator locator, FileCollectionFactory fileCollectionFactory) { diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java index 529f1073e0f8..8382ab731ff9 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocator.java @@ -16,8 +16,7 @@ package org.gradle.nativeplatform.internal.resolve; import org.gradle.api.DomainObjectSet; -import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.resolve.ProjectModelResolver; import org.gradle.model.ModelMap; import org.gradle.model.internal.registry.ModelRegistry; @@ -30,11 +29,11 @@ public class ProjectLibraryBinaryLocator implements LibraryBinaryLocator { private final ProjectModelResolver projectModelResolver; - private CollectionCallbackActionDecorator collectionCallbackActionDecorator; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; - public ProjectLibraryBinaryLocator(ProjectModelResolver projectModelResolver, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public ProjectLibraryBinaryLocator(ProjectModelResolver projectModelResolver, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.projectModelResolver = projectModelResolver; - this.collectionCallbackActionDecorator = collectionCallbackActionDecorator; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; } // Converts the binaries of a project library into regular binary instances @@ -52,7 +51,7 @@ public DomainObjectSet getBinaries(LibraryIdentifier librar return null; } ModelMap projectBinaries = library.getBinaries().withType(NativeBinarySpec.class); - DomainObjectSet binaries = new DefaultDomainObjectSet(NativeLibraryBinary.class, collectionCallbackActionDecorator); + DomainObjectSet binaries = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); for (NativeBinarySpec nativeBinarySpec : projectBinaries.values()) { binaries.add((NativeLibraryBinary) nativeBinarySpec); } diff --git a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java index 8caed801f256..47246550cc66 100644 --- a/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java +++ b/subprojects/platform-native/src/main/java/org/gradle/nativeplatform/plugins/NativeComponentModelPlugin.java @@ -28,6 +28,7 @@ import org.gradle.api.file.SourceDirectorySet; import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.project.ProjectInternal; import org.gradle.api.internal.project.ProjectRegistry; @@ -167,7 +168,8 @@ Repositories repositories(ServiceRegistry serviceRegistry, NativePlatforms nativePlatforms = serviceRegistry.get(NativePlatforms.class); FileCollectionFactory fileCollectionFactory = serviceRegistry.get(FileCollectionFactory.class); Action initializer = new PrebuiltLibraryInitializer(instantiator, fileCollectionFactory, nativePlatforms, platforms.withType(NativePlatform.class), buildTypes, flavors); - return new DefaultRepositories(instantiator, sourceDirectorySetFactory, initializer, callbackActionDecorator); + DomainObjectCollectionFactory domainObjectCollectionFactory = serviceRegistry.get(DomainObjectCollectionFactory.class); + return new DefaultRepositories(instantiator, sourceDirectorySetFactory, initializer, callbackActionDecorator, domainObjectCollectionFactory); } @Model @@ -424,15 +426,16 @@ void registerNativeDependentBinariesResolutionStrategy(DependentBinariesResolver } private static class DefaultRepositories extends DefaultPolymorphicDomainObjectContainer implements Repositories { - private DefaultRepositories(final Instantiator instantiator, - final ObjectFactory objectFactory, - final Action binaryFactory, - final CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + private DefaultRepositories(Instantiator instantiator, + ObjectFactory objectFactory, + Action binaryFactory, + CollectionCallbackActionDecorator collectionCallbackActionDecorator, + DomainObjectCollectionFactory domainObjectCollectionFactory) { super(ArtifactRepository.class, instantiator, new ArtifactRepositoryNamer(), collectionCallbackActionDecorator); registerFactory(PrebuiltLibraries.class, new NamedDomainObjectFactory() { @Override public PrebuiltLibraries create(String name) { - return instantiator.newInstance(DefaultPrebuiltLibraries.class, name, instantiator, objectFactory, binaryFactory, collectionCallbackActionDecorator); + return instantiator.newInstance(DefaultPrebuiltLibraries.class, name, instantiator, objectFactory, binaryFactory, collectionCallbackActionDecorator, domainObjectCollectionFactory); } }); } diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraryTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraryTest.groovy index a40b7d3165e9..625cc598c038 100644 --- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraryTest.groovy +++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/prebuilt/DefaultPrebuiltLibraryTest.groovy @@ -16,13 +16,13 @@ package org.gradle.nativeplatform.internal.prebuilt -import org.gradle.api.internal.CollectionCallbackActionDecorator + import org.gradle.util.TestUtil import spock.lang.Specification class DefaultPrebuiltLibraryTest extends Specification { def "has useful display name"() { - def lib = new DefaultPrebuiltLibrary("someLib", TestUtil.objectFactory(), CollectionCallbackActionDecorator.NOOP) + def lib = new DefaultPrebuiltLibrary("someLib", TestUtil.objectFactory(), TestUtil.domainObjectCollectionFactory()) expect: lib.toString() == "prebuilt library 'someLib'" diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocatorTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocatorTest.groovy index 17bcf54b6026..c0f13a43dc7e 100644 --- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocatorTest.groovy +++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/CachingLibraryBinaryLocatorTest.groovy @@ -17,11 +17,12 @@ package org.gradle.nativeplatform.internal.resolve import org.gradle.api.DomainObjectSet +import org.gradle.util.TestUtil import spock.lang.Specification class CachingLibraryBinaryLocatorTest extends Specification { def target = Mock(LibraryBinaryLocator) - def locator = new CachingLibraryBinaryLocator(target) + def locator = new CachingLibraryBinaryLocator(target, TestUtil.domainObjectCollectionFactory()) def "locates library once and reuses result for subsequent lookups"() { def lib = new LibraryIdentifier("project", "lib") diff --git a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy index f6f7a7992ce9..e7323eb2426a 100644 --- a/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy +++ b/subprojects/platform-native/src/test/groovy/org/gradle/nativeplatform/internal/resolve/ProjectLibraryBinaryLocatorTest.groovy @@ -16,8 +16,6 @@ package org.gradle.nativeplatform.internal.resolve import org.gradle.api.UnknownProjectException -import org.gradle.api.internal.CollectionCallbackActionDecorator -import org.gradle.api.internal.DefaultDomainObjectSet import org.gradle.api.internal.resolve.ProjectModelResolver import org.gradle.model.ModelMap import org.gradle.model.internal.registry.ModelRegistry @@ -25,6 +23,7 @@ import org.gradle.nativeplatform.NativeBinarySpec import org.gradle.nativeplatform.NativeLibraryBinary import org.gradle.nativeplatform.NativeLibrarySpec import org.gradle.platform.base.ComponentSpecContainer +import org.gradle.util.TestUtil import spock.lang.Specification import static org.gradle.model.internal.type.ModelTypes.modelMap @@ -36,8 +35,8 @@ class ProjectLibraryBinaryLocatorTest extends Specification { def binary = Mock(MockNativeLibraryBinary) def binaries = Mock(ModelMap) def nativeBinaries = Mock(ModelMap) - def convertedBinaries = new DefaultDomainObjectSet(NativeLibraryBinary, CollectionCallbackActionDecorator.NOOP) - def locator = new ProjectLibraryBinaryLocator(projectLocator, CollectionCallbackActionDecorator.NOOP) + def convertedBinaries = TestUtil.domainObjectCollectionFactory().newDomainObjectSet(NativeLibraryBinary) + def locator = new ProjectLibraryBinaryLocator(projectLocator, TestUtil.domainObjectCollectionFactory()) def setup() { convertedBinaries.add(binary) diff --git a/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/GradlePluginDevelopmentExtension.java b/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/GradlePluginDevelopmentExtension.java index 9b852dc8452c..13badf7189a0 100644 --- a/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/GradlePluginDevelopmentExtension.java +++ b/subprojects/plugin-development/src/main/java/org/gradle/plugin/devel/GradlePluginDevelopmentExtension.java @@ -62,7 +62,7 @@ public GradlePluginDevelopmentExtension(Project project, SourceSet pluginSourceS } public GradlePluginDevelopmentExtension(Project project, SourceSet pluginSourceSet, SourceSet[] testSourceSets) { - this.plugins = project.container(PluginDeclaration.class); + this.plugins = project.getObjects().container(PluginDeclaration.class); this.pluginSourceSet = pluginSourceSet; testSourceSets(testSourceSets); } diff --git a/subprojects/plugins/src/main/java/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java b/subprojects/plugins/src/main/java/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java index c31144123612..fed38f14f193 100644 --- a/subprojects/plugins/src/main/java/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java +++ b/subprojects/plugins/src/main/java/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpec.java @@ -20,7 +20,7 @@ import org.gradle.api.artifacts.component.LibraryBinaryIdentifier; import org.gradle.api.internal.AbstractBuildableComponentSpec; import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.tasks.SourceSet; import org.gradle.internal.reflect.Instantiator; import org.gradle.jvm.ClassDirectoryBinarySpec; @@ -44,19 +44,19 @@ import java.io.File; public class DefaultClassDirectoryBinarySpec extends AbstractBuildableComponentSpec implements ClassDirectoryBinarySpecInternal { - private final DefaultDomainObjectSet sourceSets; + private final DomainObjectSet sourceSets; private final SourceSet sourceSet; private final JavaToolChain toolChain; private final JavaPlatform platform; private final BinaryTasksCollection tasks; private boolean buildable = true; - public DefaultClassDirectoryBinarySpec(ComponentSpecIdentifier componentIdentifier, SourceSet sourceSet, JavaToolChain toolChain, JavaPlatform platform, Instantiator instantiator, NamedEntityInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public DefaultClassDirectoryBinarySpec(ComponentSpecIdentifier componentIdentifier, SourceSet sourceSet, JavaToolChain toolChain, JavaPlatform platform, Instantiator instantiator, NamedEntityInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { super(componentIdentifier, ClassDirectoryBinarySpec.class); this.sourceSet = sourceSet; this.toolChain = toolChain; this.platform = platform; - this.sourceSets = new DefaultDomainObjectSet(LanguageSourceSet.class, collectionCallbackActionDecorator); + this.sourceSets = domainObjectCollectionFactory.newDomainObjectSet(LanguageSourceSet.class); this.tasks = instantiator.newInstance(DefaultBinaryTasksCollection.class, this, taskInstantiator, collectionCallbackActionDecorator); } diff --git a/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaBasePluginRules.java b/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaBasePluginRules.java index 98feb43285b4..2cc787e791c7 100644 --- a/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaBasePluginRules.java +++ b/subprojects/plugins/src/main/java/org/gradle/api/plugins/JavaBasePluginRules.java @@ -22,6 +22,7 @@ import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.internal.CollectionCallbackActionDecorator; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.api.internal.java.DefaultJavaSourceSet; import org.gradle.api.internal.java.DefaultJvmResourceSet; import org.gradle.api.internal.jvm.ClassDirectoryBinarySpecInternal; @@ -61,14 +62,16 @@ class JavaBasePluginRules implements Plugin { private final JavaToolChain javaToolChain; private final NamedEntityInstantiator taskInstantiator; private CollectionCallbackActionDecorator collectionCallbackActionDecorator; + private final DomainObjectCollectionFactory domainObjectCollectionFactory; @Inject - public JavaBasePluginRules(ModelRegistry modelRegistry, Instantiator instantiator, JavaToolChain javaToolChain, TaskInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator) { + public JavaBasePluginRules(ModelRegistry modelRegistry, Instantiator instantiator, JavaToolChain javaToolChain, TaskInstantiator taskInstantiator, CollectionCallbackActionDecorator collectionCallbackActionDecorator, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.modelRegistry = modelRegistry; this.instantiator = instantiator; this.javaToolChain = javaToolChain; this.taskInstantiator = taskInstantiator; this.collectionCallbackActionDecorator = collectionCallbackActionDecorator; + this.domainObjectCollectionFactory = domainObjectCollectionFactory; } @Override @@ -96,7 +99,7 @@ public void execute(final SourceSet sourceSet) { Provider compileTask = tasks.named(sourceSet.getCompileJavaTaskName(), JavaCompile.class); DefaultComponentSpecIdentifier binaryId = new DefaultComponentSpecIdentifier(project.getPath(), sourceSet.getName()); - ClassDirectoryBinarySpecInternal binary = instantiator.newInstance(DefaultClassDirectoryBinarySpec.class, binaryId, sourceSet, javaToolChain, DefaultJavaPlatform.current(), instantiator, taskInstantiator, collectionCallbackActionDecorator); + ClassDirectoryBinarySpecInternal binary = instantiator.newInstance(DefaultClassDirectoryBinarySpec.class, binaryId, sourceSet, javaToolChain, DefaultJavaPlatform.current(), instantiator, taskInstantiator, collectionCallbackActionDecorator, domainObjectCollectionFactory); Classpath compileClasspath = new SourceSetCompileClasspath(sourceSet); DefaultJavaSourceSet javaSourceSet = instantiator.newInstance(DefaultJavaSourceSet.class, binaryId.child("java"), sourceSet.getJava(), compileClasspath); diff --git a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy index 5df367ce56ed..a4394b680af0 100644 --- a/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy +++ b/subprojects/plugins/src/test/groovy/org/gradle/api/internal/jvm/DefaultClassDirectoryBinarySpecTest.groovy @@ -35,6 +35,6 @@ class DefaultClassDirectoryBinarySpecTest extends Specification { private DefaultClassDirectoryBinarySpec binary(String name) { new DefaultClassDirectoryBinarySpec(new DefaultComponentSpecIdentifier(":", name), Stub(SourceSet), Stub(JavaToolChain), Stub(JavaPlatform), - TestUtil.instantiatorFactory().decorateLenient(), Mock(NamedEntityInstantiator), CollectionCallbackActionDecorator.NOOP) + TestUtil.instantiatorFactory().decorateLenient(), Mock(NamedEntityInstantiator), CollectionCallbackActionDecorator.NOOP, TestUtil.domainObjectCollectionFactory()) } } diff --git a/subprojects/signing/src/main/java/org/gradle/plugins/signing/Sign.java b/subprojects/signing/src/main/java/org/gradle/plugins/signing/Sign.java index 24635f91893d..62f7a7d13a03 100644 --- a/subprojects/signing/src/main/java/org/gradle/plugins/signing/Sign.java +++ b/subprojects/signing/src/main/java/org/gradle/plugins/signing/Sign.java @@ -28,7 +28,6 @@ import org.gradle.api.artifacts.PublishArtifact; import org.gradle.api.file.FileCollection; import org.gradle.api.internal.CollectionCallbackActionDecorator; -import org.gradle.api.internal.DefaultDomainObjectSet; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.publish.Publication; import org.gradle.api.publish.PublicationArtifact; @@ -64,11 +63,10 @@ public class Sign extends DefaultTask implements SignatureSpec { private SignatureType signatureType; private Signatory signatory; private boolean required = true; - private final DefaultDomainObjectSet signatures; + private final DomainObjectSet signatures = getProject().getObjects().domainObjectSet(Signature.class); @Inject public Sign() { - this.signatures = new DefaultDomainObjectSet(Signature.class, getCallbackActionDecorator()); // If we aren't required and don't have a signatory then we just don't run onlyIf(task -> isRequired() || getSignatory() != null); }