You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by th...@apache.org on 2014/01/02 17:15:23 UTC

[1/3] TAP5-2029: Copy annotations from service implementation to proxy

Updated Branches:
  refs/heads/master ae473c840 -> 28df9e51c


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ReloadSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ReloadSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ReloadSpec.groovy
index 143f1b9..20f2bda 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ReloadSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ReloadSpec.groovy
@@ -311,7 +311,7 @@ class ReloadSpec extends Specification {
 
     Exception e = thrown()
 
-    e.message == "Service implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor."
+    e.message == "NonAnnotatedServiceInterface implementation class com.example.ReloadableServiceImpl does not have a suitable public constructor."
   }
 
   def "ensure ReloadAware services are notified when services are reloaded"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ServiceLookupSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ServiceLookupSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ServiceLookupSpec.groovy
index c976a73..7bee080 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ServiceLookupSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ServiceLookupSpec.groovy
@@ -36,7 +36,7 @@ class ServiceLookupSpec extends AbstractRegistrySpecification {
 
     RuntimeException e = thrown()
 
-    e.message.contains "Service id 'PeekABoo' is not defined by any module."
+    e.message.contains "NonAnnotatedServiceInterface id 'PeekABoo' is not defined by any module."
   }
 
   def "verify exception when accessing a service by type and there are no matching services"() {
@@ -65,7 +65,7 @@ class ServiceLookupSpec extends AbstractRegistrySpecification {
 
     RuntimeException e = thrown()
 
-    e.message == "Service interface org.apache.tapestry5.ioc.Pingable is matched by 2 services: Barney, Fred.  Automatic dependency resolution requires that exactly one service implement the interface."
+    e.message == "NonAnnotatedServiceInterface interface org.apache.tapestry5.ioc.Pingable is matched by 2 services: Barney, Fred.  Automatic dependency resolution requires that exactly one service implement the interface."
   }
 
   def "access to builtin service via marker annotation"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingConfigurationWrapperSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingConfigurationWrapperSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingConfigurationWrapperSpec.groovy
index c76cb3c..37899fb 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingConfigurationWrapperSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingConfigurationWrapperSpec.groovy
@@ -75,6 +75,6 @@ class ValidatingConfigurationWrapperSpec extends Specification {
 
     NullPointerException e = thrown()
 
-    e.message == "Service contribution (to service 'Baz') was null."
+    e.message == "NonAnnotatedServiceInterface contribution (to service 'Baz') was null."
   }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingMappedConfigurationWrapperSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingMappedConfigurationWrapperSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingMappedConfigurationWrapperSpec.groovy
index 60241a7..ea55ace 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingMappedConfigurationWrapperSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ValidatingMappedConfigurationWrapperSpec.groovy
@@ -97,7 +97,7 @@ class ValidatingMappedConfigurationWrapperSpec extends AbstractSharedRegistrySpe
 
     IllegalArgumentException e = thrown()
 
-    e.message.contains "Service contribution (to service 'Baz') conflicts with existing contribution"
+    e.message.contains "NonAnnotatedServiceInterface contribution (to service 'Baz') conflicts with existing contribution"
 
     keyToContribution[Integer].is(def1)
     map.isEmpty()
@@ -148,7 +148,7 @@ class ValidatingMappedConfigurationWrapperSpec extends AbstractSharedRegistrySpe
 
     NullPointerException e = thrown()
 
-    e.message == "Service contribution (to service 'Baz') was null."
+    e.message == "NonAnnotatedServiceInterface contribution (to service 'Baz') was null."
     map.isEmpty()
   }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ServiceProxySerializationSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ServiceProxySerializationSpec.groovy b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ServiceProxySerializationSpec.groovy
index a68ae6e..3acb289 100644
--- a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ServiceProxySerializationSpec.groovy
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ServiceProxySerializationSpec.groovy
@@ -53,7 +53,7 @@ class ServiceProxySerializationSpec extends AbstractRegistrySpecification {
 
     Exception e = thrown()
 
-    e.message.contains "Service token for service 'TypeCoercer' can not be converted back into a proxy because no proxy provider has been registered"
+    e.message.contains "NonAnnotatedServiceInterface token for service 'TypeCoercer' can not be converted back into a proxy because no proxy provider has been registered"
   }
 
   def serialize(object) {


[3/3] git commit: TAP5-2029: Copy annotations from service implementation to proxy

Posted by th...@apache.org.
TAP5-2029: Copy annotations from service implementation to proxy


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/28df9e51
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/28df9e51
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/28df9e51

Branch: refs/heads/master
Commit: 28df9e51cbdef90f5768595cfd2992f877c244cf
Parents: 4a818e3
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Thu Jan 2 14:14:49 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Thu Jan 2 14:14:49 2014 -0200

----------------------------------------------------------------------
 .../MethodInvocationGetAnnotationSpec.groovy    | 85 ++++++++++++++++++++
 .../tapestry5/ioc/internal/AdviceModule.java    | 41 ++++++++++
 .../ioc/internal/AnnotatedServiceInterface.java | 30 +++++++
 .../internal/AnnotatedServiceInterfaceImpl.java | 23 ++++++
 .../tapestry5/ioc/internal/DecoratorModule.java | 53 ++++++++++++
 .../internal/NonAnnotatedServiceInterface.java  | 24 ++++++
 .../NonAnnotatedServiceInterfaceImpl.java       | 28 +++++++
 .../tapestry5/ioc/internal/TestAdvice.java      | 55 +++++++++++++
 8 files changed, 339 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
new file mode 100644
index 0000000..b4e4c0e
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
@@ -0,0 +1,85 @@
+package ioc.specs
+
+import org.apache.tapestry5.beaneditor.ReorderProperties
+import org.apache.tapestry5.ioc.annotations.Advise
+import org.apache.tapestry5.ioc.internal.AdviceModule
+import org.apache.tapestry5.ioc.internal.AnnotatedServiceInterface
+import org.apache.tapestry5.ioc.internal.DecoratorModule
+import org.apache.tapestry5.ioc.internal.NonAnnotatedServiceInterface
+import org.apache.tapestry5.ioc.internal.TestAdvice
+
+/**
+ * Tests whether MethodAdvice.getAnnotation() is actually returning annotations from
+ * the service implementation methods and not from the service interface ones.
+ * The tests also verify whether the proxy annotations have the service implementation annotations
+ * and whether the service implementation annotations were copied the generated proxy class. 
+ * @see TestAdvice
+ */
+class MethodInvocationGetAnnotationSpec extends AbstractRegistrySpecification {
+
+  def "MethodAdvice.getAnnotation() and getMethod() in service decoration"() {
+    when:
+
+    buildRegistry DecoratorModule
+    
+	def nonAnnotatedService = registry.getService NonAnnotatedServiceInterface.class
+	def nonAnnotatedResult = nonAnnotatedService.execute(0);
+    def nonAnnotatedMethod = nonAnnotatedService.getClass().getMethod("execute", int.class);
+
+    def annotatedService = registry.getService AnnotatedServiceInterface.class
+    def annotatedResult = annotatedService.execute(0);
+    def annotatedMethod = annotatedService.getClass().getMethod("execute", int.class);
+
+    then:
+    nonAnnotatedMethod != null
+    nonAnnotatedMethod.getAnnotation(Advise.class) != null
+    nonAnnotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    nonAnnotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder") 
+	nonAnnotatedResult == TestAdvice.ANNOTATION_FOUND
+    
+    annotatedMethod != null
+    annotatedMethod.getAnnotation(Advise.class) != null
+    annotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    annotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    annotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    annotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    annotatedResult == TestAdvice.ANNOTATION_FOUND
+
+  }
+  
+  def "MethodAdvice.getAnnotation() and getMethod() in service advice"() {
+      
+    when:
+  
+    buildRegistry AdviceModule
+    
+    def nonAnnotatedService = registry.getService NonAnnotatedServiceInterface.class
+    def nonAnnotatedResult = nonAnnotatedService.execute(0);
+    def nonAnnotatedMethod = nonAnnotatedService.getClass().getMethod("execute", int.class);
+
+    def annotatedService = registry.getService AnnotatedServiceInterface
+    def annotatedResult = annotatedService.execute(0);
+    def annotatedMethod = annotatedService.getClass().getMethod("execute", int.class);
+    
+    then:
+    nonAnnotatedMethod != null
+    nonAnnotatedMethod.getAnnotation(Advise.class) != null
+    nonAnnotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    nonAnnotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    nonAnnotatedResult == TestAdvice.ANNOTATION_FOUND
+    
+    annotatedMethod != null
+    annotatedMethod.getAnnotation(Advise.class) != null
+    annotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    annotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    annotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    annotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    annotatedResult == TestAdvice.ANNOTATION_FOUND
+
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
new file mode 100644
index 0000000..466b528
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
@@ -0,0 +1,41 @@
+// Copyright 2013 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.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.annotations.Advise;
+
+public class AdviceModule
+{
+
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(NonAnnotatedServiceInterface.class, NonAnnotatedServiceInterfaceImpl.class);
+        binder.bind(AnnotatedServiceInterface.class, AnnotatedServiceInterfaceImpl.class);
+    }
+
+    @Advise(serviceInterface = NonAnnotatedServiceInterface.class)
+    public static void adviseNonAnnotatedServiceInterface(MethodAdviceReceiver methodAdviceReceiver)
+    {
+        methodAdviceReceiver.adviseAllMethods(new TestAdvice());
+    }
+
+    @Advise(serviceInterface = AnnotatedServiceInterface.class)
+    public static void adviseAnnotatedServiceInterface(MethodAdviceReceiver methodAdviceReceiver)
+    {
+        methodAdviceReceiver.adviseAllMethods(new TestAdvice());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
new file mode 100644
index 0000000..e2575fe
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
@@ -0,0 +1,30 @@
+// Copyright 2013 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.beaneditor.ReorderProperties;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+
+/**
+ * Service definition with annotations so we can test copying the service interface
+ * annotations, both in class and methods, to the service proxy.
+ */
+@ReorderProperties("reorder") // no meaning, just for testing whether the proxy will have it
+public interface AnnotatedServiceInterface {
+
+    @Advise(id = "id", serviceInterface = NonAnnotatedServiceInterface.class)
+	public String execute(@IntermediateType(String.class) int i); 
+	
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
new file mode 100644
index 0000000..36db723
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
@@ -0,0 +1,23 @@
+// Copyright 2013 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;
+
+
+public class AnnotatedServiceInterfaceImpl implements AnnotatedServiceInterface {
+
+	public String execute(int i) {
+		return null;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
new file mode 100644
index 0000000..ebe972a
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
@@ -0,0 +1,53 @@
+// Copyright 2013 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;
+import org.apache.tapestry5.ioc.annotations.Decorate;
+import org.apache.tapestry5.ioc.services.AspectDecorator;
+import org.apache.tapestry5.ioc.services.AspectInterceptorBuilder;
+
+/**
+ * @author Thiago H. de Paula Figueiredo (http://machina.com.br/thiago)
+ */
+public class DecoratorModule
+{
+
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(NonAnnotatedServiceInterface.class, NonAnnotatedServiceInterfaceImpl.class);
+        binder.bind(AnnotatedServiceInterface.class, AnnotatedServiceInterfaceImpl.class);
+    }
+
+    @Decorate(serviceInterface = AnnotatedServiceInterface.class)
+    public static AnnotatedServiceInterface decorateAnnotated(AnnotatedServiceInterface delegate,
+            AspectDecorator aspectDecorator)
+    {
+        final AspectInterceptorBuilder<AnnotatedServiceInterface> builder = aspectDecorator
+                .createBuilder(AnnotatedServiceInterface.class, delegate, "!");
+        builder.adviseAllMethods(new TestAdvice());
+        return builder.build();
+    }
+
+    @Decorate(serviceInterface = NonAnnotatedServiceInterface.class)
+    public static NonAnnotatedServiceInterface decorateNonAnnotated(
+            NonAnnotatedServiceInterface delegate, AspectDecorator aspectDecorator)
+    {
+        final AspectInterceptorBuilder<NonAnnotatedServiceInterface> builder = aspectDecorator
+                .createBuilder(NonAnnotatedServiceInterface.class, delegate, "!");
+        builder.adviseAllMethods(new TestAdvice());
+        return builder.build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
new file mode 100644
index 0000000..4270d1e
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
@@ -0,0 +1,24 @@
+// Copyright 2013 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;
+
+/**
+ * Service definition without any annotations so we can test copying the service implementation
+ * annotations, both in class and methods, to the service proxy.
+ */
+public interface NonAnnotatedServiceInterface {
+
+	public String execute(int i);
+	
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
new file mode 100644
index 0000000..efa408d
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
@@ -0,0 +1,28 @@
+// Copyright 2013 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.beaneditor.ReorderProperties;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+
+@ReorderProperties("reorder") // no meaning, just for testing whether the proxy will have it
+public class NonAnnotatedServiceInterfaceImpl implements NonAnnotatedServiceInterface {
+
+	@Advise(id = "id", serviceInterface = NonAnnotatedServiceInterface.class)
+	public String execute(@IntermediateType(String.class) int i) { // annotation just for checking too
+		return null;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
new file mode 100644
index 0000000..f7ca811
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
@@ -0,0 +1,55 @@
+// Copyright 2013 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 java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodInvocation;
+
+final public class TestAdvice implements MethodAdvice {
+
+	public static final String ANNOTATION_FOUND = "Annotation found!";
+
+	public void advise(MethodInvocation invocation) {
+
+		final Method method = invocation.getMethod();
+        boolean annotationFoundInMethod = checkAnnotation(method.getAnnotation(Advise.class));
+		boolean annotationFoundThroughAnnotationProvider = checkAnnotation(invocation.getAnnotation(Advise.class));
+		IntermediateType parameterAnnotation = null;
+		final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+		if (parameterAnnotations.length > 0 && parameterAnnotations[0].length > 0) {
+		    parameterAnnotation = (IntermediateType) parameterAnnotations[0][0];
+		}
+        boolean annotationParameter = parameterAnnotation != null && parameterAnnotation.value() == String.class;
+		
+		if (annotationFoundInMethod && annotationFoundThroughAnnotationProvider && annotationParameter) 
+		{
+			invocation.setReturnValue(ANNOTATION_FOUND);
+		}
+		else {
+			invocation.proceed();
+		}
+		
+	}
+
+    private boolean checkAnnotation(Advise annotation)
+    {
+        return annotation != null && "id".equals(annotation.id()) && NonAnnotatedServiceInterface.class.equals(annotation.serviceInterface());
+    }
+	
+}
\ No newline at end of file


[3/3] git commit: TAP5-2029: Copy annotations from service implementation to proxy

Posted by th...@apache.org.
TAP5-2029: Copy annotations from service implementation to proxy


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/28df9e51
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/28df9e51
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/28df9e51

Branch: refs/heads/master
Commit: 28df9e51cbdef90f5768595cfd2992f877c244cf
Parents: 4a818e3
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Thu Jan 2 14:14:49 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Thu Jan 2 14:14:49 2014 -0200

----------------------------------------------------------------------
 .../MethodInvocationGetAnnotationSpec.groovy    | 85 ++++++++++++++++++++
 .../tapestry5/ioc/internal/AdviceModule.java    | 41 ++++++++++
 .../ioc/internal/AnnotatedServiceInterface.java | 30 +++++++
 .../internal/AnnotatedServiceInterfaceImpl.java | 23 ++++++
 .../tapestry5/ioc/internal/DecoratorModule.java | 53 ++++++++++++
 .../internal/NonAnnotatedServiceInterface.java  | 24 ++++++
 .../NonAnnotatedServiceInterfaceImpl.java       | 28 +++++++
 .../tapestry5/ioc/internal/TestAdvice.java      | 55 +++++++++++++
 8 files changed, 339 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
new file mode 100644
index 0000000..b4e4c0e
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/MethodInvocationGetAnnotationSpec.groovy
@@ -0,0 +1,85 @@
+package ioc.specs
+
+import org.apache.tapestry5.beaneditor.ReorderProperties
+import org.apache.tapestry5.ioc.annotations.Advise
+import org.apache.tapestry5.ioc.internal.AdviceModule
+import org.apache.tapestry5.ioc.internal.AnnotatedServiceInterface
+import org.apache.tapestry5.ioc.internal.DecoratorModule
+import org.apache.tapestry5.ioc.internal.NonAnnotatedServiceInterface
+import org.apache.tapestry5.ioc.internal.TestAdvice
+
+/**
+ * Tests whether MethodAdvice.getAnnotation() is actually returning annotations from
+ * the service implementation methods and not from the service interface ones.
+ * The tests also verify whether the proxy annotations have the service implementation annotations
+ * and whether the service implementation annotations were copied the generated proxy class. 
+ * @see TestAdvice
+ */
+class MethodInvocationGetAnnotationSpec extends AbstractRegistrySpecification {
+
+  def "MethodAdvice.getAnnotation() and getMethod() in service decoration"() {
+    when:
+
+    buildRegistry DecoratorModule
+    
+	def nonAnnotatedService = registry.getService NonAnnotatedServiceInterface.class
+	def nonAnnotatedResult = nonAnnotatedService.execute(0);
+    def nonAnnotatedMethod = nonAnnotatedService.getClass().getMethod("execute", int.class);
+
+    def annotatedService = registry.getService AnnotatedServiceInterface.class
+    def annotatedResult = annotatedService.execute(0);
+    def annotatedMethod = annotatedService.getClass().getMethod("execute", int.class);
+
+    then:
+    nonAnnotatedMethod != null
+    nonAnnotatedMethod.getAnnotation(Advise.class) != null
+    nonAnnotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    nonAnnotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder") 
+	nonAnnotatedResult == TestAdvice.ANNOTATION_FOUND
+    
+    annotatedMethod != null
+    annotatedMethod.getAnnotation(Advise.class) != null
+    annotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    annotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    annotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    annotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    annotatedResult == TestAdvice.ANNOTATION_FOUND
+
+  }
+  
+  def "MethodAdvice.getAnnotation() and getMethod() in service advice"() {
+      
+    when:
+  
+    buildRegistry AdviceModule
+    
+    def nonAnnotatedService = registry.getService NonAnnotatedServiceInterface.class
+    def nonAnnotatedResult = nonAnnotatedService.execute(0);
+    def nonAnnotatedMethod = nonAnnotatedService.getClass().getMethod("execute", int.class);
+
+    def annotatedService = registry.getService AnnotatedServiceInterface
+    def annotatedResult = annotatedService.execute(0);
+    def annotatedMethod = annotatedService.getClass().getMethod("execute", int.class);
+    
+    then:
+    nonAnnotatedMethod != null
+    nonAnnotatedMethod.getAnnotation(Advise.class) != null
+    nonAnnotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    nonAnnotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    nonAnnotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    nonAnnotatedResult == TestAdvice.ANNOTATION_FOUND
+    
+    annotatedMethod != null
+    annotatedMethod.getAnnotation(Advise.class) != null
+    annotatedMethod.getAnnotation(Advise.class).id().equals("id")
+    annotatedMethod.getAnnotation(Advise.class).serviceInterface() == NonAnnotatedServiceInterface.class
+    annotatedService.getClass().getAnnotation(ReorderProperties.class) != null
+    annotatedService.getClass().getAnnotation(ReorderProperties.class).value().equals("reorder")
+    annotatedResult == TestAdvice.ANNOTATION_FOUND
+
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
new file mode 100644
index 0000000..466b528
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AdviceModule.java
@@ -0,0 +1,41 @@
+// Copyright 2013 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.MethodAdviceReceiver;
+import org.apache.tapestry5.ioc.ServiceBinder;
+import org.apache.tapestry5.ioc.annotations.Advise;
+
+public class AdviceModule
+{
+
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(NonAnnotatedServiceInterface.class, NonAnnotatedServiceInterfaceImpl.class);
+        binder.bind(AnnotatedServiceInterface.class, AnnotatedServiceInterfaceImpl.class);
+    }
+
+    @Advise(serviceInterface = NonAnnotatedServiceInterface.class)
+    public static void adviseNonAnnotatedServiceInterface(MethodAdviceReceiver methodAdviceReceiver)
+    {
+        methodAdviceReceiver.adviseAllMethods(new TestAdvice());
+    }
+
+    @Advise(serviceInterface = AnnotatedServiceInterface.class)
+    public static void adviseAnnotatedServiceInterface(MethodAdviceReceiver methodAdviceReceiver)
+    {
+        methodAdviceReceiver.adviseAllMethods(new TestAdvice());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
new file mode 100644
index 0000000..e2575fe
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterface.java
@@ -0,0 +1,30 @@
+// Copyright 2013 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.beaneditor.ReorderProperties;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+
+/**
+ * Service definition with annotations so we can test copying the service interface
+ * annotations, both in class and methods, to the service proxy.
+ */
+@ReorderProperties("reorder") // no meaning, just for testing whether the proxy will have it
+public interface AnnotatedServiceInterface {
+
+    @Advise(id = "id", serviceInterface = NonAnnotatedServiceInterface.class)
+	public String execute(@IntermediateType(String.class) int i); 
+	
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
new file mode 100644
index 0000000..36db723
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/AnnotatedServiceInterfaceImpl.java
@@ -0,0 +1,23 @@
+// Copyright 2013 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;
+
+
+public class AnnotatedServiceInterfaceImpl implements AnnotatedServiceInterface {
+
+	public String execute(int i) {
+		return null;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
new file mode 100644
index 0000000..ebe972a
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/DecoratorModule.java
@@ -0,0 +1,53 @@
+// Copyright 2013 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;
+import org.apache.tapestry5.ioc.annotations.Decorate;
+import org.apache.tapestry5.ioc.services.AspectDecorator;
+import org.apache.tapestry5.ioc.services.AspectInterceptorBuilder;
+
+/**
+ * @author Thiago H. de Paula Figueiredo (http://machina.com.br/thiago)
+ */
+public class DecoratorModule
+{
+
+    public static void bind(ServiceBinder binder)
+    {
+        binder.bind(NonAnnotatedServiceInterface.class, NonAnnotatedServiceInterfaceImpl.class);
+        binder.bind(AnnotatedServiceInterface.class, AnnotatedServiceInterfaceImpl.class);
+    }
+
+    @Decorate(serviceInterface = AnnotatedServiceInterface.class)
+    public static AnnotatedServiceInterface decorateAnnotated(AnnotatedServiceInterface delegate,
+            AspectDecorator aspectDecorator)
+    {
+        final AspectInterceptorBuilder<AnnotatedServiceInterface> builder = aspectDecorator
+                .createBuilder(AnnotatedServiceInterface.class, delegate, "!");
+        builder.adviseAllMethods(new TestAdvice());
+        return builder.build();
+    }
+
+    @Decorate(serviceInterface = NonAnnotatedServiceInterface.class)
+    public static NonAnnotatedServiceInterface decorateNonAnnotated(
+            NonAnnotatedServiceInterface delegate, AspectDecorator aspectDecorator)
+    {
+        final AspectInterceptorBuilder<NonAnnotatedServiceInterface> builder = aspectDecorator
+                .createBuilder(NonAnnotatedServiceInterface.class, delegate, "!");
+        builder.adviseAllMethods(new TestAdvice());
+        return builder.build();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
new file mode 100644
index 0000000..4270d1e
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterface.java
@@ -0,0 +1,24 @@
+// Copyright 2013 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;
+
+/**
+ * Service definition without any annotations so we can test copying the service implementation
+ * annotations, both in class and methods, to the service proxy.
+ */
+public interface NonAnnotatedServiceInterface {
+
+	public String execute(int i);
+	
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
new file mode 100644
index 0000000..efa408d
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/NonAnnotatedServiceInterfaceImpl.java
@@ -0,0 +1,28 @@
+// Copyright 2013 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.beaneditor.ReorderProperties;
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+
+@ReorderProperties("reorder") // no meaning, just for testing whether the proxy will have it
+public class NonAnnotatedServiceInterfaceImpl implements NonAnnotatedServiceInterface {
+
+	@Advise(id = "id", serviceInterface = NonAnnotatedServiceInterface.class)
+	public String execute(@IntermediateType(String.class) int i) { // annotation just for checking too
+		return null;
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/28df9e51/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
new file mode 100644
index 0000000..f7ca811
--- /dev/null
+++ b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/TestAdvice.java
@@ -0,0 +1,55 @@
+// Copyright 2013 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 java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+import org.apache.tapestry5.ioc.annotations.Advise;
+import org.apache.tapestry5.ioc.annotations.IntermediateType;
+import org.apache.tapestry5.plastic.MethodAdvice;
+import org.apache.tapestry5.plastic.MethodInvocation;
+
+final public class TestAdvice implements MethodAdvice {
+
+	public static final String ANNOTATION_FOUND = "Annotation found!";
+
+	public void advise(MethodInvocation invocation) {
+
+		final Method method = invocation.getMethod();
+        boolean annotationFoundInMethod = checkAnnotation(method.getAnnotation(Advise.class));
+		boolean annotationFoundThroughAnnotationProvider = checkAnnotation(invocation.getAnnotation(Advise.class));
+		IntermediateType parameterAnnotation = null;
+		final Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+		if (parameterAnnotations.length > 0 && parameterAnnotations[0].length > 0) {
+		    parameterAnnotation = (IntermediateType) parameterAnnotations[0][0];
+		}
+        boolean annotationParameter = parameterAnnotation != null && parameterAnnotation.value() == String.class;
+		
+		if (annotationFoundInMethod && annotationFoundThroughAnnotationProvider && annotationParameter) 
+		{
+			invocation.setReturnValue(ANNOTATION_FOUND);
+		}
+		else {
+			invocation.proceed();
+		}
+		
+	}
+
+    private boolean checkAnnotation(Advise annotation)
+    {
+        return annotation != null && "id".equals(annotation.id()) && NonAnnotatedServiceInterface.class.equals(annotation.serviceInterface());
+    }
+	
+}
\ No newline at end of file


[2/3] git commit: TAP5-2029: Copy annotations from service implementation to proxy

Posted by th...@apache.org.
TAP5-2029: Copy annotations from service implementation to proxy


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/4a818e35
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/4a818e35
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/4a818e35

Branch: refs/heads/master
Commit: 4a818e35585ac0860aaffa23bc0d1799514480da
Parents: ae473c8
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Thu Jan 2 14:13:12 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Thu Jan 2 14:13:12 2014 -0200

----------------------------------------------------------------------
 .../internal/plastic/InheritanceData.java       |  4 +-
 .../internal/plastic/PlasticClassImpl.java      | 83 +++++++++++++++++++-
 .../internal/plastic/PlasticClassPool.java      | 75 +++++++++++++++---
 .../tapestry5/plastic/PlasticManager.java       | 28 ++++++-
 .../services/ComponentTemplateSourceImpl.java   |  2 +-
 .../internal/services/PageMarkupRenderer.java   |  2 +-
 .../internal/services/PageResponseRenderer.java |  2 +-
 .../ServiceAnnotationObjectProvider.java        |  2 +-
 .../tapestry5/modules/TapestryModule.java       | 18 ++---
 .../services/ApplicationInitializer.java        |  2 +-
 .../services/ClasspathAssetAliasManager.java    |  2 +-
 .../services/RequestExceptionHandler.java       |  2 +-
 .../tapestry5/services/RequestGlobals.java      |  2 +-
 .../tapestry5/services/RequestHandler.java      |  2 +-
 .../services/ServletApplicationInitializer.java |  2 +-
 .../apache/tapestry5/services/URLEncoder.java   |  2 +-
 .../assets/StreamableResourceSource.java        |  2 +-
 .../tapestry5/services/meta/MetaWorker.java     |  2 +-
 .../integration/app1/CoreBehaviorsTests.java    |  4 +-
 .../tapestry5/integration/app1/pages/Index.java |  6 +-
 .../org/apache/tapestry5/ioc/AdvisorDef.java    |  2 +-
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  2 +-
 .../apache/tapestry5/ioc/ServiceResources.java  | 14 ++--
 .../tapestry5/ioc/annotations/EagerLoad.java    |  2 +-
 .../annotations/PreventServiceDecoration.java   |  2 +-
 .../apache/tapestry5/ioc/def/DecoratorDef.java  |  2 +-
 .../apache/tapestry5/ioc/def/ServiceDef.java    |  6 +-
 .../apache/tapestry5/ioc/def/ServiceDef3.java   | 11 +++
 .../ioc/internal/EagerLoadServiceProxy.java     |  2 +-
 .../tapestry5/ioc/internal/ModuleImpl.java      | 16 ++--
 .../tapestry5/ioc/internal/RegistryImpl.java    |  4 +-
 .../internal/ReloadableObjectCreatorSource.java |  2 +-
 ...dableServiceImplementationObjectCreator.java |  2 +-
 .../tapestry5/ioc/internal/ServiceDefImpl.java  |  5 ++
 .../ioc/internal/ServiceResourcesImpl.java      |  5 ++
 .../internal/services/AspectDecoratorImpl.java  |  2 +-
 .../services/AspectInterceptorBuilderImpl.java  |  2 +-
 .../services/PerThreadServiceLifecycle.java     |  2 +-
 .../services/PlasticProxyFactoryImpl.java       | 24 +++++-
 .../ioc/internal/util/InternalUtils.java        |  7 ++
 .../util/WrongConfigurationTypeGuard.java       |  2 +-
 .../ioc/services/LoggingDecorator.java          |  2 +-
 .../ioc/services/PlasticProxyFactory.java       | 52 ++++++++++++
 .../ioc/services/RegistryShutdownListener.java  |  2 +-
 .../groovy/ioc/specs/BridgeBuilderSpec.groovy   |  2 +-
 .../ioc/specs/ContributionDefImplSpec.groovy    |  2 +-
 .../ioc/specs/DefaultModuleDefImplSpec.groovy   |  2 +-
 .../groovy/ioc/specs/PerThreadScopeSpec.groovy  |  2 +-
 ...istryConstructionAndRuntimeErrorsSpec.groovy |  2 +-
 .../src/test/groovy/ioc/specs/ReloadSpec.groovy |  2 +-
 .../groovy/ioc/specs/ServiceLookupSpec.groovy   |  4 +-
 .../ValidatingConfigurationWrapperSpec.groovy   |  2 +-
 ...idatingMappedConfigurationWrapperSpec.groovy |  4 +-
 .../ServiceProxySerializationSpec.groovy        |  2 +-
 54 files changed, 349 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
index 17d90d2..ab7a17f 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
@@ -119,7 +119,9 @@ public class InheritanceData
     }
 
     public void addInterface(String name) {
-        interfaceNames.add(name);
+        if (!interfaceNames.contains(name)) {
+            interfaceNames.add(name);
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
index a0e88d4..e12ef71 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
@@ -14,11 +14,13 @@
 
 package org.apache.tapestry5.internal.plastic;
 
+import org.apache.tapestry5.internal.plastic.asm.ClassReader;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.plastic.*;
 
+import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -166,28 +168,34 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
     // Set of methods that need to contribute to the shim and gain access to it
 
     final Set<PlasticMethodImpl> shimMethods = PlasticInternalUtils.newSet();
+    
+    final ClassNode implementationClassNode;
+    
+    private ClassNode interfaceClassNode;
 
     /**
      * @param classNode
+     * @param implementationClassNode
      * @param pool
      * @param parentInheritanceData
      * @param parentStaticContext
      * @param proxy
      */
-    public PlasticClassImpl(ClassNode classNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
+    public PlasticClassImpl(ClassNode classNode, ClassNode implementationClassNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
                             StaticContext parentStaticContext, boolean proxy)
     {
         this.classNode = classNode;
         this.pool = pool;
         this.proxy = proxy;
-
+        this.implementationClassNode = implementationClassNode;
+        
         staticContext = parentStaticContext.dupe();
 
         className = PlasticInternalUtils.toClassName(classNode.name);
         superClassName = PlasticInternalUtils.toClassName(classNode.superName);
 
         fieldInstrumentations = new FieldInstrumentations(classNode.superName);
-
+        
         annotationAccess = new DelegatingAnnotationAccess(pool.createAnnotationAccess(classNode.visibleAnnotations),
                 pool.createAnnotationAccess(superClassName));
 
@@ -326,6 +334,32 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
 
         return annotationAccess.getAnnotation(annotationType);
     }
+    
+    private static void copyAnnotationsFromServiceImplementation(MethodNode methodNode, ClassNode source)
+    {
+        if (source != null)
+        {
+        
+            for (MethodNode implementationNode : source.methods)
+            {
+                // Find corresponding method in the implementation class MethodNode
+                if (methodNode.name.equals(implementationNode.name) && methodNode.desc.equals(implementationNode.desc))
+                {
+                    implementationNode.accept(methodNode);
+                    
+                    // We want to copy just annotations, not code.
+                    methodNode.instructions.clear();
+                    methodNode.instructions.resetLabels();
+                    
+                    break;
+                    
+                }
+                
+            }
+            
+        }
+        
+    }
 
     public PlasticClass proxyInterface(Class interfaceType, PlasticField field)
     {
@@ -346,6 +380,8 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
     public ClassInstantiator createInstantiator()
     {
         lock();
+        
+        addClassAnnotations(implementationClassNode);
 
         createShimIfNeeded();
 
@@ -360,6 +396,29 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
         return createInstantiatorFromClass(transformedClass);
     }
 
+    private void addClassAnnotations(ClassNode otherClassNode)
+    {
+        // Copy annotations from implementation if available.
+        // Code adapted from ClassNode.accept(), as we just want to copy
+        // the annotations and nothing more.
+        if (otherClassNode != null) 
+        {
+            
+            int i, n;
+            n = otherClassNode.visibleAnnotations == null ? 0 : otherClassNode.visibleAnnotations.size();
+            for (i = 0; i < n; ++i) {
+                AnnotationNode an = otherClassNode.visibleAnnotations.get(i);
+                an.accept(classNode.visitAnnotation(an.desc, true));
+            }
+            n = otherClassNode.invisibleAnnotations == null ? 0 : otherClassNode.invisibleAnnotations.size();
+            for (i = 0; i < n; ++i) {
+                AnnotationNode an = otherClassNode.invisibleAnnotations.get(i);
+                an.accept(classNode.visitAnnotation(an.desc, false));
+            }
+            
+        }
+    }
+
     private ClassInstantiator createInstantiatorFromClass(Class clazz)
     {
         try
@@ -674,6 +733,11 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
         MethodNode methodNode = new MethodNode(description.modifiers, description.methodName, desc,
                 description.genericSignature, exceptions);
         boolean isOverride = inheritanceData.isImplemented(methodNode.name, desc);
+        
+        if (!isOverride) {
+            copyAnnotationsFromServiceImplementation(methodNode, interfaceClassNode);
+            copyAnnotationsFromServiceImplementation(methodNode, implementationClassNode);
+        }
 
         if (isOverride)
             createOverrideOfBaseClassImpl(description, methodNode);
@@ -1065,12 +1129,23 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
                     "Class %s is not an interface; ony interfaces may be introduced.", interfaceType.getName()));
 
         String interfaceName = nameCache.toInternalName(interfaceType);
+        
+        try
+        {
+            interfaceClassNode = PlasticClassPool.readClassNode(interfaceType.getName(), getClass().getClassLoader());
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
 
         if (!inheritanceData.isInterfaceImplemented(interfaceName))
         {
             classNode.interfaces.add(interfaceName);
             inheritanceData.addInterface(interfaceName);
         }
+        
+        addClassAnnotations(interfaceClassNode);
 
         Set<PlasticMethod> introducedMethods = new HashSet<PlasticMethod>();
 
@@ -1083,6 +1158,8 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
                 introducedMethods.add(introduceMethod(m));
             }
         }
+        
+        interfaceClassNode = null;
 
         return introducedMethods;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
index 5d38c0c..41ce961 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
@@ -20,6 +20,9 @@ import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.plastic.*;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Modifier;
 import java.util.*;
@@ -86,6 +89,9 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
 
     private final Map<String, FieldInstrumentations> instrumentations = PlasticInternalUtils.newMap();
 
+    private final Map<String, String> transformedClassNameToImplementationClassName = PlasticInternalUtils.newMap();
+    
+
     private final FieldInstrumentations placeholder = new FieldInstrumentations(null);
 
 
@@ -120,7 +126,6 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         synchronized (loader)
         {
             Class result = realize(PlasticInternalUtils.toClassName(classNode.name), ClassType.PRIMARY, classNode);
-
             baseClassDefs.put(result.getName(), new BaseClassDef(inheritanceData, staticContext));
 
             return result;
@@ -434,17 +439,19 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         String baseClassName = PlasticInternalUtils.toClassName(classNode.superName);
 
         instrumentations.put(classNode.name, new FieldInstrumentations(classNode.superName));
-
-        return createTransformation(baseClassName, classNode, false);
+        
+        // TODO: check whether second parameter should really be null
+        return createTransformation(baseClassName, classNode, null, false); 
     }
 
     /**
      * @param baseClassName class from which the transformed class extends
      * @param classNode     node for the class
+     * @param implementationClassNode     node for the implementation class. May be null.
      * @param proxy         if true, the class is a new empty class; if false an existing class that's being transformed
      * @throws ClassNotFoundException
      */
-    private InternalPlasticClassTransformation createTransformation(String baseClassName, ClassNode classNode, boolean proxy)
+    private InternalPlasticClassTransformation createTransformation(String baseClassName, ClassNode classNode, ClassNode implementationClassNode, boolean proxy)
             throws ClassNotFoundException
     {
         if (shouldInterceptClassLoading(baseClassName))
@@ -455,12 +462,12 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
 
             assert def != null;
 
-            return new PlasticClassImpl(classNode, this, def.inheritanceData, def.staticContext, proxy);
+            return new PlasticClassImpl(classNode, implementationClassNode, this, def.inheritanceData, def.staticContext, proxy);
         }
 
         // When the base class is Object, or otherwise not in a transformed package,
         // then start with the empty
-        return new PlasticClassImpl(classNode, this, emptyInheritanceData, emptyStaticContext, proxy);
+        return new PlasticClassImpl(classNode, implementationClassNode, this, emptyInheritanceData, emptyStaticContext, proxy);
     }
 
     /**
@@ -487,21 +494,69 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         return PlasticInternalUtils.readBytecodeForClass(parentClassLoader, className, true);
     }
 
-    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName)
+    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName) {
+        return createTransformation(baseClassName, newClassName, null);
+    }
+    
+    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName, String implementationClassName)
     {
         try
         {
             ClassNode newClassNode = new ClassNode();
 
-            newClassNode.visit(V1_5, ACC_PUBLIC, PlasticInternalUtils.toInternalName(newClassName), null,
-                    PlasticInternalUtils.toInternalName(baseClassName), null);
+            final String internalNewClassNameinternalName = PlasticInternalUtils.toInternalName(newClassName);
+            final String internalBaseClassName = PlasticInternalUtils.toInternalName(baseClassName);
+            newClassNode.visit(V1_5, ACC_PUBLIC, internalNewClassNameinternalName, null, internalBaseClassName, null);
+            
+            ClassNode implementationClassNode = null;
+            
+            if (implementationClassName != null)
+            {
+                // When decorating or advising a service, implementationClassName is the name
+                // of a proxy class already, such as "$ServiceName_[random string]",
+                // which doesn't exist as a file in the classpath, just in memory.
+                // So we need to keep what's the original implementation class name
+                // for each proxy, even a proxy around a proxy.
+                if (transformedClassNameToImplementationClassName.containsKey(implementationClassName))
+                {
+                    implementationClassName = 
+                            transformedClassNameToImplementationClassName.get(implementationClassName);
+                }
+                implementationClassNode = readClassNode(implementationClassName);
+                transformedClassNameToImplementationClassName.put(newClassName, implementationClassName);
+            }
 
-            return createTransformation(baseClassName, newClassNode, true);
+            return createTransformation(baseClassName, newClassNode, implementationClassNode, true);
         } catch (ClassNotFoundException ex)
         {
             throw new RuntimeException(String.format("Unable to create class %s as sub-class of %s: %s", newClassName,
                     baseClassName, PlasticInternalUtils.toMessage(ex)), ex);
         }
+        catch (IOException e)
+        {
+            throw new RuntimeException(String.format("Unable to load class %s as the implementation of service %s", 
+                    implementationClassName, baseClassName), e);
+        }
+    }
+
+    private ClassNode readClassNode(String className) throws IOException
+    {
+        return readClassNode(className, getClassLoader());
+    }
+    
+    static ClassNode readClassNode(String className, ClassLoader classLoader) throws IOException
+    {
+        ClassNode classNode = new ClassNode();
+        ClassReader classReader = new ClassReader(className);
+        final String location = PlasticInternalUtils.toInternalName(className) + ".class";
+        InputStream inputStream = classLoader.getResourceAsStream(location);
+        BufferedInputStream bis = new BufferedInputStream(inputStream);
+        classReader = new ClassReader(inputStream);
+        bis.close();
+        inputStream.close();
+        classReader.accept(classNode, 0);
+        return classNode;
+        
     }
 
     public ClassInstantiator getClassInstantiator(String className)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
index 26546de..4da7cc8 100644
--- a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
+++ b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
@@ -228,9 +228,27 @@ public class PlasticManager implements PlasticClassListenerHub
      */
     public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
     {
+    	return createProxy(interfaceType, null, callback);
+    }
+
+    /**
+     * Creates an entirely new class. The class extends from Object and implements the provided interface.
+     * 
+     * @param interfaceType
+     *            class to extend from, which must be a class, not an interface
+     * @param implementationType
+     *            class that implements interfaceType. It can be null. 
+     * @param callback
+     *            used to configure the new class
+     * @return the instantiator, which allows instances of the new class to be created
+     * @see #createProxyTransformation(Class, Class)
+     * @since 5.4
+     */
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+    {
         assert callback != null;
 
-        PlasticClassTransformation<T> transformation = createProxyTransformation(interfaceType);
+        PlasticClassTransformation<T> transformation = createProxyTransformation(interfaceType, implementationType);
 
         callback.transform(transformation.getPlasticClass());
 
@@ -244,9 +262,11 @@ public class PlasticManager implements PlasticClassListenerHub
      * 
      * @param interfaceType
      *            class proxy will extend from
+     * @param implementationType
+     *            class that implements interfaceType. It can be null.
      * @return transformation from which an instantiator may be created
      */
-    public <T> PlasticClassTransformation<T> createProxyTransformation(Class interfaceType)
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class interfaceType, Class implementationType)
     {
         assert interfaceType != null;
 
@@ -257,7 +277,9 @@ public class PlasticManager implements PlasticClassListenerHub
 
         String name = String.format("$%s_%s", interfaceType.getSimpleName(), PlasticUtils.nextUID());
 
-        PlasticClassTransformation<T> result = pool.createTransformation("java.lang.Object", name);
+        final String implementationClassName = implementationType != null ? implementationType.getName() : null;
+        PlasticClassTransformation<T> result = 
+                pool.createTransformation("java.lang.Object", name, implementationClassName);
 
         result.getPlasticClass().introduceInterface(interfaceType);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
index d651625..87b9b23 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
@@ -42,7 +42,7 @@ import java.util.Locale;
 import java.util.Map;
 
 /**
- * Service implementation that manages a cache of parsed component templates.
+ * NonAnnotatedServiceInterface implementation that manages a cache of parsed component templates.
  */
 public final class ComponentTemplateSourceImpl extends InvalidationEventHubImpl implements ComponentTemplateSource,
         UpdateListener

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
index 2ddee2a..ad6750f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
@@ -18,7 +18,7 @@ import org.apache.tapestry5.MarkupWriter;
 import org.apache.tapestry5.internal.structure.Page;
 
 /**
- * Service used to render page markup using a MarkupWriter.  This is  used when rendering a complete page as part of a
+ * NonAnnotatedServiceInterface used to render page markup using a MarkupWriter.  This is  used when rendering a complete page as part of a
  * {@linkplain org.apache.tapestry5.internal.services.PageRenderRequestHandlerImpl page render request},
  */
 public interface PageMarkupRenderer

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
index 62b5282..97c30b7 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.internal.structure.Page;
 import java.io.IOException;
 
 /**
- * Service responsible for writing a full page markup response.
+ * NonAnnotatedServiceInterface responsible for writing a full page markup response.
  */
 public interface PageResponseRenderer
 {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
index da0b26f..de68a77 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
@@ -20,7 +20,7 @@ import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.ObjectProvider;
 
 /**
- * Adds support for the {@link Service} annotation (which can be applied to fields or parameters), which is used to
+ * Adds support for the {@link NonAnnotatedServiceInterface} annotation (which can be applied to fields or parameters), which is used to
  * disambiguate injection when multiple services implement the same service interface.
  */
 public class ServiceAnnotationObjectProvider implements ObjectProvider

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index aa79a57..e7c7f87 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -375,13 +375,13 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Builder Methods (static)
+    // NonAnnotatedServiceInterface Builder Methods (static)
     //
     // ========================================================================
 
     // ========================================================================
     //
-    // Service Contribution Methods (static)
+    // NonAnnotatedServiceInterface Contribution Methods (static)
     //
     // ========================================================================
 
@@ -709,7 +709,7 @@ public final class TapestryModule
      * <dd>Access to properties of resources (log, messages, etc.)</dd>
      * <dt>Asset</dt>
      * <dd>injection of assets (triggered via {@link Path} annotation), with the path relative to the component class</dd>
-     * <dt>Service</dt>
+     * <dt>NonAnnotatedServiceInterface</dt>
      * <dd>Ordered last, for use when Inject is present and nothing else works, matches field type against Tapestry IoC
      * services</dd>
      * </dl>
@@ -729,7 +729,7 @@ public final class TapestryModule
 
         // This needs to be the last one, since it matches against services
         // and might blow up if there is no match.
-        configuration.addInstance("Service", ServiceInjectionProvider.class, "after:*");
+        configuration.addInstance("NonAnnotatedServiceInterface", ServiceInjectionProvider.class, "after:*");
     }
 
     /**
@@ -738,8 +738,8 @@ public final class TapestryModule
      * <dt>Asset
      * <dt>
      * <dd>Checks for the {@link Path} annotation, and injects an {@link Asset}</dd>
-     * <dt>Service</dt>
-     * <dd>Injects based on the {@link Service} annotation, if present</dd>
+     * <dt>NonAnnotatedServiceInterface</dt>
+     * <dd>Injects based on the {@link NonAnnotatedServiceInterface} annotation, if present</dd>
      * <dt>ApplicationMessages</dt>
      * <dd>Injects the global application messages</dd>
      * </dl>
@@ -753,7 +753,7 @@ public final class TapestryModule
     {
         configuration.add("Asset", assetObjectProvider, "before:AnnotationBasedContributions");
 
-        configuration.add("Service", new ServiceAnnotationObjectProvider(), "before:AnnotationBasedContributions");
+        configuration.add("NonAnnotatedServiceInterface", new ServiceAnnotationObjectProvider(), "before:AnnotationBasedContributions");
 
         configuration.add("ApplicationMessages", new ApplicationMessageCatalogObjectProvider(locator),
                 "before:AnnotationBasedContributions");
@@ -1129,7 +1129,7 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Builder Methods (instance)
+    // NonAnnotatedServiceInterface Builder Methods (instance)
     //
     // ========================================================================
 
@@ -1504,7 +1504,7 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Contribution Methods (instance)
+    // NonAnnotatedServiceInterface Contribution Methods (instance)
     //
     // ========================================================================
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
index 4674192..1ce486a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.services;
 import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 
 /**
- * Service interface for initializing Tapestry for the application.  The service is a {@linkplain
+ * NonAnnotatedServiceInterface interface for initializing Tapestry for the application.  The service is a {@linkplain
  * org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}, into which {@linkplain
  * org.apache.tapestry5.services.ApplicationInitializerFilter filters} may be contributed.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
index b540780..5548586 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
@@ -27,7 +27,7 @@ import java.util.Map;
  * classpath, is converted into a shorter virtual path. The term "alias" here is generally referred to as
  * "virtual folder" elsewhere.
  * <p/>
- * Service configuration is a map from folder aliases (short names) to complete paths. Names should not start or end end
+ * NonAnnotatedServiceInterface configuration is a map from folder aliases (short names) to complete paths. Names should not start or end end
  * with a slash. Generally, an alias should be a single name (not contain a slash). Paths should also not start or end
  * with a slash. An example mapping would be <code>mylib</code> to <code>com/example/mylib</code>.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
index 3d63bf8..676deec 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.services;
 import java.io.IOException;
 
 /**
- * Service invoked when an uncaught exception occurs. The error handler is responsible for providing a response to the
+ * NonAnnotatedServiceInterface invoked when an uncaught exception occurs. The error handler is responsible for providing a response to the
  * user to describe the error.
  */
 public interface RequestExceptionHandler

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
index 65f53b1..7004b10 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
@@ -21,7 +21,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Service used to store the current request objects, both the Servlet API versions, and the
+ * NonAnnotatedServiceInterface used to store the current request objects, both the Servlet API versions, and the
  * Tapestry generic versions.
  * The service has a per-thread scope.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
index 9a012c0..8aa33db 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 import java.io.IOException;
 
 /**
- * Service interface for the RequestHandler {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}
+ * NonAnnotatedServiceInterface interface for the RequestHandler {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}
  * service. At the end of the pipeline, the service hands off to the {@linkplain org.apache.tapestry5.services.Dispatcher
  * master dispatcher service}.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
index af3b65d..48eb50d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 import javax.servlet.ServletContext;
 
 /**
- * Service interface for initializing a servlet application, as a {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder
+ * NonAnnotatedServiceInterface interface for initializing a servlet application, as a {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder
  * pipeline}. The terminator hands off to the {@link org.apache.tapestry5.services.ApplicationInitializer} service.
  */
 @UsesOrderedConfiguration(ServletApplicationInitializerFilter.class)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
index 2bc0e63..10e7ab6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.services;
 
 /**
- * Service used to encode or decode strings that are placed into URLs.  This is used as an alternative to UUEncoding.
+ * NonAnnotatedServiceInterface used to encode or decode strings that are placed into URLs.  This is used as an alternative to UUEncoding.
  * Alphabetics, numbers and some punctuation ("-", "_", ".", ":") are passed through as is, the "$" character is an
  * escape, followed by either another "$", or by a four digit hex unicode number.  A null input (not a blank input, but
  * actual null) has a special encoding, "$N". Likewise, the blank string has the special encoding "$B".

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
index 4a35499..ac885c6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
@@ -24,7 +24,7 @@ import java.util.Set;
  * Converts {@link Resource}s into {@link StreamableResource}s, and may be responsible for
  * {@linkplain ResourceTransformer transforming} resources based on file extension. Contributions map a file extension
  * (such as "coffee") to a transformer for that file extension.
- * Service decorators added to this service may provide additional processing (compression, minimization, and caching).
+ * NonAnnotatedServiceInterface decorators added to this service may provide additional processing (compression, minimization, and caching).
  *
  * @since 5.3
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
index 5edf83c..0e80540 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
@@ -18,7 +18,7 @@ import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
 
 /**
- * Service that makes it easy to identify a class annotation and use its presence, or the value of an attribute,
+ * NonAnnotatedServiceInterface that makes it easy to identify a class annotation and use its presence, or the value of an attribute,
  * to set a meta-data key. The configuration map class annotation types to corresponding extractors who will be invoked
  * when the annotation is present. Most commonly, a {@link FixedExtractor} is used to set a fixed value to a fixed key,
  * triggered by the presence of the corresponding annotation.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
index 7f4f287..9f14319 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
@@ -1541,7 +1541,7 @@ public class CoreBehaviorsTests extends App1TestCase
     @Test
     public void module_loading()
     {
-        openLinks("Test Only Service Demo");
+        openLinks("Test Only NonAnnotatedServiceInterface Demo");
 
         assertText("message", "TestOnly service message");
     }
@@ -1593,7 +1593,7 @@ public class CoreBehaviorsTests extends App1TestCase
     @Test
     public void injection_of_application_message_catalog_into_service()
     {
-        openLinks("Inject Global Messages into Service Demo");
+        openLinks("Inject Global Messages into NonAnnotatedServiceInterface Demo");
 
         assertText("status", "Application Catalog Working");
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
index 8b2e3fe..a3f2337 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
@@ -128,10 +128,10 @@ public class Index
 
                     new Item("RenderNotificationDemo", "RenderNotification Demo", "Use of RenderNotification mixin"),
 
-                    new Item("InjectMessagesDemo", "Inject Global Messages into Service Demo",
+                    new Item("InjectMessagesDemo", "Inject Global Messages into NonAnnotatedServiceInterface Demo",
                             "Ensure that it is possible to inject the application global message catalog into a service"),
 
-                    new Item("ReloadDemo", "Reloadable Service Implementation Demo",
+                    new Item("ReloadDemo", "Reloadable NonAnnotatedServiceInterface Implementation Demo",
                             "Used when manually testing service reloads"),
 
                     new Item("RequestParameterDemo", "RequestParameter Annotation Demo",
@@ -144,7 +144,7 @@ public class Index
                     new Item("PageResetDemo", "PageReset Annotation Demo",
                             "Use of PageReset annotation to re-initialize page state"),
 
-                    new Item("TestOnlyServiceDemo", "Test Only Service Demo",
+                    new Item("TestOnlyServiceDemo", "Test Only NonAnnotatedServiceInterface Demo",
                             "IoC module available via web.xml configuration"),
 
                     new Item("RenderObjectExceptionDemo", "RenderObject Exception Demo",

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
index ef71125..30687e3 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc;
 import org.apache.tapestry5.ioc.def.ServiceDef;
 
 /**
- * Definition of a service advisor, which (by default) is derived from a service advisor method. Service advisor methods
+ * Definition of a service advisor, which (by default) is derived from a service advisor method. NonAnnotatedServiceInterface advisor methods
  * are static or instance methods on module classes prefixed with "advise". When a service is realized, a list of
  * matching AdvisorDefs is generated, then ordered, and from each a {@link org.apache.tapestry5.ioc.ServiceAdvisor} is
  * obtained and invoked.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..64ea9b5 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -36,7 +36,7 @@ public interface ObjectLocator
      * transparent to the application).
      *
      * @param <T>
-     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
+     * @param serviceId        unique NonAnnotatedServiceInterface id used to locate the service object (may contain <em>symbols</em>,
      *                         which
      *                         will be expanded), case is ignored
      * @param serviceInterface the interface implemented by the service (or an interface extended by the service

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
index b3c190e..2ef70f0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.ioc;
 
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.slf4j.Logger;
 
 /**
@@ -34,6 +35,12 @@ public interface ServiceResources extends ObjectLocator, AnnotationAccess
     Class getServiceInterface();
 
     /**
+     * Returns the service implementation.
+     */
+    @IncompatibleChange(release = "5.4", details = "Added method for TAP5-2029")
+    Class getServiceImplementation();
+
+    /**
      * Returns a Logger appropriate for logging messages. This includes debug level messages about the creation and
      * configuration of the underlying service, as well as debug, warning, or error level messages from the service
      * itself. Often service interceptors will make use of the service's logger.
@@ -46,11 +53,4 @@ public interface ServiceResources extends ObjectLocator, AnnotationAccess
      */
     OperationTracker getTracker();
 
-    /**
-     * Returns null (as of 5.3).
-     * 
-     * @since 5.2.0
-     * @deprecated Deprecated in 5.3 with no replacement. May be removed in 5.4.
-     */
-    Class getImplementationClass();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
index f67c67d..7bf7b1b 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
@@ -24,7 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
  * Marker annotation placed on a service builder method to indicate that the service should be eagerly loaded: realized
- * as if a service method had been invoked. Service realization invokes the service builder method and applys any
+ * as if a service method had been invoked. NonAnnotatedServiceInterface realization invokes the service builder method and applys any
  * decorators to the service.
  * <p/>
  * This annotation may also be placed directly on a service implementation class, when using autobuilding via the {@link

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
index 6c78cb7..a97436f 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
@@ -26,7 +26,7 @@ import java.lang.annotation.*;
  * The annotation may also be placed on a module class, to indicate that all services defined for the module should not
  * allow decoration.
  * <p/>
- * Service decoration includes the decoration mechanism (from Tapestry 5.0) and the newer service advice mechanism (from
+ * NonAnnotatedServiceInterface decoration includes the decoration mechanism (from Tapestry 5.0) and the newer service advice mechanism (from
  * Tapestry 5.1).
  * <p/>
  * Generally, services that are used to advise or decorate other services (such as {@link org.apache.tapestry5.ioc.services.LoggingAdvisor}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
index 7c3c663..61595a8 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
@@ -36,7 +36,7 @@ import org.apache.tapestry5.ioc.ServiceResources;
  * the Security interceptor, which would delegate to the Transaction interceptor, which would finally delegate to the
  * core service implementation.
  * <p/>
- * Service decorators are part of the initial version of Tapestry IoC.  Starting in release 5.1, their use has been
+ * NonAnnotatedServiceInterface decorators are part of the initial version of Tapestry IoC.  Starting in release 5.1, their use has been
  * deprecated, in favor of {@link org.apache.tapestry5.ioc.AdvisorDef}, which is based on {@link
  * org.apache.tapestry5.ioc.services.AspectInterceptorBuilder}.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
index 7b31f8a..b04d4ff 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
@@ -22,7 +22,7 @@ import org.apache.tapestry5.ioc.services.ServiceLifecycleSource;
 import java.util.Set;
 
 /**
- * Service definition derived, by default, from a service builder method. This has been extended in Tapestry 5.1 with
+ * NonAnnotatedServiceInterface definition derived, by default, from a service builder method. This has been extended in Tapestry 5.1 with
  * {@link org.apache.tapestry5.ioc.def.ServiceDef2}, which adds additional methods. Tapestry 5.3 added {@link ServiceDef3}.
  */
 @SuppressWarnings("rawtypes")
@@ -37,8 +37,8 @@ public interface ServiceDef
     ObjectCreator createServiceCreator(ServiceBuilderResources resources);
 
     /**
-     * Returns the service id, derived from the method name or the unqualified service interface name. Service ids must
-     * be unique among <em>all</em> services in all modules. Service ids are used in a heavy handed way to support
+     * Returns the service id, derived from the method name or the unqualified service interface name. NonAnnotatedServiceInterface ids must
+     * be unique among <em>all</em> services in all modules. NonAnnotatedServiceInterface ids are used in a heavy handed way to support
      * ultimate disambiguation, but their primary purpose is to support service contribution methods.
      */
     String getServiceId();

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
index 8f23cbb..bd7535c 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.ioc.def;
 
 import org.apache.tapestry5.ioc.AnnotationAccess;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 
 /**
  * Introduced for Tapestry 5.3, contains new methods to provide access to annotations on the class,
@@ -26,4 +27,14 @@ import org.apache.tapestry5.ioc.AnnotationAccess;
  */
 public interface ServiceDef3 extends ServiceDef2, AnnotationAccess
 {
+	
+    /**
+     * Returns the service implementation associated with this service. When creating the proxies
+     * for the service interface, the implementation of the service interface methods will
+     * receive the annotations of the corresponding method in the service interface.
+     * @since 5.4
+     */
+	@IncompatibleChange(release = "5.4", details = "Added method")
+    Class getServiceImplementation();
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
index 5ad53cd..8b6c398 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.ioc.internal;
 
 /**
- * Interface implemented by all service proxies. Service proxies are always {@link
+ * Interface implemented by all service proxies. NonAnnotatedServiceInterface proxies are always {@link
  * org.apache.tapestry5.ioc.services.RegistryShutdownListener}s, they also can be eager-load
  */
 public interface EagerLoadServiceProxy

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
index 85334f4..3c291e3 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
@@ -22,6 +22,7 @@ import org.apache.tapestry5.ioc.internal.util.*;
 import org.apache.tapestry5.ioc.services.AspectDecorator;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.apache.tapestry5.ioc.services.Status;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.plastic.*;
 import org.slf4j.Logger;
 
@@ -279,7 +280,7 @@ public class ModuleImpl implements Module
                         if (lifecycle.requiresProxy())
                             throw new IllegalArgumentException(
                                     String.format(
-                                            "Service scope '%s' requires a proxy, but the service does not have a service interface (necessary to create a proxy). Provide a service interface or select a different service scope.",
+                                            "NonAnnotatedServiceInterface scope '%s' requires a proxy, but the service does not have a service interface (necessary to create a proxy). Provide a service interface or select a different service scope.",
                                             def.getServiceScope()));
 
                         return creator.createObject();
@@ -309,7 +310,7 @@ public class ModuleImpl implements Module
 
                     JustInTimeObjectCreator delegate = new JustInTimeObjectCreator(tracker, creator, serviceId);
 
-                    Object proxy = createProxy(resources, delegate);
+                    Object proxy = createProxy(resources, delegate, def.isPreventDecoration());
 
                     registry.addRegistryShutdownListener(delegate);
 
@@ -325,6 +326,7 @@ public class ModuleImpl implements Module
                     return proxy;
                 } catch (Exception ex)
                 {
+                    ex.printStackTrace();
                     throw new RuntimeException(IOCMessages.errorBuildingService(serviceId, def, ex), ex);
                 }
             }
@@ -448,7 +450,7 @@ public class ModuleImpl implements Module
         throw new RuntimeException(IOCMessages.instantiateBuilderError(moduleClass, fail), fail);
     }
 
-    private Object createProxy(ServiceResources resources, ObjectCreator creator)
+    private Object createProxy(ServiceResources resources, ObjectCreator creator, boolean preventDecoration)
     {
         String serviceId = resources.getServiceId();
         Class serviceInterface = resources.getServiceInterface();
@@ -457,13 +459,14 @@ public class ModuleImpl implements Module
 
         ServiceProxyToken token = SerializationSupport.createToken(serviceId);
 
-        return createProxyInstance(creator, token, serviceInterface, toString);
+        final Class serviceImplementation = preventDecoration || serviceInterface == TypeCoercer.class ? null : resources.getServiceImplementation();
+        return createProxyInstance(creator, token, serviceInterface, serviceImplementation, toString);
     }
 
     private Object createProxyInstance(final ObjectCreator creator, final ServiceProxyToken token,
-                                       final Class serviceInterface, final String description)
+                                       final Class serviceInterface, final Class serviceImplementation, final String description)
     {
-        ClassInstantiator instantiator = proxyFactory.createProxy(serviceInterface, new PlasticClassTransformer()
+        ClassInstantiator instantiator = proxyFactory.createProxy(serviceInterface, serviceImplementation, new PlasticClassTransformer()
         {
             public void transform(final PlasticClass plasticClass)
             {
@@ -588,4 +591,5 @@ public class ModuleImpl implements Module
     {
         return String.format("ModuleImpl[%s]", moduleDef.getLoggerName());
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
index 1170fe6..aecbab9 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
@@ -445,7 +445,7 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         Module module = serviceIdToModule.get(serviceId);
 
         if (module == null)
-            throw new UnknownValueException(String.format("Service id '%s' is not defined by any module.", serviceId),
+            throw new UnknownValueException(String.format("NonAnnotatedServiceInterface id '%s' is not defined by any module.", serviceId),
                     new AvailableValues("Defined service ids", serviceIdToModule));
 
         return module;
@@ -1093,7 +1093,7 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
 
         getService(UpdateListenerHub.class).addUpdateListener(creator);
 
-        return proxyFactory.createProxy(interfaceClass, (ObjectCreator<T>) creator,
+        return proxyFactory.createProxy(interfaceClass, implementationClass, (ObjectCreator<T>) creator,
                 String.format("<Autoreload proxy %s(%s)>", implementationClass.getName(), interfaceClass.getName()));
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
index 2bf35f7..2473a29 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
@@ -83,6 +83,6 @@ public class ReloadableObjectCreatorSource implements ObjectCreatorSource
             reloadableCreator.createObject();
         }
 
-        return proxyFactory.createProxy(serviceInterfaceClass, reloadableCreator, getDescription());
+        return proxyFactory.createProxy(serviceInterfaceClass, resources.getServiceImplementation(), reloadableCreator, getDescription());
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
index 93baf33..b1d0232 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
@@ -45,7 +45,7 @@ public class ReloadableServiceImplementationObjectCreator extends AbstractReload
 
         if (constructor == null)
             throw new RuntimeException(String.format(
-                    "Service implementation class %s does not have a suitable public constructor.", clazz.getName()));
+                    "NonAnnotatedServiceInterface implementation class %s does not have a suitable public constructor.", clazz.getName()));
 
         ObjectCreator constructorServiceCreator = new ConstructorServiceCreator(resources, constructor.toString(),
                 constructor);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
index 3baa05c..9575f32 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
@@ -99,6 +99,11 @@ public class ServiceDefImpl implements ServiceDef3
         return serviceInterface;
     }
 
+    public Class getServiceImplementation()
+    {
+        return serviceImplementation;
+    }
+
     public String getServiceScope()
     {
         return scope;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
index 3b64db3..8f5aebe 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
@@ -72,6 +72,11 @@ public class ServiceResourcesImpl extends ObjectLocatorImpl implements ServiceBu
         return serviceDef.getServiceInterface();
     }
 
+    public Class getServiceImplementation()
+    {
+        return serviceDef.getServiceImplementation();
+    }
+
     public Logger getLogger()
     {
         return logger;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
index 79b99b9..66b3685 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
@@ -38,7 +38,7 @@ public class AspectDecoratorImpl implements AspectDecorator
 
     public <T> AspectInterceptorBuilder<T> createBuilder(Class<T> serviceInterface, final T delegate, String description)
     {
-        return createBuilder(serviceInterface, delegate, new AnnotationAccessImpl(serviceInterface), description);
+        return createBuilder(serviceInterface, delegate, new AnnotationAccessImpl(delegate.getClass()), description);
     }
 
     public <T> AspectInterceptorBuilder<T> createBuilder(final Class<T> serviceInterface, final T delegate,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
index 9850b9b..b2807d0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
@@ -43,7 +43,7 @@ public class AspectInterceptorBuilderImpl<T> extends AbtractAspectInterceptorBui
 
         this.serviceInterface = serviceInterface;
 
-        transformation = plasticProxyFactory.createProxyTransformation(serviceInterface);
+        transformation = plasticProxyFactory.createProxyTransformation(serviceInterface, (Class<? extends T>) delegate.getClass());
         plasticClass = transformation.getPlasticClass();
 
         plasticClass.addToString(description);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
index 5b17ce0..ae606d2 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
@@ -25,7 +25,7 @@ import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
  * Allows a service to exist "per thread" (in each thread). Creates a proxy that delegates to a per-thread instance.
  * <p/>
  * This scheme ensures that, although the service builder method will be invoked many times over the life of the
- * application, the service decoration process occurs only once. The final calling chain is: Service Proxy --&gt;
+ * application, the service decoration process occurs only once. The final calling chain is: NonAnnotatedServiceInterface Proxy --&gt;
  * Interceptor(s) (from Decorators) --&gt; Advise Proxy (from Advisiors) --&gt; PerThread Proxy --&gt; (per thread)
  * instance.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
index a5f5a13..a7bb67a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
@@ -19,6 +19,7 @@ import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
@@ -59,22 +60,39 @@ public class PlasticProxyFactoryImpl implements PlasticProxyFactory
         return manager.getClassLoader();
     }
 
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+    {
+        return manager.createProxy(interfaceType, implementationType, callback);
+    }
+    
     public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
     {
         return manager.createProxy(interfaceType, callback);
     }
+    
+    
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
+            Class<? extends T> implementationType)
+    {
+        return manager.createProxyTransformation(interfaceType, implementationType);
+    }
 
-    public PlasticClassTransformation createProxyTransformation(Class interfaceType)
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
     {
-        return manager.createProxyTransformation(interfaceType);
+        return createProxyTransformation(interfaceType, null);
     }
 
     public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
+    {   return createProxy(interfaceType, null, creator, description);
+    }
+    
+    public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
+            final ObjectCreator<T> creator, final String description)
     {
         assert creator != null;
         assert InternalUtils.isNonBlank(description);
 
-        ClassInstantiator<T> instantiator = createProxy(interfaceType, new PlasticClassTransformer()
+        ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
         {
             public void transform(PlasticClass plasticClass)
             {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
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 11c22c9..1122293 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
@@ -30,6 +30,7 @@ import org.slf4j.Logger;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Named;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -897,6 +898,11 @@ public class InternalUtils
             {
                 return toAnnotationProvider(findMethod(getServiceInterface(), methodName, argumentTypes));
             }
+            
+			public Class getServiceImplementation() 
+			{
+				return null;
+			}
 
             // ServiceDef2 methods:
 
@@ -934,6 +940,7 @@ public class InternalUtils
             {
                 return sd2.isEagerLoad();
             }
+
         };
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
index b18cb0a..db2de0e 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
@@ -37,7 +37,7 @@ public class WrongConfigurationTypeGuard implements InjectionResources
     public <T> T findResource(Class<T> type, Type genericType)
     {
         if (type == guardType)
-            throw new IllegalArgumentException(String.format("Service '%s' is configured using %s, not %s.",
+            throw new IllegalArgumentException(String.format("NonAnnotatedServiceInterface '%s' is configured using %s, not %s.",
                                                              serviceId,
                                                              expectedType.getName(), guardType.getName()));
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
index be0c43e..2b79b0a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.services;
 import org.slf4j.Logger;
 
 /**
- * Service that can create a logging interceptor that wraps around a service implementation (or interceptor). The
+ * NonAnnotatedServiceInterface that can create a logging interceptor that wraps around a service implementation (or interceptor). The
  * interceptor works with the service's log to log, at debug level, method entry (with arguments), method exit (with
  * return value, if any) as well as any thrown exceptions.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
index 81e1eac..7addde0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.services;
 
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.apache.tapestry5.plastic.ClassInstantiator;
 import org.apache.tapestry5.plastic.PlasticClassListenerHub;
 import org.apache.tapestry5.plastic.PlasticClassTransformation;
@@ -51,6 +52,21 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
     <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
 
     /**
+     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+     * then invokes the callback to further configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+    /**
      * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
      * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
      * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
@@ -62,6 +78,21 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
     <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
 
     /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+     * implementation class. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @return transformation from which an instantiator may be created
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+    /**
      * Creates a proxy instance that delegates all methods through a corresponding
      * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
      * creator implementation may decide to
@@ -78,6 +109,27 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
      * @return proxy instance
      */
     <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+    
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param implementationType
+     *         class that implements the interface type. It may be null
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
 
     /**
      * Converts a method to a {@link Location}, which includes information about the source file name and line number.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
index edf3b0b..e7633c4 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
@@ -25,7 +25,7 @@ import java.util.EventListener;
 public interface RegistryShutdownListener extends EventListener
 {
     /**
-     * Invoked when the registry shuts down, giving services a chance to perform any final operations. Service
+     * Invoked when the registry shuts down, giving services a chance to perform any final operations. NonAnnotatedServiceInterface
      * implementations should not attempt to invoke methods on other services (via proxies) as the service proxies may
      * themselves be shutdown.
      */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
index 402d3a9..204a584 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
@@ -60,7 +60,7 @@ class BridgeBuilderSpec extends AbstractSharedRegistrySpecification {
 
     ToStringService service = new ToStringService() {
 
-      String toString() { "Service" }
+      String toString() { "NonAnnotatedServiceInterface" }
     }
 
     ToStringFilter filter = new ToStringFilter() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
index e85c516..fe498c7 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
@@ -159,7 +159,7 @@ class ContributionDefImplSpec extends Specification {
 
     RuntimeException e = thrown()
 
-    e.message.contains "Service 'Foo' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
+    e.message.contains "NonAnnotatedServiceInterface 'Foo' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
   }
 
   def "ordered configuration injects and contributes a service via @InjectService"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/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 d017dfc..9682a4b 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy
@@ -144,7 +144,7 @@ class DefaultModuleDefImplSpec extends Specification {
 
     RuntimeException ex = thrown()
 
-    ex.message.contains "Service Fred (defined by ${ServiceIdConflictMethodModule.name}.buildFred()"
+    ex.message.contains "NonAnnotatedServiceInterface Fred (defined by ${ServiceIdConflictMethodModule.name}.buildFred()"
     ex.message.contains "conflicts with previously defined service defined by ${ServiceIdConflictMethodModule.name}.buildFred(Object)"
   }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
index d79c6ce..b771e4b 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
@@ -57,7 +57,7 @@ class PerThreadScopeSpec extends AbstractRegistrySpecification {
     Exception e = thrown()
 
     e.message.contains "Error building service proxy for service 'ScopeRequiresAProxyAndNoInterfaceIsProvided'"
-    e.message.contains "Service scope 'perthread' requires a proxy"
+    e.message.contains "NonAnnotatedServiceInterface scope 'perthread' requires a proxy"
   }
 
   def "ensure that perthread services are discarded by cleanupThread()"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
index a746d07..fc8ca85 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
@@ -20,7 +20,7 @@ class RegistryConstructionAndRuntimeErrorsSpec extends AbstractRegistrySpecifica
 
     RuntimeException ex = thrown()
 
-    ex.message.startsWith "Service id 'Fred' has already been defined by"
+    ex.message.startsWith "NonAnnotatedServiceInterface id 'Fred' has already been defined by"
 
     // Can't check entire message, can't guarantee what order modules will be processed in
   }


[2/3] git commit: TAP5-2029: Copy annotations from service implementation to proxy

Posted by th...@apache.org.
TAP5-2029: Copy annotations from service implementation to proxy


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/4a818e35
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/4a818e35
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/4a818e35

Branch: refs/heads/master
Commit: 4a818e35585ac0860aaffa23bc0d1799514480da
Parents: ae473c8
Author: Thiago H. de Paula Figueiredo <th...@apache.org>
Authored: Thu Jan 2 14:13:12 2014 -0200
Committer: Thiago H. de Paula Figueiredo <th...@apache.org>
Committed: Thu Jan 2 14:13:12 2014 -0200

----------------------------------------------------------------------
 .../internal/plastic/InheritanceData.java       |  4 +-
 .../internal/plastic/PlasticClassImpl.java      | 83 +++++++++++++++++++-
 .../internal/plastic/PlasticClassPool.java      | 75 +++++++++++++++---
 .../tapestry5/plastic/PlasticManager.java       | 28 ++++++-
 .../services/ComponentTemplateSourceImpl.java   |  2 +-
 .../internal/services/PageMarkupRenderer.java   |  2 +-
 .../internal/services/PageResponseRenderer.java |  2 +-
 .../ServiceAnnotationObjectProvider.java        |  2 +-
 .../tapestry5/modules/TapestryModule.java       | 18 ++---
 .../services/ApplicationInitializer.java        |  2 +-
 .../services/ClasspathAssetAliasManager.java    |  2 +-
 .../services/RequestExceptionHandler.java       |  2 +-
 .../tapestry5/services/RequestGlobals.java      |  2 +-
 .../tapestry5/services/RequestHandler.java      |  2 +-
 .../services/ServletApplicationInitializer.java |  2 +-
 .../apache/tapestry5/services/URLEncoder.java   |  2 +-
 .../assets/StreamableResourceSource.java        |  2 +-
 .../tapestry5/services/meta/MetaWorker.java     |  2 +-
 .../integration/app1/CoreBehaviorsTests.java    |  4 +-
 .../tapestry5/integration/app1/pages/Index.java |  6 +-
 .../org/apache/tapestry5/ioc/AdvisorDef.java    |  2 +-
 .../org/apache/tapestry5/ioc/ObjectLocator.java |  2 +-
 .../apache/tapestry5/ioc/ServiceResources.java  | 14 ++--
 .../tapestry5/ioc/annotations/EagerLoad.java    |  2 +-
 .../annotations/PreventServiceDecoration.java   |  2 +-
 .../apache/tapestry5/ioc/def/DecoratorDef.java  |  2 +-
 .../apache/tapestry5/ioc/def/ServiceDef.java    |  6 +-
 .../apache/tapestry5/ioc/def/ServiceDef3.java   | 11 +++
 .../ioc/internal/EagerLoadServiceProxy.java     |  2 +-
 .../tapestry5/ioc/internal/ModuleImpl.java      | 16 ++--
 .../tapestry5/ioc/internal/RegistryImpl.java    |  4 +-
 .../internal/ReloadableObjectCreatorSource.java |  2 +-
 ...dableServiceImplementationObjectCreator.java |  2 +-
 .../tapestry5/ioc/internal/ServiceDefImpl.java  |  5 ++
 .../ioc/internal/ServiceResourcesImpl.java      |  5 ++
 .../internal/services/AspectDecoratorImpl.java  |  2 +-
 .../services/AspectInterceptorBuilderImpl.java  |  2 +-
 .../services/PerThreadServiceLifecycle.java     |  2 +-
 .../services/PlasticProxyFactoryImpl.java       | 24 +++++-
 .../ioc/internal/util/InternalUtils.java        |  7 ++
 .../util/WrongConfigurationTypeGuard.java       |  2 +-
 .../ioc/services/LoggingDecorator.java          |  2 +-
 .../ioc/services/PlasticProxyFactory.java       | 52 ++++++++++++
 .../ioc/services/RegistryShutdownListener.java  |  2 +-
 .../groovy/ioc/specs/BridgeBuilderSpec.groovy   |  2 +-
 .../ioc/specs/ContributionDefImplSpec.groovy    |  2 +-
 .../ioc/specs/DefaultModuleDefImplSpec.groovy   |  2 +-
 .../groovy/ioc/specs/PerThreadScopeSpec.groovy  |  2 +-
 ...istryConstructionAndRuntimeErrorsSpec.groovy |  2 +-
 .../src/test/groovy/ioc/specs/ReloadSpec.groovy |  2 +-
 .../groovy/ioc/specs/ServiceLookupSpec.groovy   |  4 +-
 .../ValidatingConfigurationWrapperSpec.groovy   |  2 +-
 ...idatingMappedConfigurationWrapperSpec.groovy |  4 +-
 .../ServiceProxySerializationSpec.groovy        |  2 +-
 54 files changed, 349 insertions(+), 91 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
index 17d90d2..ab7a17f 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/InheritanceData.java
@@ -119,7 +119,9 @@ public class InheritanceData
     }
 
     public void addInterface(String name) {
-        interfaceNames.add(name);
+        if (!interfaceNames.contains(name)) {
+            interfaceNames.add(name);
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
index a0e88d4..e12ef71 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassImpl.java
@@ -14,11 +14,13 @@
 
 package org.apache.tapestry5.internal.plastic;
 
+import org.apache.tapestry5.internal.plastic.asm.ClassReader;
 import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.plastic.*;
 
+import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
@@ -166,28 +168,34 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
     // Set of methods that need to contribute to the shim and gain access to it
 
     final Set<PlasticMethodImpl> shimMethods = PlasticInternalUtils.newSet();
+    
+    final ClassNode implementationClassNode;
+    
+    private ClassNode interfaceClassNode;
 
     /**
      * @param classNode
+     * @param implementationClassNode
      * @param pool
      * @param parentInheritanceData
      * @param parentStaticContext
      * @param proxy
      */
-    public PlasticClassImpl(ClassNode classNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
+    public PlasticClassImpl(ClassNode classNode, ClassNode implementationClassNode, PlasticClassPool pool, InheritanceData parentInheritanceData,
                             StaticContext parentStaticContext, boolean proxy)
     {
         this.classNode = classNode;
         this.pool = pool;
         this.proxy = proxy;
-
+        this.implementationClassNode = implementationClassNode;
+        
         staticContext = parentStaticContext.dupe();
 
         className = PlasticInternalUtils.toClassName(classNode.name);
         superClassName = PlasticInternalUtils.toClassName(classNode.superName);
 
         fieldInstrumentations = new FieldInstrumentations(classNode.superName);
-
+        
         annotationAccess = new DelegatingAnnotationAccess(pool.createAnnotationAccess(classNode.visibleAnnotations),
                 pool.createAnnotationAccess(superClassName));
 
@@ -326,6 +334,32 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
 
         return annotationAccess.getAnnotation(annotationType);
     }
+    
+    private static void copyAnnotationsFromServiceImplementation(MethodNode methodNode, ClassNode source)
+    {
+        if (source != null)
+        {
+        
+            for (MethodNode implementationNode : source.methods)
+            {
+                // Find corresponding method in the implementation class MethodNode
+                if (methodNode.name.equals(implementationNode.name) && methodNode.desc.equals(implementationNode.desc))
+                {
+                    implementationNode.accept(methodNode);
+                    
+                    // We want to copy just annotations, not code.
+                    methodNode.instructions.clear();
+                    methodNode.instructions.resetLabels();
+                    
+                    break;
+                    
+                }
+                
+            }
+            
+        }
+        
+    }
 
     public PlasticClass proxyInterface(Class interfaceType, PlasticField field)
     {
@@ -346,6 +380,8 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
     public ClassInstantiator createInstantiator()
     {
         lock();
+        
+        addClassAnnotations(implementationClassNode);
 
         createShimIfNeeded();
 
@@ -360,6 +396,29 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
         return createInstantiatorFromClass(transformedClass);
     }
 
+    private void addClassAnnotations(ClassNode otherClassNode)
+    {
+        // Copy annotations from implementation if available.
+        // Code adapted from ClassNode.accept(), as we just want to copy
+        // the annotations and nothing more.
+        if (otherClassNode != null) 
+        {
+            
+            int i, n;
+            n = otherClassNode.visibleAnnotations == null ? 0 : otherClassNode.visibleAnnotations.size();
+            for (i = 0; i < n; ++i) {
+                AnnotationNode an = otherClassNode.visibleAnnotations.get(i);
+                an.accept(classNode.visitAnnotation(an.desc, true));
+            }
+            n = otherClassNode.invisibleAnnotations == null ? 0 : otherClassNode.invisibleAnnotations.size();
+            for (i = 0; i < n; ++i) {
+                AnnotationNode an = otherClassNode.invisibleAnnotations.get(i);
+                an.accept(classNode.visitAnnotation(an.desc, false));
+            }
+            
+        }
+    }
+
     private ClassInstantiator createInstantiatorFromClass(Class clazz)
     {
         try
@@ -674,6 +733,11 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
         MethodNode methodNode = new MethodNode(description.modifiers, description.methodName, desc,
                 description.genericSignature, exceptions);
         boolean isOverride = inheritanceData.isImplemented(methodNode.name, desc);
+        
+        if (!isOverride) {
+            copyAnnotationsFromServiceImplementation(methodNode, interfaceClassNode);
+            copyAnnotationsFromServiceImplementation(methodNode, implementationClassNode);
+        }
 
         if (isOverride)
             createOverrideOfBaseClassImpl(description, methodNode);
@@ -1065,12 +1129,23 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
                     "Class %s is not an interface; ony interfaces may be introduced.", interfaceType.getName()));
 
         String interfaceName = nameCache.toInternalName(interfaceType);
+        
+        try
+        {
+            interfaceClassNode = PlasticClassPool.readClassNode(interfaceType.getName(), getClass().getClassLoader());
+        }
+        catch (IOException e)
+        {
+            throw new RuntimeException(e);
+        }
 
         if (!inheritanceData.isInterfaceImplemented(interfaceName))
         {
             classNode.interfaces.add(interfaceName);
             inheritanceData.addInterface(interfaceName);
         }
+        
+        addClassAnnotations(interfaceClassNode);
 
         Set<PlasticMethod> introducedMethods = new HashSet<PlasticMethod>();
 
@@ -1083,6 +1158,8 @@ public class PlasticClassImpl extends Lockable implements PlasticClass, Internal
                 introducedMethods.add(introduceMethod(m));
             }
         }
+        
+        interfaceClassNode = null;
 
         return introducedMethods;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
index 5d38c0c..41ce961 100644
--- a/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
+++ b/plastic/src/main/java/org/apache/tapestry5/internal/plastic/PlasticClassPool.java
@@ -20,6 +20,9 @@ import org.apache.tapestry5.internal.plastic.asm.Opcodes;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.plastic.*;
 
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Modifier;
 import java.util.*;
@@ -86,6 +89,9 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
 
     private final Map<String, FieldInstrumentations> instrumentations = PlasticInternalUtils.newMap();
 
+    private final Map<String, String> transformedClassNameToImplementationClassName = PlasticInternalUtils.newMap();
+    
+
     private final FieldInstrumentations placeholder = new FieldInstrumentations(null);
 
 
@@ -120,7 +126,6 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         synchronized (loader)
         {
             Class result = realize(PlasticInternalUtils.toClassName(classNode.name), ClassType.PRIMARY, classNode);
-
             baseClassDefs.put(result.getName(), new BaseClassDef(inheritanceData, staticContext));
 
             return result;
@@ -434,17 +439,19 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         String baseClassName = PlasticInternalUtils.toClassName(classNode.superName);
 
         instrumentations.put(classNode.name, new FieldInstrumentations(classNode.superName));
-
-        return createTransformation(baseClassName, classNode, false);
+        
+        // TODO: check whether second parameter should really be null
+        return createTransformation(baseClassName, classNode, null, false); 
     }
 
     /**
      * @param baseClassName class from which the transformed class extends
      * @param classNode     node for the class
+     * @param implementationClassNode     node for the implementation class. May be null.
      * @param proxy         if true, the class is a new empty class; if false an existing class that's being transformed
      * @throws ClassNotFoundException
      */
-    private InternalPlasticClassTransformation createTransformation(String baseClassName, ClassNode classNode, boolean proxy)
+    private InternalPlasticClassTransformation createTransformation(String baseClassName, ClassNode classNode, ClassNode implementationClassNode, boolean proxy)
             throws ClassNotFoundException
     {
         if (shouldInterceptClassLoading(baseClassName))
@@ -455,12 +462,12 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
 
             assert def != null;
 
-            return new PlasticClassImpl(classNode, this, def.inheritanceData, def.staticContext, proxy);
+            return new PlasticClassImpl(classNode, implementationClassNode, this, def.inheritanceData, def.staticContext, proxy);
         }
 
         // When the base class is Object, or otherwise not in a transformed package,
         // then start with the empty
-        return new PlasticClassImpl(classNode, this, emptyInheritanceData, emptyStaticContext, proxy);
+        return new PlasticClassImpl(classNode, implementationClassNode, this, emptyInheritanceData, emptyStaticContext, proxy);
     }
 
     /**
@@ -487,21 +494,69 @@ public class PlasticClassPool implements ClassLoaderDelegate, Opcodes, PlasticCl
         return PlasticInternalUtils.readBytecodeForClass(parentClassLoader, className, true);
     }
 
-    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName)
+    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName) {
+        return createTransformation(baseClassName, newClassName, null);
+    }
+    
+    public PlasticClassTransformation createTransformation(String baseClassName, String newClassName, String implementationClassName)
     {
         try
         {
             ClassNode newClassNode = new ClassNode();
 
-            newClassNode.visit(V1_5, ACC_PUBLIC, PlasticInternalUtils.toInternalName(newClassName), null,
-                    PlasticInternalUtils.toInternalName(baseClassName), null);
+            final String internalNewClassNameinternalName = PlasticInternalUtils.toInternalName(newClassName);
+            final String internalBaseClassName = PlasticInternalUtils.toInternalName(baseClassName);
+            newClassNode.visit(V1_5, ACC_PUBLIC, internalNewClassNameinternalName, null, internalBaseClassName, null);
+            
+            ClassNode implementationClassNode = null;
+            
+            if (implementationClassName != null)
+            {
+                // When decorating or advising a service, implementationClassName is the name
+                // of a proxy class already, such as "$ServiceName_[random string]",
+                // which doesn't exist as a file in the classpath, just in memory.
+                // So we need to keep what's the original implementation class name
+                // for each proxy, even a proxy around a proxy.
+                if (transformedClassNameToImplementationClassName.containsKey(implementationClassName))
+                {
+                    implementationClassName = 
+                            transformedClassNameToImplementationClassName.get(implementationClassName);
+                }
+                implementationClassNode = readClassNode(implementationClassName);
+                transformedClassNameToImplementationClassName.put(newClassName, implementationClassName);
+            }
 
-            return createTransformation(baseClassName, newClassNode, true);
+            return createTransformation(baseClassName, newClassNode, implementationClassNode, true);
         } catch (ClassNotFoundException ex)
         {
             throw new RuntimeException(String.format("Unable to create class %s as sub-class of %s: %s", newClassName,
                     baseClassName, PlasticInternalUtils.toMessage(ex)), ex);
         }
+        catch (IOException e)
+        {
+            throw new RuntimeException(String.format("Unable to load class %s as the implementation of service %s", 
+                    implementationClassName, baseClassName), e);
+        }
+    }
+
+    private ClassNode readClassNode(String className) throws IOException
+    {
+        return readClassNode(className, getClassLoader());
+    }
+    
+    static ClassNode readClassNode(String className, ClassLoader classLoader) throws IOException
+    {
+        ClassNode classNode = new ClassNode();
+        ClassReader classReader = new ClassReader(className);
+        final String location = PlasticInternalUtils.toInternalName(className) + ".class";
+        InputStream inputStream = classLoader.getResourceAsStream(location);
+        BufferedInputStream bis = new BufferedInputStream(inputStream);
+        classReader = new ClassReader(inputStream);
+        bis.close();
+        inputStream.close();
+        classReader.accept(classNode, 0);
+        return classNode;
+        
     }
 
     public ClassInstantiator getClassInstantiator(String className)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
----------------------------------------------------------------------
diff --git a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
index 26546de..4da7cc8 100644
--- a/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
+++ b/plastic/src/main/java/org/apache/tapestry5/plastic/PlasticManager.java
@@ -228,9 +228,27 @@ public class PlasticManager implements PlasticClassListenerHub
      */
     public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
     {
+    	return createProxy(interfaceType, null, callback);
+    }
+
+    /**
+     * Creates an entirely new class. The class extends from Object and implements the provided interface.
+     * 
+     * @param interfaceType
+     *            class to extend from, which must be a class, not an interface
+     * @param implementationType
+     *            class that implements interfaceType. It can be null. 
+     * @param callback
+     *            used to configure the new class
+     * @return the instantiator, which allows instances of the new class to be created
+     * @see #createProxyTransformation(Class, Class)
+     * @since 5.4
+     */
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+    {
         assert callback != null;
 
-        PlasticClassTransformation<T> transformation = createProxyTransformation(interfaceType);
+        PlasticClassTransformation<T> transformation = createProxyTransformation(interfaceType, implementationType);
 
         callback.transform(transformation.getPlasticClass());
 
@@ -244,9 +262,11 @@ public class PlasticManager implements PlasticClassListenerHub
      * 
      * @param interfaceType
      *            class proxy will extend from
+     * @param implementationType
+     *            class that implements interfaceType. It can be null.
      * @return transformation from which an instantiator may be created
      */
-    public <T> PlasticClassTransformation<T> createProxyTransformation(Class interfaceType)
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class interfaceType, Class implementationType)
     {
         assert interfaceType != null;
 
@@ -257,7 +277,9 @@ public class PlasticManager implements PlasticClassListenerHub
 
         String name = String.format("$%s_%s", interfaceType.getSimpleName(), PlasticUtils.nextUID());
 
-        PlasticClassTransformation<T> result = pool.createTransformation("java.lang.Object", name);
+        final String implementationClassName = implementationType != null ? implementationType.getName() : null;
+        PlasticClassTransformation<T> result = 
+                pool.createTransformation("java.lang.Object", name, implementationClassName);
 
         result.getPlasticClass().introduceInterface(interfaceType);
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
index d651625..87b9b23 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ComponentTemplateSourceImpl.java
@@ -42,7 +42,7 @@ import java.util.Locale;
 import java.util.Map;
 
 /**
- * Service implementation that manages a cache of parsed component templates.
+ * NonAnnotatedServiceInterface implementation that manages a cache of parsed component templates.
  */
 public final class ComponentTemplateSourceImpl extends InvalidationEventHubImpl implements ComponentTemplateSource,
         UpdateListener

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
index 2ddee2a..ad6750f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageMarkupRenderer.java
@@ -18,7 +18,7 @@ import org.apache.tapestry5.MarkupWriter;
 import org.apache.tapestry5.internal.structure.Page;
 
 /**
- * Service used to render page markup using a MarkupWriter.  This is  used when rendering a complete page as part of a
+ * NonAnnotatedServiceInterface used to render page markup using a MarkupWriter.  This is  used when rendering a complete page as part of a
  * {@linkplain org.apache.tapestry5.internal.services.PageRenderRequestHandlerImpl page render request},
  */
 public interface PageMarkupRenderer

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
index 62b5282..97c30b7 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/PageResponseRenderer.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.internal.structure.Page;
 import java.io.IOException;
 
 /**
- * Service responsible for writing a full page markup response.
+ * NonAnnotatedServiceInterface responsible for writing a full page markup response.
  */
 public interface PageResponseRenderer
 {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
index da0b26f..de68a77 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ServiceAnnotationObjectProvider.java
@@ -20,7 +20,7 @@ import org.apache.tapestry5.ioc.ObjectLocator;
 import org.apache.tapestry5.ioc.ObjectProvider;
 
 /**
- * Adds support for the {@link Service} annotation (which can be applied to fields or parameters), which is used to
+ * Adds support for the {@link NonAnnotatedServiceInterface} annotation (which can be applied to fields or parameters), which is used to
  * disambiguate injection when multiple services implement the same service interface.
  */
 public class ServiceAnnotationObjectProvider implements ObjectProvider

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
index aa79a57..e7c7f87 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/modules/TapestryModule.java
@@ -375,13 +375,13 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Builder Methods (static)
+    // NonAnnotatedServiceInterface Builder Methods (static)
     //
     // ========================================================================
 
     // ========================================================================
     //
-    // Service Contribution Methods (static)
+    // NonAnnotatedServiceInterface Contribution Methods (static)
     //
     // ========================================================================
 
@@ -709,7 +709,7 @@ public final class TapestryModule
      * <dd>Access to properties of resources (log, messages, etc.)</dd>
      * <dt>Asset</dt>
      * <dd>injection of assets (triggered via {@link Path} annotation), with the path relative to the component class</dd>
-     * <dt>Service</dt>
+     * <dt>NonAnnotatedServiceInterface</dt>
      * <dd>Ordered last, for use when Inject is present and nothing else works, matches field type against Tapestry IoC
      * services</dd>
      * </dl>
@@ -729,7 +729,7 @@ public final class TapestryModule
 
         // This needs to be the last one, since it matches against services
         // and might blow up if there is no match.
-        configuration.addInstance("Service", ServiceInjectionProvider.class, "after:*");
+        configuration.addInstance("NonAnnotatedServiceInterface", ServiceInjectionProvider.class, "after:*");
     }
 
     /**
@@ -738,8 +738,8 @@ public final class TapestryModule
      * <dt>Asset
      * <dt>
      * <dd>Checks for the {@link Path} annotation, and injects an {@link Asset}</dd>
-     * <dt>Service</dt>
-     * <dd>Injects based on the {@link Service} annotation, if present</dd>
+     * <dt>NonAnnotatedServiceInterface</dt>
+     * <dd>Injects based on the {@link NonAnnotatedServiceInterface} annotation, if present</dd>
      * <dt>ApplicationMessages</dt>
      * <dd>Injects the global application messages</dd>
      * </dl>
@@ -753,7 +753,7 @@ public final class TapestryModule
     {
         configuration.add("Asset", assetObjectProvider, "before:AnnotationBasedContributions");
 
-        configuration.add("Service", new ServiceAnnotationObjectProvider(), "before:AnnotationBasedContributions");
+        configuration.add("NonAnnotatedServiceInterface", new ServiceAnnotationObjectProvider(), "before:AnnotationBasedContributions");
 
         configuration.add("ApplicationMessages", new ApplicationMessageCatalogObjectProvider(locator),
                 "before:AnnotationBasedContributions");
@@ -1129,7 +1129,7 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Builder Methods (instance)
+    // NonAnnotatedServiceInterface Builder Methods (instance)
     //
     // ========================================================================
 
@@ -1504,7 +1504,7 @@ public final class TapestryModule
 
     // ========================================================================
     //
-    // Service Contribution Methods (instance)
+    // NonAnnotatedServiceInterface Contribution Methods (instance)
     //
     // ========================================================================
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
index 4674192..1ce486a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ApplicationInitializer.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.services;
 import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 
 /**
- * Service interface for initializing Tapestry for the application.  The service is a {@linkplain
+ * NonAnnotatedServiceInterface interface for initializing Tapestry for the application.  The service is a {@linkplain
  * org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}, into which {@linkplain
  * org.apache.tapestry5.services.ApplicationInitializerFilter filters} may be contributed.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
index b540780..5548586 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ClasspathAssetAliasManager.java
@@ -27,7 +27,7 @@ import java.util.Map;
  * classpath, is converted into a shorter virtual path. The term "alias" here is generally referred to as
  * "virtual folder" elsewhere.
  * <p/>
- * Service configuration is a map from folder aliases (short names) to complete paths. Names should not start or end end
+ * NonAnnotatedServiceInterface configuration is a map from folder aliases (short names) to complete paths. Names should not start or end end
  * with a slash. Generally, an alias should be a single name (not contain a slash). Paths should also not start or end
  * with a slash. An example mapping would be <code>mylib</code> to <code>com/example/mylib</code>.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
index 3d63bf8..676deec 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestExceptionHandler.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.services;
 import java.io.IOException;
 
 /**
- * Service invoked when an uncaught exception occurs. The error handler is responsible for providing a response to the
+ * NonAnnotatedServiceInterface invoked when an uncaught exception occurs. The error handler is responsible for providing a response to the
  * user to describe the error.
  */
 public interface RequestExceptionHandler

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
index 65f53b1..7004b10 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestGlobals.java
@@ -21,7 +21,7 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 /**
- * Service used to store the current request objects, both the Servlet API versions, and the
+ * NonAnnotatedServiceInterface used to store the current request objects, both the Servlet API versions, and the
  * Tapestry generic versions.
  * The service has a per-thread scope.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
index 9a012c0..8aa33db 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/RequestHandler.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 import java.io.IOException;
 
 /**
- * Service interface for the RequestHandler {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}
+ * NonAnnotatedServiceInterface interface for the RequestHandler {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder pipeline}
  * service. At the end of the pipeline, the service hands off to the {@linkplain org.apache.tapestry5.services.Dispatcher
  * master dispatcher service}.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
index af3b65d..48eb50d 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/ServletApplicationInitializer.java
@@ -19,7 +19,7 @@ import org.apache.tapestry5.ioc.annotations.UsesOrderedConfiguration;
 import javax.servlet.ServletContext;
 
 /**
- * Service interface for initializing a servlet application, as a {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder
+ * NonAnnotatedServiceInterface interface for initializing a servlet application, as a {@linkplain org.apache.tapestry5.ioc.services.PipelineBuilder
  * pipeline}. The terminator hands off to the {@link org.apache.tapestry5.services.ApplicationInitializer} service.
  */
 @UsesOrderedConfiguration(ServletApplicationInitializerFilter.class)

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
index 2bc0e63..10e7ab6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/URLEncoder.java
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.services;
 
 /**
- * Service used to encode or decode strings that are placed into URLs.  This is used as an alternative to UUEncoding.
+ * NonAnnotatedServiceInterface used to encode or decode strings that are placed into URLs.  This is used as an alternative to UUEncoding.
  * Alphabetics, numbers and some punctuation ("-", "_", ".", ":") are passed through as is, the "$" character is an
  * escape, followed by either another "$", or by a four digit hex unicode number.  A null input (not a blank input, but
  * actual null) has a special encoding, "$N". Likewise, the blank string has the special encoding "$B".

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
index 4a35499..ac885c6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResourceSource.java
@@ -24,7 +24,7 @@ import java.util.Set;
  * Converts {@link Resource}s into {@link StreamableResource}s, and may be responsible for
  * {@linkplain ResourceTransformer transforming} resources based on file extension. Contributions map a file extension
  * (such as "coffee") to a transformer for that file extension.
- * Service decorators added to this service may provide additional processing (compression, minimization, and caching).
+ * NonAnnotatedServiceInterface decorators added to this service may provide additional processing (compression, minimization, and caching).
  *
  * @since 5.3
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
index 5edf83c..0e80540 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/meta/MetaWorker.java
@@ -18,7 +18,7 @@ import org.apache.tapestry5.ioc.annotations.UsesMappedConfiguration;
 import org.apache.tapestry5.services.transform.ComponentClassTransformWorker2;
 
 /**
- * Service that makes it easy to identify a class annotation and use its presence, or the value of an attribute,
+ * NonAnnotatedServiceInterface that makes it easy to identify a class annotation and use its presence, or the value of an attribute,
  * to set a meta-data key. The configuration map class annotation types to corresponding extractors who will be invoked
  * when the annotation is present. Most commonly, a {@link FixedExtractor} is used to set a fixed value to a fixed key,
  * triggered by the presence of the corresponding annotation.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
index 7f4f287..9f14319 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
@@ -1541,7 +1541,7 @@ public class CoreBehaviorsTests extends App1TestCase
     @Test
     public void module_loading()
     {
-        openLinks("Test Only Service Demo");
+        openLinks("Test Only NonAnnotatedServiceInterface Demo");
 
         assertText("message", "TestOnly service message");
     }
@@ -1593,7 +1593,7 @@ public class CoreBehaviorsTests extends App1TestCase
     @Test
     public void injection_of_application_message_catalog_into_service()
     {
-        openLinks("Inject Global Messages into Service Demo");
+        openLinks("Inject Global Messages into NonAnnotatedServiceInterface Demo");
 
         assertText("status", "Application Catalog Working");
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
index 8b2e3fe..a3f2337 100644
--- a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
+++ b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/pages/Index.java
@@ -128,10 +128,10 @@ public class Index
 
                     new Item("RenderNotificationDemo", "RenderNotification Demo", "Use of RenderNotification mixin"),
 
-                    new Item("InjectMessagesDemo", "Inject Global Messages into Service Demo",
+                    new Item("InjectMessagesDemo", "Inject Global Messages into NonAnnotatedServiceInterface Demo",
                             "Ensure that it is possible to inject the application global message catalog into a service"),
 
-                    new Item("ReloadDemo", "Reloadable Service Implementation Demo",
+                    new Item("ReloadDemo", "Reloadable NonAnnotatedServiceInterface Implementation Demo",
                             "Used when manually testing service reloads"),
 
                     new Item("RequestParameterDemo", "RequestParameter Annotation Demo",
@@ -144,7 +144,7 @@ public class Index
                     new Item("PageResetDemo", "PageReset Annotation Demo",
                             "Use of PageReset annotation to re-initialize page state"),
 
-                    new Item("TestOnlyServiceDemo", "Test Only Service Demo",
+                    new Item("TestOnlyServiceDemo", "Test Only NonAnnotatedServiceInterface Demo",
                             "IoC module available via web.xml configuration"),
 
                     new Item("RenderObjectExceptionDemo", "RenderObject Exception Demo",

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
index ef71125..30687e3 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/AdvisorDef.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc;
 import org.apache.tapestry5.ioc.def.ServiceDef;
 
 /**
- * Definition of a service advisor, which (by default) is derived from a service advisor method. Service advisor methods
+ * Definition of a service advisor, which (by default) is derived from a service advisor method. NonAnnotatedServiceInterface advisor methods
  * are static or instance methods on module classes prefixed with "advise". When a service is realized, a list of
  * matching AdvisorDefs is generated, then ordered, and from each a {@link org.apache.tapestry5.ioc.ServiceAdvisor} is
  * obtained and invoked.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
index 81d1f77..64ea9b5 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ObjectLocator.java
@@ -36,7 +36,7 @@ public interface ObjectLocator
      * transparent to the application).
      *
      * @param <T>
-     * @param serviceId        unique Service id used to locate the service object (may contain <em>symbols</em>,
+     * @param serviceId        unique NonAnnotatedServiceInterface id used to locate the service object (may contain <em>symbols</em>,
      *                         which
      *                         will be expanded), case is ignored
      * @param serviceInterface the interface implemented by the service (or an interface extended by the service

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
index b3c190e..2ef70f0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
@@ -14,6 +14,7 @@
 
 package org.apache.tapestry5.ioc;
 
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.slf4j.Logger;
 
 /**
@@ -34,6 +35,12 @@ public interface ServiceResources extends ObjectLocator, AnnotationAccess
     Class getServiceInterface();
 
     /**
+     * Returns the service implementation.
+     */
+    @IncompatibleChange(release = "5.4", details = "Added method for TAP5-2029")
+    Class getServiceImplementation();
+
+    /**
      * Returns a Logger appropriate for logging messages. This includes debug level messages about the creation and
      * configuration of the underlying service, as well as debug, warning, or error level messages from the service
      * itself. Often service interceptors will make use of the service's logger.
@@ -46,11 +53,4 @@ public interface ServiceResources extends ObjectLocator, AnnotationAccess
      */
     OperationTracker getTracker();
 
-    /**
-     * Returns null (as of 5.3).
-     * 
-     * @since 5.2.0
-     * @deprecated Deprecated in 5.3 with no replacement. May be removed in 5.4.
-     */
-    Class getImplementationClass();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
index f67c67d..7bf7b1b 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/EagerLoad.java
@@ -24,7 +24,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 /**
  * Marker annotation placed on a service builder method to indicate that the service should be eagerly loaded: realized
- * as if a service method had been invoked. Service realization invokes the service builder method and applys any
+ * as if a service method had been invoked. NonAnnotatedServiceInterface realization invokes the service builder method and applys any
  * decorators to the service.
  * <p/>
  * This annotation may also be placed directly on a service implementation class, when using autobuilding via the {@link

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
index 6c78cb7..a97436f 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/annotations/PreventServiceDecoration.java
@@ -26,7 +26,7 @@ import java.lang.annotation.*;
  * The annotation may also be placed on a module class, to indicate that all services defined for the module should not
  * allow decoration.
  * <p/>
- * Service decoration includes the decoration mechanism (from Tapestry 5.0) and the newer service advice mechanism (from
+ * NonAnnotatedServiceInterface decoration includes the decoration mechanism (from Tapestry 5.0) and the newer service advice mechanism (from
  * Tapestry 5.1).
  * <p/>
  * Generally, services that are used to advise or decorate other services (such as {@link org.apache.tapestry5.ioc.services.LoggingAdvisor}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
index 7c3c663..61595a8 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/DecoratorDef.java
@@ -36,7 +36,7 @@ import org.apache.tapestry5.ioc.ServiceResources;
  * the Security interceptor, which would delegate to the Transaction interceptor, which would finally delegate to the
  * core service implementation.
  * <p/>
- * Service decorators are part of the initial version of Tapestry IoC.  Starting in release 5.1, their use has been
+ * NonAnnotatedServiceInterface decorators are part of the initial version of Tapestry IoC.  Starting in release 5.1, their use has been
  * deprecated, in favor of {@link org.apache.tapestry5.ioc.AdvisorDef}, which is based on {@link
  * org.apache.tapestry5.ioc.services.AspectInterceptorBuilder}.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
index 7b31f8a..b04d4ff 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef.java
@@ -22,7 +22,7 @@ import org.apache.tapestry5.ioc.services.ServiceLifecycleSource;
 import java.util.Set;
 
 /**
- * Service definition derived, by default, from a service builder method. This has been extended in Tapestry 5.1 with
+ * NonAnnotatedServiceInterface definition derived, by default, from a service builder method. This has been extended in Tapestry 5.1 with
  * {@link org.apache.tapestry5.ioc.def.ServiceDef2}, which adds additional methods. Tapestry 5.3 added {@link ServiceDef3}.
  */
 @SuppressWarnings("rawtypes")
@@ -37,8 +37,8 @@ public interface ServiceDef
     ObjectCreator createServiceCreator(ServiceBuilderResources resources);
 
     /**
-     * Returns the service id, derived from the method name or the unqualified service interface name. Service ids must
-     * be unique among <em>all</em> services in all modules. Service ids are used in a heavy handed way to support
+     * Returns the service id, derived from the method name or the unqualified service interface name. NonAnnotatedServiceInterface ids must
+     * be unique among <em>all</em> services in all modules. NonAnnotatedServiceInterface ids are used in a heavy handed way to support
      * ultimate disambiguation, but their primary purpose is to support service contribution methods.
      */
     String getServiceId();

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
index 8f23cbb..bd7535c 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/def/ServiceDef3.java
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.ioc.def;
 
 import org.apache.tapestry5.ioc.AnnotationAccess;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 
 /**
  * Introduced for Tapestry 5.3, contains new methods to provide access to annotations on the class,
@@ -26,4 +27,14 @@ import org.apache.tapestry5.ioc.AnnotationAccess;
  */
 public interface ServiceDef3 extends ServiceDef2, AnnotationAccess
 {
+	
+    /**
+     * Returns the service implementation associated with this service. When creating the proxies
+     * for the service interface, the implementation of the service interface methods will
+     * receive the annotations of the corresponding method in the service interface.
+     * @since 5.4
+     */
+	@IncompatibleChange(release = "5.4", details = "Added method")
+    Class getServiceImplementation();
+
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
index 5ad53cd..8b6c398 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/EagerLoadServiceProxy.java
@@ -15,7 +15,7 @@
 package org.apache.tapestry5.ioc.internal;
 
 /**
- * Interface implemented by all service proxies. Service proxies are always {@link
+ * Interface implemented by all service proxies. NonAnnotatedServiceInterface proxies are always {@link
  * org.apache.tapestry5.ioc.services.RegistryShutdownListener}s, they also can be eager-load
  */
 public interface EagerLoadServiceProxy

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
index 85334f4..3c291e3 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
@@ -22,6 +22,7 @@ import org.apache.tapestry5.ioc.internal.util.*;
 import org.apache.tapestry5.ioc.services.AspectDecorator;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
 import org.apache.tapestry5.ioc.services.Status;
+import org.apache.tapestry5.ioc.services.TypeCoercer;
 import org.apache.tapestry5.plastic.*;
 import org.slf4j.Logger;
 
@@ -279,7 +280,7 @@ public class ModuleImpl implements Module
                         if (lifecycle.requiresProxy())
                             throw new IllegalArgumentException(
                                     String.format(
-                                            "Service scope '%s' requires a proxy, but the service does not have a service interface (necessary to create a proxy). Provide a service interface or select a different service scope.",
+                                            "NonAnnotatedServiceInterface scope '%s' requires a proxy, but the service does not have a service interface (necessary to create a proxy). Provide a service interface or select a different service scope.",
                                             def.getServiceScope()));
 
                         return creator.createObject();
@@ -309,7 +310,7 @@ public class ModuleImpl implements Module
 
                     JustInTimeObjectCreator delegate = new JustInTimeObjectCreator(tracker, creator, serviceId);
 
-                    Object proxy = createProxy(resources, delegate);
+                    Object proxy = createProxy(resources, delegate, def.isPreventDecoration());
 
                     registry.addRegistryShutdownListener(delegate);
 
@@ -325,6 +326,7 @@ public class ModuleImpl implements Module
                     return proxy;
                 } catch (Exception ex)
                 {
+                    ex.printStackTrace();
                     throw new RuntimeException(IOCMessages.errorBuildingService(serviceId, def, ex), ex);
                 }
             }
@@ -448,7 +450,7 @@ public class ModuleImpl implements Module
         throw new RuntimeException(IOCMessages.instantiateBuilderError(moduleClass, fail), fail);
     }
 
-    private Object createProxy(ServiceResources resources, ObjectCreator creator)
+    private Object createProxy(ServiceResources resources, ObjectCreator creator, boolean preventDecoration)
     {
         String serviceId = resources.getServiceId();
         Class serviceInterface = resources.getServiceInterface();
@@ -457,13 +459,14 @@ public class ModuleImpl implements Module
 
         ServiceProxyToken token = SerializationSupport.createToken(serviceId);
 
-        return createProxyInstance(creator, token, serviceInterface, toString);
+        final Class serviceImplementation = preventDecoration || serviceInterface == TypeCoercer.class ? null : resources.getServiceImplementation();
+        return createProxyInstance(creator, token, serviceInterface, serviceImplementation, toString);
     }
 
     private Object createProxyInstance(final ObjectCreator creator, final ServiceProxyToken token,
-                                       final Class serviceInterface, final String description)
+                                       final Class serviceInterface, final Class serviceImplementation, final String description)
     {
-        ClassInstantiator instantiator = proxyFactory.createProxy(serviceInterface, new PlasticClassTransformer()
+        ClassInstantiator instantiator = proxyFactory.createProxy(serviceInterface, serviceImplementation, new PlasticClassTransformer()
         {
             public void transform(final PlasticClass plasticClass)
             {
@@ -588,4 +591,5 @@ public class ModuleImpl implements Module
     {
         return String.format("ModuleImpl[%s]", moduleDef.getLoggerName());
     }
+    
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
index 1170fe6..aecbab9 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
@@ -445,7 +445,7 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
         Module module = serviceIdToModule.get(serviceId);
 
         if (module == null)
-            throw new UnknownValueException(String.format("Service id '%s' is not defined by any module.", serviceId),
+            throw new UnknownValueException(String.format("NonAnnotatedServiceInterface id '%s' is not defined by any module.", serviceId),
                     new AvailableValues("Defined service ids", serviceIdToModule));
 
         return module;
@@ -1093,7 +1093,7 @@ public class RegistryImpl implements Registry, InternalRegistry, ServiceProxyPro
 
         getService(UpdateListenerHub.class).addUpdateListener(creator);
 
-        return proxyFactory.createProxy(interfaceClass, (ObjectCreator<T>) creator,
+        return proxyFactory.createProxy(interfaceClass, implementationClass, (ObjectCreator<T>) creator,
                 String.format("<Autoreload proxy %s(%s)>", implementationClass.getName(), interfaceClass.getName()));
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
index 2bf35f7..2473a29 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
@@ -83,6 +83,6 @@ public class ReloadableObjectCreatorSource implements ObjectCreatorSource
             reloadableCreator.createObject();
         }
 
-        return proxyFactory.createProxy(serviceInterfaceClass, reloadableCreator, getDescription());
+        return proxyFactory.createProxy(serviceInterfaceClass, resources.getServiceImplementation(), reloadableCreator, getDescription());
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
index 93baf33..b1d0232 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableServiceImplementationObjectCreator.java
@@ -45,7 +45,7 @@ public class ReloadableServiceImplementationObjectCreator extends AbstractReload
 
         if (constructor == null)
             throw new RuntimeException(String.format(
-                    "Service implementation class %s does not have a suitable public constructor.", clazz.getName()));
+                    "NonAnnotatedServiceInterface implementation class %s does not have a suitable public constructor.", clazz.getName()));
 
         ObjectCreator constructorServiceCreator = new ConstructorServiceCreator(resources, constructor.toString(),
                 constructor);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
index 3baa05c..9575f32 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
@@ -99,6 +99,11 @@ public class ServiceDefImpl implements ServiceDef3
         return serviceInterface;
     }
 
+    public Class getServiceImplementation()
+    {
+        return serviceImplementation;
+    }
+
     public String getServiceScope()
     {
         return scope;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
index 3b64db3..8f5aebe 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
@@ -72,6 +72,11 @@ public class ServiceResourcesImpl extends ObjectLocatorImpl implements ServiceBu
         return serviceDef.getServiceInterface();
     }
 
+    public Class getServiceImplementation()
+    {
+        return serviceDef.getServiceImplementation();
+    }
+
     public Logger getLogger()
     {
         return logger;

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
index 79b99b9..66b3685 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectDecoratorImpl.java
@@ -38,7 +38,7 @@ public class AspectDecoratorImpl implements AspectDecorator
 
     public <T> AspectInterceptorBuilder<T> createBuilder(Class<T> serviceInterface, final T delegate, String description)
     {
-        return createBuilder(serviceInterface, delegate, new AnnotationAccessImpl(serviceInterface), description);
+        return createBuilder(serviceInterface, delegate, new AnnotationAccessImpl(delegate.getClass()), description);
     }
 
     public <T> AspectInterceptorBuilder<T> createBuilder(final Class<T> serviceInterface, final T delegate,

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
index 9850b9b..b2807d0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AspectInterceptorBuilderImpl.java
@@ -43,7 +43,7 @@ public class AspectInterceptorBuilderImpl<T> extends AbtractAspectInterceptorBui
 
         this.serviceInterface = serviceInterface;
 
-        transformation = plasticProxyFactory.createProxyTransformation(serviceInterface);
+        transformation = plasticProxyFactory.createProxyTransformation(serviceInterface, (Class<? extends T>) delegate.getClass());
         plasticClass = transformation.getPlasticClass();
 
         plasticClass.addToString(description);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
index 5b17ce0..ae606d2 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PerThreadServiceLifecycle.java
@@ -25,7 +25,7 @@ import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
  * Allows a service to exist "per thread" (in each thread). Creates a proxy that delegates to a per-thread instance.
  * <p/>
  * This scheme ensures that, although the service builder method will be invoked many times over the life of the
- * application, the service decoration process occurs only once. The final calling chain is: Service Proxy --&gt;
+ * application, the service decoration process occurs only once. The final calling chain is: NonAnnotatedServiceInterface Proxy --&gt;
  * Interceptor(s) (from Decorators) --&gt; Advise Proxy (from Advisiors) --&gt; PerThread Proxy --&gt; (per thread)
  * instance.
  */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
index a5f5a13..a7bb67a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/PlasticProxyFactoryImpl.java
@@ -19,6 +19,7 @@ import org.apache.tapestry5.internal.plastic.asm.Type;
 import org.apache.tapestry5.internal.plastic.asm.tree.*;
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
@@ -59,22 +60,39 @@ public class PlasticProxyFactoryImpl implements PlasticProxyFactory
         return manager.getClassLoader();
     }
 
+    public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback)
+    {
+        return manager.createProxy(interfaceType, implementationType, callback);
+    }
+    
     public <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback)
     {
         return manager.createProxy(interfaceType, callback);
     }
+    
+    
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType,
+            Class<? extends T> implementationType)
+    {
+        return manager.createProxyTransformation(interfaceType, implementationType);
+    }
 
-    public PlasticClassTransformation createProxyTransformation(Class interfaceType)
+    public <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType)
     {
-        return manager.createProxyTransformation(interfaceType);
+        return createProxyTransformation(interfaceType, null);
     }
 
     public <T> T createProxy(final Class<T> interfaceType, final ObjectCreator<T> creator, final String description)
+    {   return createProxy(interfaceType, null, creator, description);
+    }
+    
+    public <T> T createProxy(final Class<T> interfaceType, final Class<? extends T> implementationType,
+            final ObjectCreator<T> creator, final String description)
     {
         assert creator != null;
         assert InternalUtils.isNonBlank(description);
 
-        ClassInstantiator<T> instantiator = createProxy(interfaceType, new PlasticClassTransformer()
+        ClassInstantiator<T> instantiator = createProxy(interfaceType, implementationType, new PlasticClassTransformer()
         {
             public void transform(PlasticClass plasticClass)
             {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
----------------------------------------------------------------------
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 11c22c9..1122293 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
@@ -30,6 +30,7 @@ import org.slf4j.Logger;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Named;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.lang.annotation.Annotation;
@@ -897,6 +898,11 @@ public class InternalUtils
             {
                 return toAnnotationProvider(findMethod(getServiceInterface(), methodName, argumentTypes));
             }
+            
+			public Class getServiceImplementation() 
+			{
+				return null;
+			}
 
             // ServiceDef2 methods:
 
@@ -934,6 +940,7 @@ public class InternalUtils
             {
                 return sd2.isEagerLoad();
             }
+
         };
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
index b18cb0a..db2de0e 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/WrongConfigurationTypeGuard.java
@@ -37,7 +37,7 @@ public class WrongConfigurationTypeGuard implements InjectionResources
     public <T> T findResource(Class<T> type, Type genericType)
     {
         if (type == guardType)
-            throw new IllegalArgumentException(String.format("Service '%s' is configured using %s, not %s.",
+            throw new IllegalArgumentException(String.format("NonAnnotatedServiceInterface '%s' is configured using %s, not %s.",
                                                              serviceId,
                                                              expectedType.getName(), guardType.getName()));
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
index be0c43e..2b79b0a 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/LoggingDecorator.java
@@ -17,7 +17,7 @@ package org.apache.tapestry5.ioc.services;
 import org.slf4j.Logger;
 
 /**
- * Service that can create a logging interceptor that wraps around a service implementation (or interceptor). The
+ * NonAnnotatedServiceInterface that can create a logging interceptor that wraps around a service implementation (or interceptor). The
  * interceptor works with the service's log to log, at debug level, method entry (with arguments), method exit (with
  * return value, if any) as well as any thrown exceptions.
  * <p/>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
index 81e1eac..7addde0 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/PlasticProxyFactory.java
@@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.services;
 
 import org.apache.tapestry5.ioc.Location;
 import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.annotations.IncompatibleChange;
 import org.apache.tapestry5.plastic.ClassInstantiator;
 import org.apache.tapestry5.plastic.PlasticClassListenerHub;
 import org.apache.tapestry5.plastic.PlasticClassTransformation;
@@ -51,6 +52,21 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
     <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, PlasticClassTransformer callback);
 
     /**
+     * Creates a proxy object that implements the indicated interface and indicated service implementation type,
+     * then invokes the callback to further configure the proxy.
+     *
+     * @param interfaceType
+     *         interface implemented by proxy
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @param callback
+     *         configures the proxy
+     * @return instantiator that can be used to create an instance of the proxy class
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> ClassInstantiator<T> createProxy(Class<T> interfaceType, Class<? extends T> implementationType, PlasticClassTransformer callback);
+
+    /**
      * Creates the underlying {@link PlasticClassTransformation} for an interface proxy. This should only be
      * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
      * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
@@ -62,6 +78,21 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
     <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType);
 
     /**
+     * Creates the underlying {@link PlasticClassTransformation} for an interface proxy with a given
+     * implementation class. This should only be
+     * used in the cases where encapsulating the PlasticClass construction into a {@linkplain PlasticClassTransformer
+     * callback} is not feasible (which is the case for some of the older APIs inside Tapestry IoC).
+     *
+     * @param interfaceType
+     *         class proxy will extend from
+     * @param implementationType
+     *         a class that implements the interfaceType. It can be null.
+     * @return transformation from which an instantiator may be created
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> PlasticClassTransformation<T> createProxyTransformation(Class<T> interfaceType, Class<? extends T> implementationType);
+
+    /**
      * Creates a proxy instance that delegates all methods through a corresponding
      * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
      * creator implementation may decide to
@@ -78,6 +109,27 @@ public interface PlasticProxyFactory extends PlasticClassListenerHub
      * @return proxy instance
      */
     <T> T createProxy(Class<T> interfaceType, ObjectCreator<T> creator, String description);
+    
+    /**
+     * Creates a proxy instance that delegates all methods through a corresponding
+     * ObjectCreator. Each method invocation on the proxy will route through {@link ObjectCreator#createObject()} (the
+     * creator implementation may decide to
+     * cache the return value as appropriate).
+     *
+     * @param <T>
+     *         type of proxy
+     * @param interfaceType
+     *         interface class for proxy
+     * @param implementationType
+     *         class that implements the interface type. It may be null
+     * @param creator
+     *         object responsible for creating the real object
+     * @param description
+     *         the <code>toString()</code> of the proxy
+     * @return proxy instance
+     */
+    @IncompatibleChange(release = "5.4", details = "TAP5-2029")
+    <T> T createProxy(Class<T> interfaceType, Class<? extends T> implementationType, ObjectCreator<T> creator, String description);
 
     /**
      * Converts a method to a {@link Location}, which includes information about the source file name and line number.

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
index edf3b0b..e7633c4 100644
--- a/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
+++ b/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/RegistryShutdownListener.java
@@ -25,7 +25,7 @@ import java.util.EventListener;
 public interface RegistryShutdownListener extends EventListener
 {
     /**
-     * Invoked when the registry shuts down, giving services a chance to perform any final operations. Service
+     * Invoked when the registry shuts down, giving services a chance to perform any final operations. NonAnnotatedServiceInterface
      * implementations should not attempt to invoke methods on other services (via proxies) as the service proxies may
      * themselves be shutdown.
      */

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
index 402d3a9..204a584 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/BridgeBuilderSpec.groovy
@@ -60,7 +60,7 @@ class BridgeBuilderSpec extends AbstractSharedRegistrySpecification {
 
     ToStringService service = new ToStringService() {
 
-      String toString() { "Service" }
+      String toString() { "NonAnnotatedServiceInterface" }
     }
 
     ToStringFilter filter = new ToStringFilter() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
index e85c516..fe498c7 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/ContributionDefImplSpec.groovy
@@ -159,7 +159,7 @@ class ContributionDefImplSpec extends Specification {
 
     RuntimeException e = thrown()
 
-    e.message.contains "Service 'Foo' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
+    e.message.contains "NonAnnotatedServiceInterface 'Foo' is configured using org.apache.tapestry5.ioc.Configuration, not org.apache.tapestry5.ioc.MappedConfiguration."
   }
 
   def "ordered configuration injects and contributes a service via @InjectService"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/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 d017dfc..9682a4b 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/DefaultModuleDefImplSpec.groovy
@@ -144,7 +144,7 @@ class DefaultModuleDefImplSpec extends Specification {
 
     RuntimeException ex = thrown()
 
-    ex.message.contains "Service Fred (defined by ${ServiceIdConflictMethodModule.name}.buildFred()"
+    ex.message.contains "NonAnnotatedServiceInterface Fred (defined by ${ServiceIdConflictMethodModule.name}.buildFred()"
     ex.message.contains "conflicts with previously defined service defined by ${ServiceIdConflictMethodModule.name}.buildFred(Object)"
   }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
index d79c6ce..b771e4b 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/PerThreadScopeSpec.groovy
@@ -57,7 +57,7 @@ class PerThreadScopeSpec extends AbstractRegistrySpecification {
     Exception e = thrown()
 
     e.message.contains "Error building service proxy for service 'ScopeRequiresAProxyAndNoInterfaceIsProvided'"
-    e.message.contains "Service scope 'perthread' requires a proxy"
+    e.message.contains "NonAnnotatedServiceInterface scope 'perthread' requires a proxy"
   }
 
   def "ensure that perthread services are discarded by cleanupThread()"() {

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/4a818e35/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy b/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
index a746d07..fc8ca85 100644
--- a/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/RegistryConstructionAndRuntimeErrorsSpec.groovy
@@ -20,7 +20,7 @@ class RegistryConstructionAndRuntimeErrorsSpec extends AbstractRegistrySpecifica
 
     RuntimeException ex = thrown()
 
-    ex.message.startsWith "Service id 'Fred' has already been defined by"
+    ex.message.startsWith "NonAnnotatedServiceInterface id 'Fred' has already been defined by"
 
     // Can't check entire message, can't guarantee what order modules will be processed in
   }