This is an automated email from the ASF dual-hosted git repository. benw pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/tapestry-5.git
The following commit(s) were added to refs/heads/master by this push: new 3dc068e6a TAP5-2758: Treat @Symbol as explicit injection signal 3dc068e6a is described below commit 3dc068e6a33a4fbb9ab36d383b32f08647f50f76 Author: Ben Weidig <b...@netzgut.net> AuthorDate: Mon Apr 14 08:33:39 2025 +0200 TAP5-2758: Treat @Symbol as explicit injection signal The @Symbol annotation should be an explicit injection signal and not be autowired. That allows using @Symbol without an additional @Inject to force the behavior in certain scenarios. --- .../tapestry5/ioc/internal/util/InternalUtils.java | 19 ++++++- .../groovy/ioc/specs/DecorateWithSymbolSpec.groovy | 24 +++++++++ .../specs/ServiceBuilderMethodInvokerSpec.groovy | 20 ++++++++ .../test/internal/DecorateWithSymbolModule.java | 60 ++++++++++++++++++++++ .../test/internal/ServiceBuilderMethodFixture.java | 17 +++++- 5 files changed, 138 insertions(+), 2 deletions(-) diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java index 8b7b607f9..ad5da52a2 100644 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java +++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java @@ -1,4 +1,4 @@ -// Copyright 2006-2014 The Apache Software Foundation +// Copyright 2006-2025 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -205,6 +205,23 @@ public class InternalUtils return asObjectCreator(locator.getService(named.value(), injectionType)); } + + // TAP5-2758: An @Symbol is treated as an explicit signal that the injected value + // should not be autowired, but resolved using the MasterObjectProvider instead. + // The check needs to be done before the @Inject one, or the value is solely treated + // by its type. + // Without this check, if any configuration is used, no List/Collection/Map value as + // Symbol can be used without both @Inject and @Symbol, as @Symbol has no explicit + // meaning on how to inject the value, and the configuration detector strikes before + // the final fallback to the MasterObjectProvider. + + Symbol symbol = provider.getAnnotation(Symbol.class); + + if (symbol != null) + { + return asObjectCreator(locator.getObject(injectionType, provider)); + } + // In the absence of @InjectService, try some autowiring. First, does the // parameter type match one of the resources (the parameter defaults)? diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/DecorateWithSymbolSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/DecorateWithSymbolSpec.groovy new file mode 100644 index 000000000..dd4a89e45 --- /dev/null +++ b/tapestry-ioc/src/test/groovy/ioc/specs/DecorateWithSymbolSpec.groovy @@ -0,0 +1,24 @@ +package ioc.specs + +import org.apache.tapestry5.ioc.test.internal.DecorateWithSymbolModule +import org.apache.tapestry5.ioc.test.internal.FoeService + +import spock.lang.Issue + +@Issue("TAP5-2758") +class DecorateWithSymbolSpec extends AbstractRegistrySpecification { + + + def "ServiceDef obtainable by service id"() { + given: + buildRegistry DecorateWithSymbolModule + + when: + + def service = getService "FoeService", FoeService + + then: + service.foe() == DecorateWithSymbolModule.SYMBOL_VALUE + service.foe() != DecorateWithSymbolModule.ORIGINAL_VALUE + } +} diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ServiceBuilderMethodInvokerSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ServiceBuilderMethodInvokerSpec.groovy index 73109e17e..3b83fd3af 100644 --- a/tapestry-ioc/src/test/groovy/ioc/specs/ServiceBuilderMethodInvokerSpec.groovy +++ b/tapestry-ioc/src/test/groovy/ioc/specs/ServiceBuilderMethodInvokerSpec.groovy @@ -3,11 +3,13 @@ package ioc.specs import org.apache.tapestry5.commons.AnnotationProvider import org.apache.tapestry5.commons.ObjectCreator import org.apache.tapestry5.ioc.ServiceBuilderResources +import org.apache.tapestry5.ioc.internal.IOCMessages import org.apache.tapestry5.ioc.internal.ServiceBuilderMethodInvoker import org.apache.tapestry5.ioc.test.internal.FieService import org.apache.tapestry5.ioc.test.internal.FoeService import org.apache.tapestry5.ioc.test.internal.ServiceBuilderMethodFixture import org.slf4j.Logger +import spock.lang.Issue class ServiceBuilderMethodInvokerSpec extends AbstractSharedRegistrySpecification { @@ -150,6 +152,24 @@ class ServiceBuilderMethodInvokerSpec extends AbstractSharedRegistrySpecificatio 1 * resources.getUnorderedConfiguration(Runnable) >> configuration } + @Issue("TAP5-2758") + def "injection of ordered configuration as List and another List"() { + + List<Runnable> configuration = Mock() + + fixture.expectedConfiguration = configuration + + when: + + def actual = invoke "buildWithOrderedConfigurationAndList" + + then: + + RuntimeException e = thrown() + + e.message == IOCMessages.tooManyConfigurationParameters(DESCRIPTION) + } + def "builder method returns null"() { fixture.fie = null diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/DecorateWithSymbolModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/DecorateWithSymbolModule.java new file mode 100644 index 000000000..05288e82c --- /dev/null +++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/DecorateWithSymbolModule.java @@ -0,0 +1,60 @@ +// Copyright 2025 The Apache Software Foundation +// +// 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.apache.tapestry5.ioc.test.internal; + +import org.apache.tapestry5.commons.MappedConfiguration; +import org.apache.tapestry5.ioc.annotations.Contribute; +import org.apache.tapestry5.ioc.annotations.Decorate; +import org.apache.tapestry5.ioc.annotations.Match; +import org.apache.tapestry5.ioc.annotations.Symbol; +import org.apache.tapestry5.ioc.services.FactoryDefaults; +import org.apache.tapestry5.ioc.services.SymbolProvider; + +public class DecorateWithSymbolModule +{ + public static final String SYMBOL_KEY = "symbol-key"; + + public static final int ORIGINAL_VALUE = 23; + public static final int SYMBOL_VALUE = 42; + + @FactoryDefaults + @Contribute(SymbolProvider.class) + public static void contributeFactoryDefaults(MappedConfiguration<String, Object> conf) + { + conf.add(SYMBOL_KEY, SYMBOL_VALUE); + } + + public FoeService buildFoeService() + { + return new FoeService() + { + + @Override + public int foe() + { + return ORIGINAL_VALUE; + } + }; + } + + @Decorate(serviceInterface = FoeService.class) + @Match(value = "FoeService") + public static FoeService decorateSymbolService(FoeService delegate, + @Symbol(SYMBOL_KEY) + int symbolValue) + { + return () -> symbolValue; + } +} diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/ServiceBuilderMethodFixture.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/ServiceBuilderMethodFixture.java index 1f5fd9789..e4f9945f6 100644 --- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/ServiceBuilderMethodFixture.java +++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/test/internal/ServiceBuilderMethodFixture.java @@ -1,4 +1,4 @@ -// Copyright 2006, 2007, 2010, 2012 The Apache Software Foundation +// Copyright 2006, 2007, 2010, 2012, 2025 The Apache Software Foundation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.test.internal; import org.apache.tapestry5.ioc.ServiceResources; import org.apache.tapestry5.ioc.annotations.InjectService; +import org.apache.tapestry5.ioc.annotations.Symbol; import org.apache.tapestry5.ioc.annotations.Value; import org.slf4j.Logger; import org.testng.Assert; @@ -58,6 +59,20 @@ public class ServiceBuilderMethodFixture extends Assert return fie; } + public FieService buildWithOrderedConfigurationAndList(List<Runnable> configuration, List<Runnable> noConfiguration) + { + assertSame(configuration, expectedConfiguration); + + return fie; + } + + public FieService buildWithOrderedConfigurationAndSymbolList(List<Runnable> configuration, @Symbol("ignored") List<Runnable> noConfiguration) + { + assertSame(configuration, expectedConfiguration); + + return fie; + } + public void methodWithParameterizedList(List<Runnable> list) { }