TAP5-2425: throw a meaningful exception when trying to use an abstract class as a service implementation
Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/b06c013f Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/b06c013f Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/b06c013f Branch: refs/heads/beanmodel-split Commit: b06c013f1719c455b46ed4b88b74b66fd963197a Parents: 23e512b Author: Jochen Kemnade <[email protected]> Authored: Thu Dec 4 20:38:32 2014 +0100 Committer: Jochen Kemnade <[email protected]> Committed: Thu Dec 4 20:38:32 2014 +0100 ---------------------------------------------------------------------- .../tapestry5/ioc/internal/IOCMessages.java | 5 ++++ .../ioc/internal/ServiceBinderImpl.java | 3 ++ .../ioc/internal/IOCStrings.properties | 3 +- .../ioc/specs/DefaultModuleDefImplSpec.groovy | 28 +++++++++++++++---- .../AbstractAutobuildServiceModule.java | 25 +++++++++++++++++ .../ioc/internal/AbstractRunnableService.java | 29 ++++++++++++++++++++ 6 files changed, 87 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java index 7584702..ac39d15 100644 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java +++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/IOCMessages.java @@ -187,6 +187,11 @@ final class IOCMessages return MESSAGES.format("no-constructor", implementationClass.getName(), serviceId); } + static String abstractServiceImplementation(Class implementationClass, String serviceId) + { + return MESSAGES.format("abstract-service-implementation", implementationClass.getName(), serviceId); + } + static String bindMethodMustBeStatic(String methodId) { return MESSAGES.format("bind-method-must-be-static", methodId); http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java index e7ec9e1..d93ed2e 100644 --- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java +++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java @@ -28,6 +28,7 @@ import org.apache.tapestry5.ioc.services.PlasticProxyFactory; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Set; @@ -140,6 +141,8 @@ public class ServiceBinderImpl implements ServiceBinder, ServiceBindingOptions private ObjectCreatorSource createStandardConstructorBasedObjectCreatorSource() { + if (Modifier.isAbstract(serviceImplementation.getModifiers())) + throw new RuntimeException(IOCMessages.abstractServiceImplementation(serviceImplementation, serviceId)); final Constructor constructor = InternalUtils.findAutobuildConstructor(serviceImplementation); if (constructor == null) http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties b/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties index 73fe7e7..6710b91 100644 --- a/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties +++ b/tapestry-ioc/src/main/resources/org/apache/tapestry5/ioc/internal/IOCStrings.properties @@ -65,4 +65,5 @@ overlapping-service-proxy-providers=Setting a new service proxy provider when th unexpected-service-proxy-provider=Unexpected service proxy provider when clearing the provider. This may indicate that you have multiple IoC Registries. no-proxy-provider=Service token for service '%s' can not be converted back into a proxy because no proxy provider has been registered. This may indicate that an IoC Registry has not been started yet. contribution-for-nonexistent-service=Contribution %s is for service '%s', which does not exist. -contribution-for-unqualified-service=Contribution %s is for service '%s' qualified with marker annotations %s, which does not exist. \ No newline at end of file +contribution-for-unqualified-service=Contribution %s is for service '%s' qualified with marker annotations %s, which does not exist. +abstract-service-implementation=Class %s (implementation of service '%s') is abstract. http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy index 91f6dc3..e46f469 100644 --- a/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy +++ b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy @@ -7,9 +7,12 @@ import org.apache.tapestry5.ioc.def.ServiceDef3 import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl import org.apache.tapestry5.ioc.services.PlasticProxyFactory import org.slf4j.Logger + +import spock.lang.Issue; import spock.lang.Shared import spock.lang.Specification import spock.lang.Unroll + import org.apache.tapestry5.ioc.* import org.apache.tapestry5.ioc.internal.* @@ -415,15 +418,15 @@ class DefaultModuleDefImplSpec extends Specification { def "Multiple marker annotations can be added to service via ServiceBindingOptions"() { when: - + def md = module MarkerModule def sd = md.getServiceDef "ColorfulGreeter" - + then: - + sd.markers == [RedMarker, BlueMarker] as Set } - + def "public synthetic methods on module class are ignored"() { def moduleClass = createSyntheticModuleClass() @@ -435,7 +438,7 @@ class DefaultModuleDefImplSpec extends Specification { md.serviceIds.size() == 1 } - + def "Methods overridden from Object are ignored"() { when: @@ -447,6 +450,21 @@ class DefaultModuleDefImplSpec extends Specification { md.serviceIds.size() == 1 } + @Issue('https://issues.apache.org/jira/browse/TAP5-2425') + def "a service implementation must not be abstract"() { + + when: + + module AbstractAutobuildServiceModule + + then: + + RuntimeException e = thrown() + + e.message.contains "Class org.apache.tapestry5.ioc.internal.AbstractRunnableService (implementation of service 'Runnable') is abstract." + + } + private createSyntheticModuleClass() { http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractAutobuildServiceModule.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractAutobuildServiceModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractAutobuildServiceModule.java new file mode 100644 index 0000000..13bc367 --- /dev/null +++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractAutobuildServiceModule.java @@ -0,0 +1,25 @@ +// Copyright 2007, 2010 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.internal; + +import org.apache.tapestry5.ioc.ServiceBinder; + +public class AbstractAutobuildServiceModule +{ + public static void bind(ServiceBinder binder) + { + binder.bind(Runnable.class, AbstractRunnableService.class).preventReloading(); + } +} http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/b06c013f/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractRunnableService.java ---------------------------------------------------------------------- diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractRunnableService.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractRunnableService.java new file mode 100644 index 0000000..978286a --- /dev/null +++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AbstractRunnableService.java @@ -0,0 +1,29 @@ +// Copyright 2014 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.internal; + +/** + * This service implementation is abstract, which triggers an exception. + */ +public abstract class AbstractRunnableService implements Runnable +{ + + + @Override + public void run() + { + } + +}
