From dad5e02dc6047e0d4725ec14afb0d0d626577160 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Sat, 11 May 2019 19:25:39 +0200 Subject: [PATCH 01/24] Add factory methods to create NamedDomainObjectContainer and DomainObjectSet on ObjectFactory --- .../org/gradle/api/model/ObjectFactory.java | 43 +++++++++++- .../model/ObjectFactoryIntegrationTest.groovy | 57 ++++++++++++++++ .../DefaultDomainObjectCollectionFactory.java | 65 +++++++++++++++++++ .../DomainObjectCollectionFactory.java | 38 +++++++++++ .../internal/model/DefaultObjectFactory.java | 23 ++++++- .../InstantiatorBackedObjectFactory.java | 18 +++++ .../api/internal/project/DefaultProject.java | 10 +-- .../service/scopes/GlobalScopeServices.java | 6 +- .../service/scopes/ProjectScopeServices.java | 9 ++- .../model/DefaultObjectFactoryTest.groovy | 3 +- .../groovy/org/gradle/util/TestUtil.groovy | 6 +- subprojects/docs/src/docs/release/notes.md | 4 ++ .../GradlePluginDevelopmentExtension.java | 2 +- 13 files changed, 267 insertions(+), 17 deletions(-) create mode 100644 subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java create mode 100644 subprojects/core/src/main/java/org/gradle/api/internal/collections/DomainObjectCollectionFactory.java 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/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/collections/DefaultDomainObjectCollectionFactory.java b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java new file mode 100644 index 000000000000..ff7ab4d28d8c --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DefaultDomainObjectCollectionFactory.java @@ -0,0 +1,65 @@ +/* + * 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 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.DefaultDomainObjectSet; +import org.gradle.api.internal.DynamicPropertyNamer; +import org.gradle.api.internal.FactoryNamedDomainObjectContainer; +import org.gradle.api.internal.MutationGuard; +import org.gradle.api.internal.MutationGuards; +import org.gradle.api.internal.ReflectiveNamedDomainObjectFactory; +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 instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), objectFactory, mutationGuard, collectionCallbackActionDecorator); + } + + @Override + public NamedDomainObjectContainer newNamedDomainObjectContainer(Class elementType, NamedDomainObjectFactory factory) { + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), factory, mutationGuard, collectionCallbackActionDecorator); + } + + @Override + public DomainObjectSet newDomainObjectSet(Class elementType) { + Instantiator instantiator = instantiatorFactory.decorateLenient(); + return instantiator.newInstance(DefaultDomainObjectSet.class, elementType, collectionCallbackActionDecorator); + } +} 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..883b99403b82 --- /dev/null +++ b/subprojects/core/src/main/java/org/gradle/api/internal/collections/DomainObjectCollectionFactory.java @@ -0,0 +1,38 @@ +/* + * 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 org.gradle.api.DomainObjectSet; +import org.gradle.api.NamedDomainObjectContainer; +import org.gradle.api.NamedDomainObjectFactory; + +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 DomainObjectSet} for managing objects of the specified type. + */ + DomainObjectSet newDomainObjectSet(Class elementType); +} 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/project/DefaultProject.java b/subprojects/core/src/main/java/org/gradle/api/internal/project/DefaultProject.java index dd228ef483a0..097096ed5df3 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 @@ -54,6 +54,7 @@ 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; @@ -1314,17 +1315,12 @@ 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 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 53836d2b4048..6f19c8d31c7f 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,11 @@ 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.file.DefaultFilePropertyFactory; import org.gradle.api.internal.file.FileCollectionFactory; import org.gradle.api.internal.file.FileResolver; @@ -247,7 +250,8 @@ ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, Servi fileResolver, directoryFileTreeFactory, new DefaultFilePropertyFactory(fileResolver), - fileCollectionFactory); + fileCollectionFactory, + new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, CollectionCallbackActionDecorator.NOOP, MutationGuards.identity())); } ProviderFactory createProviderFactory() { 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 615872d6fb6e..da598980c5e2 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,13 @@ 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.component.ComponentRegistry; import org.gradle.api.internal.component.DefaultSoftwareComponentContainer; import org.gradle.api.internal.file.BaseDirFileResolver; @@ -308,9 +310,10 @@ 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, CollectionCallbackActionDecorator collectionCallbackActionDecorator, CrossProjectConfigurator projectConfigurator) { + ServiceRegistry services = ProjectScopeServices.this; + Instantiator instantiator = instantiatorFactory.injectAndDecorate(services); + return new DefaultObjectFactory(instantiator, NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, filePropertyFactory, fileCollectionFactory, new DefaultDomainObjectCollectionFactory(instantiatorFactory,services, collectionCallbackActionDecorator, MutationGuards.of(projectConfigurator))); } } 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/testFixtures/groovy/org/gradle/util/TestUtil.groovy b/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy index 1f31a911473a..b092fe5b214b 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,10 @@ 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.file.DefaultFilePropertyFactory import org.gradle.api.internal.file.FileResolver import org.gradle.api.internal.file.TestFiles @@ -73,7 +76,8 @@ class TestUtil { 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(), new DefaultDomainObjectCollectionFactory(instantiatorFactory(), services, CollectionCallbackActionDecorator.NOOP, MutationGuards.identity())) } static NamedObjectInstantiator objectInstantiator() { diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index b7cff0cf12b7..44a18ea644e6 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -50,6 +50,10 @@ The `init` task can now generate simple Gradle plugins. You can use these as a s See the [User manual](userguide/build_init_plugin.html) for more details. +### New factory method for creating `NamedDomainObjectContainer` and `DomainObjectSet` + +The `ObjectFactory` can now be used for creating `NamedDomainObjectContainer` and `DomainObjectSet`. + ## Define organization-wide properties with a custom Gradle Distribution Gradle now looks for a `gradle.properties` file in the Gradle distribution used by the build. This file has the [lowest precedence of any `gradle.properties`](userguide/build_environment.html#sec:gradle_configuration_properties) and properties defined in other locations will override values defined here. 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); } From cbbcbe1c70b699e285a40e3476638faf36ef652d Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Sun, 12 May 2019 08:55:01 +0200 Subject: [PATCH 02/24] Fix checkstyle issues --- .../collections/DefaultDomainObjectCollectionFactory.java | 1 - .../java/org/gradle/api/internal/project/DefaultProject.java | 1 - .../gradle/internal/service/scopes/ProjectScopeServices.java | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) 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 index ff7ab4d28d8c..52275ea589a1 100644 --- 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 @@ -24,7 +24,6 @@ import org.gradle.api.internal.DynamicPropertyNamer; import org.gradle.api.internal.FactoryNamedDomainObjectContainer; import org.gradle.api.internal.MutationGuard; -import org.gradle.api.internal.MutationGuards; import org.gradle.api.internal.ReflectiveNamedDomainObjectFactory; import org.gradle.internal.instantiation.InstantiatorFactory; import org.gradle.internal.reflect.Instantiator; 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 097096ed5df3..bf702ff9157d 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 @@ -51,7 +51,6 @@ 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; 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 da598980c5e2..d884fd4f5dfb 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 @@ -313,7 +313,7 @@ protected FileCollectionFactory createFileCollectionFactory(PathToFileResolver f protected ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory, CollectionCallbackActionDecorator collectionCallbackActionDecorator, CrossProjectConfigurator projectConfigurator) { ServiceRegistry services = ProjectScopeServices.this; Instantiator instantiator = instantiatorFactory.injectAndDecorate(services); - return new DefaultObjectFactory(instantiator, NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, filePropertyFactory, fileCollectionFactory, new DefaultDomainObjectCollectionFactory(instantiatorFactory,services, collectionCallbackActionDecorator, MutationGuards.of(projectConfigurator))); + return new DefaultObjectFactory(instantiator, NamedObjectInstantiator.INSTANCE, fileResolver, directoryFileTreeFactory, filePropertyFactory, fileCollectionFactory, new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, collectionCallbackActionDecorator, MutationGuards.of(projectConfigurator))); } } From dab7580e3c824a8cdc220e3047aa9adfde98f8c2 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Thu, 16 May 2019 19:28:50 +0200 Subject: [PATCH 03/24] Use the `DomainObjectCollectionFactory` everywhere --- .../DefaultDomainObjectCollectionFactory.java | 21 ++++++++++++--- .../DomainObjectCollectionFactory.java | 19 +++++++++++++ .../plugins/DefaultPluginManager.java | 10 +++---- .../api/internal/project/DefaultProject.java | 5 +--- .../service/scopes/GlobalScopeServices.java | 9 +++++-- .../service/scopes/ProjectScopeServices.java | 14 +++++++--- .../service/scopes/SettingsScopeServices.java | 5 ++-- .../plugins/DefaultPluginContainerTest.groovy | 2 +- .../plugins/DefaultPluginManagerTest.groovy | 2 +- .../org/gradle/util/NameValidatorTest.groovy | 2 +- .../groovy/org/gradle/util/TestUtil.groovy | 20 +++++++++++--- .../DefaultDependencyManagementServices.java | 7 +++-- .../configurations/DefaultConfiguration.java | 27 ++++++++++--------- .../DefaultConfigurationContainer.java | 10 ++++--- .../DefaultConfigurationPublications.java | 13 ++++----- .../configurations/DefaultVariant.java | 7 +++-- .../DefaultConfigurationContainerSpec.groovy | 8 +++--- .../DefaultConfigurationContainerTest.groovy | 2 +- ...efaultConfigurationPublicationsTest.groovy | 8 +++--- .../cpp/internal/DefaultCppApplication.java | 5 ++-- .../cpp/internal/DefaultCppLibrary.java | 5 ++-- .../cpp/internal/MainExecutableVariant.java | 7 +++-- .../cpp/internal/MainLibraryVariant.java | 6 ++--- .../platform/base/binary/BaseBinarySpec.java | 12 +++++---- .../internal/ComponentSpecFactory.java | 6 +++-- .../base/plugins/ComponentBasePlugin.java | 7 +++-- .../base/binary/BaseBinaryFixtures.groovy | 2 +- .../prebuilt/DefaultPrebuiltLibraries.java | 9 ++++--- .../prebuilt/DefaultPrebuiltLibrary.java | 7 +++-- .../resolve/CachingLibraryBinaryLocator.java | 9 +++++-- .../NativeDependencyResolverServices.java | 8 +++--- .../resolve/ProjectLibraryBinaryLocator.java | 11 ++++---- .../plugins/NativeComponentModelPlugin.java | 15 ++++++----- .../DefaultPrebuiltLibraryTest.groovy | 4 +-- .../CachingLibraryBinaryLocatorTest.groovy | 3 ++- .../ProjectLibraryBinaryLocatorTest.groovy | 7 +++-- .../jvm/DefaultClassDirectoryBinarySpec.java | 8 +++--- .../api/plugins/JavaBasePluginRules.java | 7 +++-- ...DefaultClassDirectoryBinarySpecTest.groovy | 2 +- .../java/org/gradle/plugins/signing/Sign.java | 3 +-- 40 files changed, 204 insertions(+), 130 deletions(-) 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 index 52275ea589a1..c944087af3d5 100644 --- 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 @@ -16,15 +16,19 @@ 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; @@ -47,18 +51,29 @@ public NamedDomainObjectContainer newNamedDomainObjectContainer(Class // 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 instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), objectFactory, mutationGuard, collectionCallbackActionDecorator); + 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 instantiator.newInstance(FactoryNamedDomainObjectContainer.class, elementType, instantiator, new DynamicPropertyNamer(), factory, mutationGuard, collectionCallbackActionDecorator); + 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 instantiator.newInstance(DefaultDomainObjectSet.class, elementType, collectionCallbackActionDecorator); + 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 index 883b99403b82..94beb2b63fc4 100644 --- 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 @@ -16,9 +16,18 @@ 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.DynamicPropertyNamer; +import org.gradle.api.internal.FactoryNamedDomainObjectContainer; +import org.gradle.api.internal.MutationGuards; +import org.gradle.internal.instantiation.InstantiatorFactory; +import org.gradle.internal.reflect.Instantiator; public interface DomainObjectCollectionFactory { /** @@ -31,8 +40,18 @@ public interface DomainObjectCollectionFactory { */ 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/plugins/DefaultPluginManager.java b/subprojects/core/src/main/java/org/gradle/api/internal/plugins/DefaultPluginManager.java index d1d89a4aba84..2f8a4fe2b132 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) { @@ -213,7 +213,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 bf702ff9157d..c0bbf3500b8d 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,8 +46,6 @@ 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; @@ -1324,8 +1322,7 @@ public NamedDomainObjectContainer container(Class type, NamedDomainObj @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 6f19c8d31c7f..de053fffc195 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 @@ -24,6 +24,7 @@ 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.FileResolver; @@ -243,7 +244,7 @@ MemoryManager createMemoryManager(OsMemoryInfo osMemoryInfo, JvmMemoryInfo jvmMe return new DefaultMemoryManager(osMemoryInfo, jvmMemoryInfo, listenerManager, executorFactory); } - ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry services, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FileCollectionFactory fileCollectionFactory) { + ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, ServiceRegistry services, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FileCollectionFactory fileCollectionFactory, DomainObjectCollectionFactory domainObjectCollectionFactory) { return new DefaultObjectFactory( instantiatorFactory.injectAndDecorate(services), NamedObjectInstantiator.INSTANCE, @@ -251,7 +252,11 @@ ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, Servi directoryFileTreeFactory, new DefaultFilePropertyFactory(fileResolver), fileCollectionFactory, - new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, CollectionCallbackActionDecorator.NOOP, MutationGuards.identity())); + 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/ProjectScopeServices.java b/subprojects/core/src/main/java/org/gradle/internal/service/scopes/ProjectScopeServices.java index d884fd4f5dfb..ac0b90df0d3c 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 @@ -28,6 +28,7 @@ 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 +184,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) { @@ -310,10 +311,15 @@ protected FileCollectionFactory createFileCollectionFactory(PathToFileResolver f return new DefaultFileCollectionFactory(fileResolver, taskResolver); } - protected ObjectFactory createObjectFactory(InstantiatorFactory instantiatorFactory, FileResolver fileResolver, DirectoryFileTreeFactory directoryFileTreeFactory, FilePropertyFactory filePropertyFactory, FileCollectionFactory fileCollectionFactory, CollectionCallbackActionDecorator collectionCallbackActionDecorator, CrossProjectConfigurator projectConfigurator) { + 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, new DefaultDomainObjectCollectionFactory(instantiatorFactory, services, collectionCallbackActionDecorator, MutationGuards.of(projectConfigurator))); + 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 f5f3617fcabf..10c0e292438a 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; @@ -62,9 +63,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/plugins/DefaultPluginContainerTest.groovy b/subprojects/core/src/test/groovy/org/gradle/api/internal/plugins/DefaultPluginContainerTest.groovy index 8dbc2d43a9a2..87410ed2bf6f 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, 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/util/NameValidatorTest.groovy b/subprojects/core/src/test/groovy/org/gradle/util/NameValidatorTest.groovy index 175ca438f6fe..83916b58d683 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 b092fe5b214b..808554b4a317 100644 --- a/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy +++ b/subprojects/core/src/testFixtures/groovy/org/gradle/util/TestUtil.groovy @@ -21,6 +21,7 @@ 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 @@ -36,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 @@ -47,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 @@ -64,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()) } @@ -73,11 +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(), domainObjectCollectionFactory()) + } - return new DefaultObjectFactory(instantiatorFactory().injectAndDecorate(services), NamedObjectInstantiator.INSTANCE, fileResolver, TestFiles.directoryFileTreeFactory(), new DefaultFilePropertyFactory(fileResolver), TestFiles.fileCollectionFactory(), new DefaultDomainObjectCollectionFactory(instantiatorFactory(), services, CollectionCallbackActionDecorator.NOOP, MutationGuards.identity())) + 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 b3f068ba6caf..7ddea7726379 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; @@ -463,7 +464,8 @@ ConfigurationContainerInternal createConfigurationContainer(Instantiator instant ProjectStateRegistry projectStateRegistry, DocumentationRegistry documentationRegistry, CollectionCallbackActionDecorator callbackDecorator, - UserCodeApplicationContext userCodeApplicationContext) { + UserCodeApplicationContext userCodeApplicationContext, + DomainObjectCollectionFactory domainObjectCollectionFactory) { return instantiator.newInstance(DefaultConfigurationContainer.class, configurationResolver, instantiator, @@ -486,7 +488,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 7a9d833b6377..ae8bb8a3ac2c 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 @@ -81,6 +81,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 +218,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 +240,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 +271,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); @@ -738,7 +739,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()); } @@ -762,7 +763,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()); } @@ -792,14 +793,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); } @@ -928,7 +929,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 13fedb5b002f..aaa322df7c1f 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; } @@ -157,7 +161,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..af13a205f9c0 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 @@ -35,6 +35,7 @@ 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 +57,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 +72,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 +82,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 +156,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 +197,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/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..6e5160876b47 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 @@ -25,9 +25,9 @@ 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 +40,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/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..a66ca5292c3a 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 @@ -19,6 +19,8 @@ import org.gradle.api.DomainObjectSet; import org.gradle.api.internal.CollectionCallbackActionDecorator; import org.gradle.api.internal.DefaultDomainObjectSet; +import org.gradle.api.internal.collections.DefaultDomainObjectCollectionFactory; +import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.nativeplatform.NativeLibraryBinary; import javax.annotation.Nullable; @@ -26,12 +28,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 NULL_RESULT; private final LibraryBinaryLocator delegate; private final Map> libraries = new HashMap>(); - public CachingLibraryBinaryLocator(LibraryBinaryLocator delegate) { + public CachingLibraryBinaryLocator(LibraryBinaryLocator delegate, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.delegate = delegate; + if (NULL_RESULT == null) { + NULL_RESULT = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); + } } @Nullable 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 b7f9f9794905..c8e00ff6a796 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 @@ -423,14 +425,15 @@ 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() { 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/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 2c7e2aa22d15..15c7e65cc3d5 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 403e90476212..e10126463f7a 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 @@ -95,7 +98,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 57d1786185b5..3cb8c07dcbf9 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 @@ -64,11 +64,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); } From 38de5aa2c69c00fa6d6c1e474ad433e384c1ae79 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 May 2019 11:42:42 +0200 Subject: [PATCH 04/24] Fix checkstyle issues --- .../collections/DomainObjectCollectionFactory.java | 6 ------ .../artifacts/configurations/DefaultConfiguration.java | 1 - .../configurations/DefaultConfigurationPublications.java | 2 -- .../src/changes/accepted-public-api-changes.json | 9 ++++++++- .../gradle/language/cpp/internal/MainLibraryVariant.java | 1 - .../internal/resolve/CachingLibraryBinaryLocator.java | 3 --- .../src/main/java/org/gradle/plugins/signing/Sign.java | 1 - 7 files changed, 8 insertions(+), 15 deletions(-) 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 index 94beb2b63fc4..cb0720cdbc11 100644 --- 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 @@ -21,13 +21,7 @@ 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.DynamicPropertyNamer; -import org.gradle.api.internal.FactoryNamedDomainObjectContainer; -import org.gradle.api.internal.MutationGuards; -import org.gradle.internal.instantiation.InstantiatorFactory; -import org.gradle.internal.reflect.Instantiator; public interface 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 ae8bb8a3ac2c..8e30c18e61a1 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; 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 af13a205f9c0..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,8 +30,6 @@ 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; 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/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 6e5160876b47..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,7 +24,6 @@ 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.component.SoftwareComponentInternal; import org.gradle.api.internal.component.UsageContext; import org.gradle.api.model.ObjectFactory; 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 a66ca5292c3a..499075cab8fd 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,9 +17,6 @@ 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.DefaultDomainObjectCollectionFactory; import org.gradle.api.internal.collections.DomainObjectCollectionFactory; import org.gradle.nativeplatform.NativeLibraryBinary; 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 3cb8c07dcbf9..aac354979db8 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; From 58500955f7f7b3a36cec97e5e3bc95526d6d28c7 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 May 2019 12:20:41 +0200 Subject: [PATCH 05/24] Update user manual custom plugin page to mention the ObjectFactory alternative --- .../docs/src/docs/userguide/custom_plugins.adoc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) 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] ---- From 2d4311fb6d1c4002d5a76c6444be9ca1bf87b8bf Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 May 2019 16:19:45 +0200 Subject: [PATCH 06/24] Fix checkstyle issues --- .../internal/resolve/CachingLibraryBinaryLocator.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 499075cab8fd..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 @@ -25,14 +25,14 @@ import java.util.Map; public class CachingLibraryBinaryLocator implements LibraryBinaryLocator { - private static DomainObjectSet NULL_RESULT; + private static DomainObjectSet nullResult; private final LibraryBinaryLocator delegate; private final Map> libraries = new HashMap>(); public CachingLibraryBinaryLocator(LibraryBinaryLocator delegate, DomainObjectCollectionFactory domainObjectCollectionFactory) { this.delegate = delegate; - if (NULL_RESULT == null) { - NULL_RESULT = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); + if (nullResult == null) { + nullResult = domainObjectCollectionFactory.newDomainObjectSet(NativeLibraryBinary.class); } } @@ -43,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; } } From 88e8122d46f6d95ea496d49f3a360617499536b5 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 May 2019 17:23:44 +0200 Subject: [PATCH 07/24] Fix missing constructor arguments for DefaultPluginManager --- .../gradle/internal/service/scopes/GradleScopeServices.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 0ed29396dd52..8aa8b7a1b593 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; @@ -258,9 +259,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) { From c1d374bf51329ed7fd89824c9daf42e370c528dd Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Fri, 17 May 2019 17:56:06 +0200 Subject: [PATCH 08/24] Add forgotten parameters to constructors when instantiating --- .../api/internal/plugins/DefaultPluginContainerTest.groovy | 2 +- .../artifacts/configurations/DefaultConfigurationSpec.groovy | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) 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 87410ed2bf6f..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, domainObjectCollectionFactory) + def pluginManager = new DefaultPluginManager(pluginRegistry, instantiator, target, new TestBuildOperationExecutor(), new DefaultUserCodeApplicationContext(), CollectionCallbackActionDecorator.NOOP, TestUtil.domainObjectCollectionFactory()) @Subject def container = pluginManager.pluginContainer 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) { From 21a1bc4da65bc96f1b4cc7dfd6c4156ea6d32977 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Fri, 17 May 2019 15:41:00 +0200 Subject: [PATCH 09/24] Fix Kotlin examples in documentation that produce extra null nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issue: #9384 Signed-off-by: Björn Kautler --- subprojects/docs/src/samples/eclipse/kotlin/build.gradle.kts | 2 +- subprojects/docs/src/samples/idea/kotlin/build.gradle.kts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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() } From 36fd9b35dbe1f6183e366f6c196ccfaccb25893f Mon Sep 17 00:00:00 2001 From: Paul Merlin Date: Sat, 18 May 2019 12:25:26 +0200 Subject: [PATCH 10/24] Recognize contributor in release notes Signed-off-by: Paul Merlin --- subprojects/docs/src/docs/release/notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index b7cff0cf12b7..1f1a4bb103ef 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -15,6 +15,7 @@ Include only their name, impactful features should be called out separately belo [Evgeny Mandrikov](https://github.com/Godin), [Stefan M.](https://github.com/StefMa), [Igor Melnichenko](https://github.com/Myllyenko), +[Björn Kautler](https://github.com/Vampire), [Roberto Perez Alcolea](https://github.com/rpalcolea) and [Christian Fränkel](https://github.com/fraenkelc) From 437a1481809ede905efbce925ccc9feefbf7988d Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Sun, 19 May 2019 10:13:24 -0400 Subject: [PATCH 11/24] Adjust worker API performance test to work with older versions of Gradle @Option wasn't introduced until 4.6 --- .../corefeature/WorkerApiPerformanceTest.groovy | 6 +++--- .../src/templates/workerApiProject/build.gradle | 4 +--- .../src/main/java/com/example/worker/WorkerPlugin.java | 10 +++++++++- .../src/main/java/com/example/worker/WorkerTask.java | 6 ------ 4 files changed, 13 insertions(+), 13 deletions(-) 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..fa6b8c8bb07d 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 @@ -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/WorkerPlugin.java b/subprojects/performance/src/templates/workerApiProject/buildSrc/src/main/java/com/example/worker/WorkerPlugin.java index 190ddb2c5375..dad1e7d044f1 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,13 @@ public void execute(WorkerTask workerTask) { workerTask.setIsolationMode(IsolationMode.PROCESS); } }); + + project.getTasks().withType(WorkerTask.class, new Action() { + @Override + public void execute(WorkerTask workerTask) { + int outputSize = Integer.valueOf(project.property("outputSize").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; } From 06314dc24601c490e68a00d60c44cf68345b9e7a Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Sun, 19 May 2019 20:03:14 -0400 Subject: [PATCH 12/24] Make the worker API perf project easier to inspect by hand --- .../buildSrc/src/main/java/com/example/worker/UnitOfWork.java | 2 +- .../src/main/java/com/example/worker/WorkerPlugin.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 dad1e7d044f1..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 @@ -44,7 +44,8 @@ public void execute(WorkerTask workerTask) { project.getTasks().withType(WorkerTask.class, new Action() { @Override public void execute(WorkerTask workerTask) { - int outputSize = Integer.valueOf(project.property("outputSize").toString()); + Object maybeOutputSize = project.findProperty("outputSize"); + int outputSize = Integer.valueOf(maybeOutputSize == null ? "1" : maybeOutputSize.toString()); workerTask.setOutputSize(outputSize); } }); From cabf33f466157992203f82ec2883022eb436cf5e Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Sun, 19 May 2019 20:04:14 -0400 Subject: [PATCH 13/24] Bump the minimum version of Gradle for worker API perf tests to 5.0 Earlier versions of Gradle seem to have a serious process/memory leak with larger worker pools or high number of work items. --- .../regression/corefeature/WorkerApiPerformanceTest.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fa6b8c8bb07d..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" } From 2b4d94c165cd3a5626c9c4e7fce1fec959da63c5 Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Mon, 20 May 2019 17:54:42 +0200 Subject: [PATCH 14/24] Fix failing `DefaultProjectTest` --- .../api/internal/project/DefaultProjectTest.groovy | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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) From a30c717d7caeb9f90d813bd31d61915ce8fed3fa Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Mon, 20 May 2019 14:59:48 -0400 Subject: [PATCH 15/24] More tests to reproduce the problems in all containers --- ...omainObjectContainerIntegrationTest.groovy | 34 +++++++++++++++++++ .../api/TaskContainerIntegrationTest.groovy | 15 ++++---- 2 files changed, 41 insertions(+), 8 deletions(-) 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" From c3bb6af8b074072cb7973bedd46ea702ab84d63d Mon Sep 17 00:00:00 2001 From: Sterling Greene Date: Mon, 20 May 2019 15:42:35 -0400 Subject: [PATCH 16/24] Delegate to underlying event register to enforce filtered views These two calls should be equivalent in behavior (maybe not performance) container.matching(pred).withType(type).all {} container.withType(type).matching(pred).all {} A regression was introduced that skipped honoring the matching(pred) when this was done first. --- .../CollectionCallbackActionDecorator.java | 1 - .../DefaultDomainObjectCollection.java | 10 ++++-- .../collections/CollectionEventRegister.java | 1 + .../DefaultCollectionEventRegister.java | 31 ++++++++----------- 4 files changed, 21 insertions(+), 22 deletions(-) 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 30f0c132dfd9..8fa41d947234 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 @@ -163,7 +163,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 @@ -214,11 +214,11 @@ public void whenObjectAdded(Closure action) { private Action addEagerAction(Action action) { store.realizePending(type); - return eventRegister.registerEagerAddAction(type, action); + return eventRegister.registerEagerAddAction(type, decorate(action)); } public Action whenObjectRemoved(Action action) { - eventRegister.registerRemoveAction(type, action); + eventRegister.registerRemoveAction(type, decorate(action)); return action; } @@ -226,6 +226,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); } } From ae4115855a76ddd099864cd9ad0e94fdd0d91b65 Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Tue, 21 May 2019 11:09:10 +0200 Subject: [PATCH 17/24] Add artifact transforms to release notes --- subprojects/docs/src/docs/release/notes.md | 17 +++++++++++++++++ .../docs/src/docs/release/release-features.txt | 3 ++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 1f1a4bb103ef..581540a237ee 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -37,6 +37,23 @@ Switch your build to use Gradle @version@ by updating your wrapper: `./gradlew wrapper --gradle-version=@version@` +## Transforming dependency artifacts on resolution + +A dependency’s artifacts can take many forms, some of which will be published but others may not be. +As an example, imagine you have a dependency on a JavaScript package. +Its producer publishes two variants: normal and minified. +As a consumer, you want to use the normal package for development. +But for production, you want to use an obfuscated version of the package rather than the simple minified version that’s published. + +Let’s say you want to get hold of the obfuscated version of a JavaScript package, but it’s not available in any repository. +Why not just retrieve the minified version and obfuscate it yourself? + +Gradle now allows you to register an _artifact transform_ to do just that, by hooking into the dependency management resolution engine. +You can specify that whenever an obfuscated JS package is requested but can’t be found, Gradle should run an artifact transform that performs the obfuscation and makes the resulting artifact available to the build. +The build won’t even be aware that the artifact transform has run. + +For more information have a look at the [user manual](userguide/dependency_management_attribute_based_matching.htmpl#sec:abm_artifact_transforms). + ## Build init plugin improvements ### Support for JUnit Jupiter diff --git a/subprojects/docs/src/docs/release/release-features.txt b/subprojects/docs/src/docs/release/release-features.txt index e776c537b1f7..d9c961363708 100644 --- a/subprojects/docs/src/docs/release/release-features.txt +++ b/subprojects/docs/src/docs/release/release-features.txt @@ -1,2 +1,3 @@ - Kickstart Gradle plugin development with gradle init - - Distribute organization-wide Gradle properties in custom Gradle distributions \ No newline at end of file + - Distribute organization-wide Gradle properties in custom Gradle distributions + - Transform dependency artifacts on resolution From 7d0afae21f144a8292d9af416627b691b231928d Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Tue, 21 May 2019 13:51:02 +0200 Subject: [PATCH 18/24] Add and fix links between chapters --- .../docs/userguide/building_cpp_projects.adoc | 18 +++++++----------- .../docs/userguide/cpp_application_plugin.adoc | 13 ++++++------- .../src/docs/userguide/cpp_library_plugin.adoc | 13 ++++++------- .../docs/src/docs/userguide/cpp_plugins.adoc | 14 ++++++++++++++ .../docs/src/docs/userguide/cpp_testing.adoc | 7 +++---- .../docs/userguide/cpp_unit_test_plugin.adoc | 10 +++++----- .../src/docs/userguide/more_about_tasks.adoc | 2 +- .../src/docs/userguide/publishing_ivy.adoc | 2 +- .../src/docs/userguide/publishing_maven.adoc | 2 +- 9 files changed, 44 insertions(+), 37 deletions(-) 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/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. From c28ca009eb9f381b486958f35d9d09401cd116de Mon Sep 17 00:00:00 2001 From: Daniel Lacasse Date: Tue, 21 May 2019 14:11:13 +0200 Subject: [PATCH 19/24] Update release note for native documentation --- subprojects/docs/src/docs/release/notes.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index af441d22245e..0e43aab43e75 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -51,7 +51,7 @@ The `init` task can now generate simple Gradle plugins. You can use these as a s See the [User manual](userguide/build_init_plugin.html) for more details. -### New factory method for creating `NamedDomainObjectContainer` and `DomainObjectSet` +## New factory methods for creating `NamedDomainObjectContainer` and `DomainObjectSet` The `ObjectFactory` can now be used for creating `NamedDomainObjectContainer` and `DomainObjectSet`. @@ -70,6 +70,12 @@ The upcoming 3.1.1 version of Buildship is required to take advantage of this be Contributed by [Christian Fränkel](https://github.com/fraenkelc) +## 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. From 4664bd07b69189d4f4f05dba8a168f6a1e75bb29 Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Tue, 21 May 2019 14:29:24 +0200 Subject: [PATCH 20/24] Use JVM packages instead of Javascript --- subprojects/docs/src/docs/release/notes.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 581540a237ee..eedfe691d863 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -40,16 +40,16 @@ Switch your build to use Gradle @version@ by updating your wrapper: ## Transforming dependency artifacts on resolution A dependency’s artifacts can take many forms, some of which will be published but others may not be. -As an example, imagine you have a dependency on a JavaScript package. -Its producer publishes two variants: normal and minified. -As a consumer, you want to use the normal package for development. -But for production, you want to use an obfuscated version of the package rather than the simple minified version that’s published. +As an example, imagine you have a dependency on a Java module. +Its producer publishes a normal JAR file and an obfuscated JAR file to a binary repository. +As a consumer, you want to use the normal JAR for development. +But for production, you want to use an obfuscated version of the JAR rather than the version that’s published. -Let’s say you want to get hold of the obfuscated version of a JavaScript package, but it’s not available in any repository. -Why not just retrieve the minified version and obfuscate it yourself? +Let’s say you want to get hold of the obfuscated JAR, but it’s not available in any repository. +Why not just retrieve the un-obfuscated JAR and obfuscate it yourself? Gradle now allows you to register an _artifact transform_ to do just that, by hooking into the dependency management resolution engine. -You can specify that whenever an obfuscated JS package is requested but can’t be found, Gradle should run an artifact transform that performs the obfuscation and makes the resulting artifact available to the build. +You can specify that whenever an obfuscated JAR is requested but can’t be found, Gradle should run an artifact transform that performs the obfuscation and makes the resulting artifact available to the build. The build won’t even be aware that the artifact transform has run. For more information have a look at the [user manual](userguide/dependency_management_attribute_based_matching.htmpl#sec:abm_artifact_transforms). From 8569ffc975b5f346b8e576d66b3fc8d09bb3e15e Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Tue, 21 May 2019 18:03:31 +0200 Subject: [PATCH 21/24] Polish release notes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lóránt Pintér --- subprojects/docs/src/docs/release/notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index eedfe691d863..3b52e1366138 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -50,7 +50,7 @@ Why not just retrieve the un-obfuscated JAR and obfuscate it yourself? Gradle now allows you to register an _artifact transform_ to do just that, by hooking into the dependency management resolution engine. You can specify that whenever an obfuscated JAR is requested but can’t be found, Gradle should run an artifact transform that performs the obfuscation and makes the resulting artifact available to the build. -The build won’t even be aware that the artifact transform has run. +The build won’t even be aware that the artifact was transformed. For more information have a look at the [user manual](userguide/dependency_management_attribute_based_matching.htmpl#sec:abm_artifact_transforms). From b1f0a843769b8651714df79f38e4b8a5381c5246 Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Tue, 21 May 2019 18:44:23 +0200 Subject: [PATCH 22/24] Polish release notes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lóránt Pintér --- subprojects/docs/src/docs/release/notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index 3b52e1366138..e7e0dec5328d 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -39,7 +39,7 @@ Switch your build to use Gradle @version@ by updating your wrapper: ## Transforming dependency artifacts on resolution -A dependency’s artifacts can take many forms, some of which will be published but others may not be. +A dependency’s artifacts can take many forms, and sometimes you might need them in a form that is not readily available in a published form. As an example, imagine you have a dependency on a Java module. Its producer publishes a normal JAR file and an obfuscated JAR file to a binary repository. As a consumer, you want to use the normal JAR for development. From a0e8d75944f93aaf74b17cdfd6e32f88d01a8bcc Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Tue, 21 May 2019 18:59:55 +0200 Subject: [PATCH 23/24] Fewer forms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Lóránt Pintér --- subprojects/docs/src/docs/release/notes.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subprojects/docs/src/docs/release/notes.md b/subprojects/docs/src/docs/release/notes.md index e7e0dec5328d..826490199f16 100644 --- a/subprojects/docs/src/docs/release/notes.md +++ b/subprojects/docs/src/docs/release/notes.md @@ -39,7 +39,7 @@ Switch your build to use Gradle @version@ by updating your wrapper: ## Transforming dependency artifacts on resolution -A dependency’s artifacts can take many forms, and sometimes you might need them in a form that is not readily available in a published form. +A dependency’s artifacts can take many forms, and sometimes you might need one that is not readily available. As an example, imagine you have a dependency on a Java module. Its producer publishes a normal JAR file and an obfuscated JAR file to a binary repository. As a consumer, you want to use the normal JAR for development. From b174d730be4e9615fca0d24560978ae3e182162c Mon Sep 17 00:00:00 2001 From: Stefan Wolf Date: Wed, 22 May 2019 08:14:56 +0200 Subject: [PATCH 24/24] Improve artifact transform API docs (#9452) By adding more samples and explanations to it. --- .../api/artifacts/dsl/DependencyHandler.java | 36 ++++++++ .../transform/CacheableTransform.java | 26 +++++- .../artifacts/transform/InputArtifact.java | 24 ++++- .../transform/InputArtifactDependencies.java | 28 +++++- .../artifacts/transform/TransformAction.java | 39 ++++++-- .../artifacts/transform/TransformOutputs.java | 88 ++++++++++++++++++- .../transform/TransformParameters.java | 18 ++++ .../artifacts/transform/TransformSpec.java | 9 ++ .../api/artifacts/transform/package-info.java | 9 +- 9 files changed, 261 insertions(+), 16 deletions(-) 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 + * } + * } + *

+ * + *
    + *
  • Do not implement {@link #getParameters()} in your class, the method will be implemented by Gradle.
  • + *
  • Implementations may only have a default constructor.
  • + *
  • Implementations can receive parameters by using annotated abstract getter methods.
  • + *
  • 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.
  • + *
  • A property annotated with {@link InputArtifactDependencies} will receive the dependencies of its input artifact.
  • + *
* * @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;