You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by dr...@apache.org on 2010/07/28 08:36:49 UTC

svn commit: r979956 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/ioc/ main/java/org/apache/tapestry5/ioc/internal/ main/java/org/apache/tapestry5/ioc/internal/services/ main/java/org/apache/tapestry5/ioc/internal/util...

Author: drobiazko
Date: Wed Jul 28 06:36:48 2010
New Revision: 979956

URL: http://svn.apache.org/viewvc?rev=979956&view=rev
Log:
TAP5-335: Provide access to annotations of service implementation class

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java   (with props)
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java   (with props)
Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AbstractFab.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFabImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFab.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFactory.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/StringHolderImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFabImplTest.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImplTest.java

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/ServiceResources.java Wed Jul 28 06:36:48 2010
@@ -45,4 +45,11 @@ public interface ServiceResources extend
      * initializing the service.
      */
     OperationTracker getTracker();
+    
+    /**
+     * Returns the service implementation class.
+     * 
+     * @since 5.2.0
+     */
+    Class getImplementationClass();
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/DefaultModuleDefImpl.java Wed Jul 28 06:36:48 2010
@@ -461,7 +461,7 @@ public class DefaultModuleDefImpl implem
         Set<Class> markers = CollectionFactory.newSet(defaultMarkers);
         markers.addAll(extractServiceDefMarkers(method));
 
-        ServiceDefImpl serviceDef = new ServiceDefImpl(returnType, serviceId, markers, scope, eagerLoad,
+        ServiceDefImpl serviceDef = new ServiceDefImpl(returnType, null, serviceId, markers, scope, eagerLoad,
                 preventDecoration, source);
 
         addServiceDef(serviceDef);

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java?rev=979956&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java Wed Jul 28 06:36:48 2010
@@ -0,0 +1,26 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.internal;
+
+import org.apache.tapestry5.ioc.def.ServiceDef2;
+
+public interface InternalServiceDef extends ServiceDef2
+{
+    /**
+     * Returns the service implementation class.
+     * 
+     * @return implementations class or {@code null}
+     */
+    Class getImplementationClass();
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/InternalServiceDef.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ModuleImpl.java Wed Jul 28 06:36:48 2010
@@ -472,10 +472,10 @@ public class ModuleImpl implements Modul
 
         String toString = format("<Proxy for %s(%s)>", serviceId, serviceInterface.getName());
 
-        return createProxyInstance(creator, serviceId, serviceInterface, toString);
+        return createProxyInstance(creator, serviceId, serviceInterface, resources.getImplementationClass(), toString);
     }
 
-    private Object createProxyInstance(ObjectCreator creator, String serviceId, Class serviceInterface,
+    private Object createProxyInstance(ObjectCreator creator, String serviceId, Class serviceInterface, Class serviceImplementation,
             String description)
     {
         ServiceProxyToken token = SerializationSupport.createToken(serviceId);
@@ -508,6 +508,13 @@ public class ModuleImpl implements Modul
         classFab.addMethod(Modifier.PRIVATE, sig, body);
 
         classFab.proxyMethodsToDelegate(serviceInterface, "delegate()", description);
+        
+        if(serviceImplementation != null)
+        {
+            classFab.copyClassAnnotationsFromDelegate(serviceImplementation);
+            
+            classFab.copyMethodAnnotationsFromDelegate(serviceInterface, serviceImplementation);
+        }
 
         Class proxyClass = classFab.createClass();
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/RegistryImpl.java Wed Jul 28 06:36:48 2010
@@ -1026,7 +1026,7 @@ public class RegistryImpl implements Reg
             }
         };
 
-        return classFactory.createProxy(interfaceClass, justInTime,
+        return classFactory.createProxy(interfaceClass, implementationClass, justInTime,
                 String.format("<Autobuild proxy %s(%s)>", implementationClass.getName(), interfaceClass.getName()));
     }
 
@@ -1038,7 +1038,7 @@ public class RegistryImpl implements Reg
 
         getService(UpdateListenerHub.class).addUpdateListener(creator);
 
-        return classFactory.createProxy(interfaceClass, creator,
+        return classFactory.createProxy(interfaceClass, implementationClass, creator,
                 String.format("<Autoreload proxy %s(%s)>", implementationClass.getName(), interfaceClass.getName()));
     }
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ReloadableObjectCreatorSource.java Wed Jul 28 06:36:48 2010
@@ -73,6 +73,6 @@ public class ReloadableObjectCreatorSour
         if (eagerLoad)
             reloadableCreator.createObject();
 
-        return classFactory.createProxy(serviceInterfaceClass, reloadableCreator, getDescription());
+        return classFactory.createProxy(serviceInterfaceClass, serviceImplementationClass, reloadableCreator, getDescription());
     }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceBinderImpl.java Wed Jul 28 06:36:48 2010
@@ -104,7 +104,7 @@ public class ServiceBinderImpl implement
         Set<Class> markers = CollectionFactory.newSet(defaultMarkers);
         markers.addAll(this.markers);
 
-        ServiceDef serviceDef = new ServiceDefImpl(serviceInterface, serviceId, markers, scope, eagerLoad,
+        ServiceDef serviceDef = new ServiceDefImpl(serviceInterface, serviceImplementation, serviceId, markers, scope, eagerLoad,
                 preventDecoration, source);
 
         accumulator.addServiceDef(serviceDef);

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceDefImpl.java Wed Jul 28 06:36:48 2010
@@ -14,15 +14,16 @@
 
 package org.apache.tapestry5.ioc.internal;
 
+import java.util.Set;
+
 import org.apache.tapestry5.ioc.ObjectCreator;
 import org.apache.tapestry5.ioc.ServiceBuilderResources;
-import org.apache.tapestry5.ioc.def.ServiceDef2;
-
-import java.util.Set;
 
-public class ServiceDefImpl implements ServiceDef2
+public class ServiceDefImpl implements InternalServiceDef
 {
     private final Class serviceInterface;
+    
+    private final Class serviceImplementation;
 
     private final String serviceId;
 
@@ -39,6 +40,7 @@ public class ServiceDefImpl implements S
     /**
      * @param serviceInterface  interface implemented by the service (or the service implementation class, for
      *                          non-proxied services)
+     * @param serviceImplementation service implementation class if exists                
      * @param serviceId         unique id for the service
      * @param markers           set of marker annotation classes (will be retained not copied)
      * @param scope             scope of the service (i.e., {@link org.apache.tapestry5.ioc.ScopeConstants#DEFAULT}).
@@ -46,10 +48,11 @@ public class ServiceDefImpl implements S
      * @param preventDecoration if true, the service may not be decorated
      * @param source            used to create the service implementation when needed
      */
-    ServiceDefImpl(Class serviceInterface, String serviceId, Set<Class> markers, String scope,
+    ServiceDefImpl(Class serviceInterface, Class serviceImplementation, String serviceId, Set<Class> markers, String scope,
                    boolean eagerLoad, boolean preventDecoration, ObjectCreatorSource source)
     {
         this.serviceInterface = serviceInterface;
+        this.serviceImplementation = serviceImplementation;
         this.serviceId = serviceId;
         this.scope = scope;
         this.eagerLoad = eagerLoad;
@@ -99,4 +102,9 @@ public class ServiceDefImpl implements S
     {
         return preventDecoration;
     }
+
+    public Class getImplementationClass()
+    {
+        return serviceImplementation;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/ServiceResourcesImpl.java Wed Jul 28 06:36:48 2010
@@ -44,7 +44,7 @@ public class ServiceResourcesImpl extend
 
     private final Module module;
 
-    private final ServiceDef serviceDef;
+    private final InternalServiceDef serviceDef;
 
     private final Logger logger;
 
@@ -57,7 +57,7 @@ public class ServiceResourcesImpl extend
 
         this.registry = registry;
         this.module = module;
-        this.serviceDef = serviceDef;
+        this.serviceDef = InternalUtils.toInternalServiceDef(serviceDef);
         this.classFactory = classFactory;
         this.logger = logger;
     }
@@ -174,4 +174,9 @@ public class ServiceResourcesImpl extend
     {
         return registry;
     }
+
+    public Class getImplementationClass()
+    {
+        return serviceDef.getImplementationClass();
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AbstractFab.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AbstractFab.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AbstractFab.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AbstractFab.java Wed Jul 28 06:36:48 2010
@@ -98,5 +98,10 @@ public class AbstractFab
     {
         return source;
     }
+    
+    protected Logger getLogger()
+    {
+        return logger;
+    }
 
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java?rev=979956&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java Wed Jul 28 06:36:48 2010
@@ -0,0 +1,178 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.internal.services;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.annotation.Annotation;
+import javassist.bytecode.annotation.AnnotationMemberValue;
+import javassist.bytecode.annotation.ArrayMemberValue;
+import javassist.bytecode.annotation.BooleanMemberValue;
+import javassist.bytecode.annotation.ByteMemberValue;
+import javassist.bytecode.annotation.CharMemberValue;
+import javassist.bytecode.annotation.ClassMemberValue;
+import javassist.bytecode.annotation.DoubleMemberValue;
+import javassist.bytecode.annotation.EnumMemberValue;
+import javassist.bytecode.annotation.FloatMemberValue;
+import javassist.bytecode.annotation.IntegerMemberValue;
+import javassist.bytecode.annotation.LongMemberValue;
+import javassist.bytecode.annotation.MemberValue;
+import javassist.bytecode.annotation.MemberValueVisitor;
+import javassist.bytecode.annotation.ShortMemberValue;
+import javassist.bytecode.annotation.StringMemberValue;
+
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+
+public class AnnotationMemberValueVisitor implements MemberValueVisitor
+{
+    private final ConstPool constPool;
+
+    private final CtClassSource classSource;
+
+    private final Object value;
+
+    public AnnotationMemberValueVisitor(final ConstPool constPool, final CtClassSource classSource, final Object value)
+    {
+        this.constPool = constPool;
+        this.classSource = classSource;
+        this.value = value;
+    }
+
+    public void visitAnnotationMemberValue(final AnnotationMemberValue mb)
+    {
+        Class annotationType = getClass(value);
+        
+        final Method[] methods = annotationType.getDeclaredMethods();
+
+        for (final Method method : methods)
+        {
+            try
+            {
+                final Object result = method.invoke(value);
+
+                final MemberValue memberValue = Annotation.createMemberValue(
+                        this.constPool,
+                        this.classSource.toCtClass(result.getClass()));
+
+                memberValue.accept(new AnnotationMemberValueVisitor(this.constPool, this.classSource, result));
+                
+                mb.getValue().addMemberValue(method.getName(), memberValue);
+            }
+            catch (Exception e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+        
+    }
+
+    public void visitArrayMemberValue(final ArrayMemberValue mb)
+    {
+        final Object[] array = (Object[]) this.value;
+
+        final List<MemberValue> members = CollectionFactory.newList();
+        
+        for (final Object object : array)
+        {
+            try
+            {
+                final MemberValue memberValue = Annotation.createMemberValue(
+                        this.constPool,
+                        this.classSource.toCtClass(getClass(object)));
+
+                memberValue.accept(new AnnotationMemberValueVisitor(this.constPool, this.classSource, object));
+
+                members.add(memberValue);
+            }
+            catch (final Exception e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        mb.setValue(members.toArray(new MemberValue[] {}));
+    }
+    
+    private Class getClass(Object object)
+    {
+        if(object instanceof java.lang.annotation.Annotation)
+        {
+            return ((java.lang.annotation.Annotation)object).annotationType();
+        }
+        
+        return object.getClass();
+    }
+
+    public void visitBooleanMemberValue(final BooleanMemberValue mb)
+    {
+        mb.setValue((Boolean) this.value);
+    }
+
+    public void visitByteMemberValue(final ByteMemberValue mb)
+    {
+        mb.setValue((Byte) this.value);
+    }
+
+    public void visitCharMemberValue(final CharMemberValue mb)
+    {
+        mb.setValue((Character) this.value);
+    }
+
+    public void visitDoubleMemberValue(final DoubleMemberValue mb)
+    {
+        mb.setValue((Double) this.value);
+    }
+
+    public void visitEnumMemberValue(final EnumMemberValue mb)
+    {
+        final Enum enumeration = (Enum) this.value;
+        
+        final Class type = enumeration.getDeclaringClass();
+        mb.setType(type.getName());
+        mb.setValue(enumeration.name());
+    }
+
+    public void visitFloatMemberValue(final FloatMemberValue mb)
+    {
+        mb.setValue((Float) this.value);
+    }
+
+    public void visitIntegerMemberValue(final IntegerMemberValue mb)
+    {
+        mb.setValue((Integer) this.value);
+    }
+
+    public void visitLongMemberValue(final LongMemberValue mb)
+    {
+        mb.setValue((Long) this.value);
+    }
+
+    public void visitShortMemberValue(final ShortMemberValue mb)
+    {
+        mb.setValue((Short) this.value);
+    }
+
+    public void visitStringMemberValue(final StringMemberValue mb)
+    {
+        mb.setValue((String) this.value);
+    }
+
+    public void visitClassMemberValue(final ClassMemberValue mb)
+    {
+        mb.setValue(((Class) this.value).getName());
+    }
+
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/AnnotationMemberValueVisitor.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFabImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFabImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFabImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFabImpl.java Wed Jul 28 06:36:48 2010
@@ -18,6 +18,8 @@ import static java.lang.String.format;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newMap;
 import static org.apache.tapestry5.ioc.internal.util.CollectionFactory.newSet;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.Formatter;
 import java.util.Map;
@@ -29,6 +31,11 @@ import javassist.CtConstructor;
 import javassist.CtField;
 import javassist.CtMethod;
 import javassist.NotFoundException;
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ClassFile;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.MethodInfo;
+import javassist.bytecode.annotation.MemberValue;
 
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
 import org.apache.tapestry5.ioc.services.ClassFab;
@@ -337,4 +344,164 @@ public class ClassFabImpl extends Abstra
         description.append("\n");
         description.append(body);
     }
+    
+    public void copyClassAnnotationsFromDelegate(Class delegateClass)
+    {
+        lock.check();
+        
+        for (Annotation annotation : delegateClass.getAnnotations())
+        {
+            try
+            {
+                addAnnotation(annotation);
+            }
+            catch (RuntimeException ex) 
+            {
+                //Annotation processing may cause exceptions thrown by Javassist. 
+                //To provide backward compatibility we have to continue even though copying a particular annotation failed.
+                getLogger().error(String.format("Failed to copy annotation '%s' from '%s'", annotation.annotationType(), delegateClass.getName()));
+            }
+        }   
+    }
+    
+    public void copyMethodAnnotationsFromDelegate(Class serviceInterface, Class delegateClass)
+    {
+        lock.check();
+        
+        for(MethodSignature sig: addedSignatures)
+        {   
+            if(getMethod(sig, serviceInterface) == null)
+                continue;
+            
+            Method method = getMethod(sig, delegateClass);
+            
+            assert method != null;
+            
+            Annotation[] annotations = method.getAnnotations();
+            
+            for (Annotation annotation : annotations)
+            {   
+                try
+                {
+                    addMethodAnnotation(getCtMethod(sig), annotation);   
+                }
+                catch (RuntimeException ex) 
+                {
+                    //Annotation processing may cause exceptions thrown by Javassist. 
+                    //To provide backward compatibility we have to continue even though copying a particular annotation failed.
+                    getLogger().error(String.format("Failed to copy annotation '%s' from method '%s' of class '%s'", 
+                            annotation.annotationType(), method.getName(), delegateClass.getName()));
+                }
+            }
+        }
+    }
+    
+    private CtMethod getCtMethod(MethodSignature sig)
+    {
+        try
+        {
+            return getCtClass().getDeclaredMethod(sig.getName(), toCtClasses(sig.getParameterTypes()));
+        }
+        catch (NotFoundException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+    
+    private Method getMethod(MethodSignature sig, Class clazz)
+    {
+        try
+        {
+            return clazz.getMethod(sig.getName(), sig.getParameterTypes());
+        }
+        catch (Exception e)
+        {
+            return null;
+        }
+    }
+
+    private void addAnnotation(Annotation annotation)
+    {
+        
+        final ClassFile classFile = getClassFile();
+        
+        AnnotationsAttribute attribute = (AnnotationsAttribute) classFile.getAttribute(AnnotationsAttribute.visibleTag);
+        
+        if (attribute == null)
+        {
+            attribute = new AnnotationsAttribute(getConstPool(), AnnotationsAttribute.visibleTag);
+        }
+        
+        final javassist.bytecode.annotation.Annotation copy = toJavassistAnnotation(annotation);
+        
+        
+        attribute.addAnnotation(copy);
+        
+        classFile.addAttribute(attribute);
+        
+    }
+    
+    private void addMethodAnnotation(final CtMethod ctMethod, final Annotation annotation) {
+
+        MethodInfo methodInfo = ctMethod.getMethodInfo();
+
+        AnnotationsAttribute attribute = (AnnotationsAttribute) methodInfo
+            .getAttribute(AnnotationsAttribute.visibleTag);
+
+        if (attribute == null) {
+            attribute = new AnnotationsAttribute(getConstPool(), AnnotationsAttribute.visibleTag);
+        }
+
+        final javassist.bytecode.annotation.Annotation copy = toJavassistAnnotation(annotation);
+
+        attribute.addAnnotation(copy);
+
+        methodInfo.addAttribute(attribute);
+
+    }
+
+    
+    private ClassFile getClassFile()
+    {
+        return getCtClass().getClassFile();
+    }
+    
+    private ConstPool getConstPool() 
+    {   
+        return getClassFile().getConstPool();
+    }
+    
+    private javassist.bytecode.annotation.Annotation toJavassistAnnotation(final Annotation source)
+    {
+
+        final Class<? extends Annotation> annotationType = source.annotationType();
+
+        final ConstPool constPool = getConstPool();
+
+        final javassist.bytecode.annotation.Annotation copy = new javassist.bytecode.annotation.Annotation(
+                annotationType.getName(), constPool);
+
+        final Method[] methods = annotationType.getDeclaredMethods();
+
+        for (final Method method : methods)
+        {
+            try
+            {
+                CtClass ctType = toCtClass(method.getReturnType());
+                
+                final MemberValue memberValue = javassist.bytecode.annotation.Annotation.createMemberValue(constPool, ctType);
+                final Object value = method.invoke(source);
+
+                memberValue.accept(new AnnotationMemberValueVisitor(constPool, getSource(), value));
+
+                copy.addMemberValue(method.getName(), memberValue);
+            }
+            catch (final Exception e)
+            {
+                throw new RuntimeException(e);
+            }
+        }
+
+        return copy;
+    }
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImpl.java Wed Jul 28 06:36:48 2010
@@ -16,6 +16,7 @@ package org.apache.tapestry5.ioc.interna
 
 import static java.lang.String.format;
 
+import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
@@ -227,6 +228,11 @@ public class ClassFactoryImpl implements
 
     public <T> T createProxy(Class<T> proxyInterface, ObjectCreator delegateCreator, String description)
     {
+        return createProxy(proxyInterface, null, delegateCreator, description);
+    }
+
+    public <T> T createProxy(Class<T> proxyInterface, Class<? extends T> delegateClass, ObjectCreator delegateCreator, String description)
+    {
         ClassFab classFab = newClass(proxyInterface);
 
         classFab.addField("_creator", Modifier.PRIVATE | Modifier.FINAL, ObjectCreator.class);
@@ -239,8 +245,16 @@ public class ClassFactoryImpl implements
         MethodSignature sig = new MethodSignature(proxyInterface, "_delegate", null, null);
 
         classFab.addMethod(Modifier.PRIVATE, sig, body);
-
+        
         classFab.proxyMethodsToDelegate(proxyInterface, "_delegate()", description);
+        
+        if(delegateClass != null)
+        {
+            classFab.copyClassAnnotationsFromDelegate(delegateClass);
+            
+            classFab.copyMethodAnnotationsFromDelegate(proxyInterface, (Class)delegateClass);
+        }
+        
         Class proxyClass = classFab.createClass();
 
         try

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/util/InternalUtils.java Wed Jul 28 06:36:48 2010
@@ -48,6 +48,7 @@ import org.apache.tapestry5.ioc.def.Modu
 import org.apache.tapestry5.ioc.def.ServiceDef;
 import org.apache.tapestry5.ioc.def.ServiceDef2;
 import org.apache.tapestry5.ioc.def.StartupDef;
+import org.apache.tapestry5.ioc.internal.InternalServiceDef;
 import org.apache.tapestry5.ioc.services.ClassFabUtils;
 import org.apache.tapestry5.ioc.services.ClassFactory;
 import org.apache.tapestry5.ioc.services.Coercion;
@@ -797,6 +798,55 @@ public class InternalUtils
                                     + "You should make the constructor public, or mark an alternate public constructor with the @Inject annotation.",
                             constructor));
     }
+    
+    public static InternalServiceDef toInternalServiceDef(final ServiceDef sd)
+    {
+        if (sd instanceof InternalServiceDef)
+            return (InternalServiceDef) sd;
+
+        return new InternalServiceDef()
+        {
+            public boolean isPreventDecoration()
+            {
+                return false;
+            }
+
+            public ObjectCreator createServiceCreator(ServiceBuilderResources resources)
+            {
+                return sd.createServiceCreator(resources);
+            }
+
+            public String getServiceId()
+            {
+                return sd.getServiceId();
+            }
+
+            public Set<Class> getMarkers()
+            {
+                return sd.getMarkers();
+            }
+
+            public Class getServiceInterface()
+            {
+                return sd.getServiceInterface();
+            }
+
+            public String getServiceScope()
+            {
+                return sd.getServiceScope();
+            }
+
+            public boolean isEagerLoad()
+            {
+                return sd.isEagerLoad();
+            }
+            
+            public Class getImplementationClass()
+            {
+                return null;
+            }
+        };
+    }
 
     public static ServiceDef2 toServiceDef2(final ServiceDef sd)
     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFab.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFab.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFab.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFab.java Wed Jul 28 06:36:48 2010
@@ -90,6 +90,25 @@ public interface ClassFab
      * @param toString           fixed value to be returned as the description of the resultant object
      */
     void proxyMethodsToDelegate(Class serviceInterface, String delegateExpression, String toString);
+    
+    /**
+     * Copies annotations from delegate class to the fabricated class. 
+     * 
+     * @param delegateClass class of the delegate
+     * 
+     * @since 5.2.0
+     */
+    void copyClassAnnotationsFromDelegate(Class delegateClass);
+    
+    /**
+     * Copies method annotations from delegate class to the methods of the fabricated class. 
+     * 
+     * @param serviceInterface service interface
+     * @param delegateClass class of the delegate
+     * 
+     * @since 5.2.0
+     */
+    void copyMethodAnnotationsFromDelegate(Class serviceInterface, Class delegateClass);
 
     /**
      * Invoked last to create the class. This will enforce that all abstract methods have been implemented in the

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFactory.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFactory.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFactory.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ClassFactory.java Wed Jul 28 06:36:48 2010
@@ -95,9 +95,31 @@ public interface ClassFactory
      *            type of proxy
      * @param proxyInterface
      *            proxy interface class
+     * @parame delegateCreator
+     *            creates the delegate
      * @param description
      *            used for the toString() method
      * @since 5.2.0
      */
     <T> T createProxy(Class<T> proxyInterface, ObjectCreator delegateCreator, String description);
+
+    /**
+     * Creates a proxy for an interface. All methods of the interface are delegated through the
+     * object returned from the {@link ObjectCreator} (which is accessed on each method invocation, so it
+     * is responsible for caching of the true delegate). The description will be used for the toString() method
+     * (unless toString() is part of the proxy interface).
+     * 
+     * @param <T>
+     *            type of proxy
+     * @param proxyInterface
+     *            proxy interface class
+     * @parame delegateClass
+     *            delegate class
+     * @parame delegateCreator
+     *            creates the delegate
+     * @param description
+     *            used for the toString() method
+     * @since 5.2.0
+     */
+    <T> T createProxy(Class<T> proxyInterface, Class<? extends T> delegateClass, ObjectCreator delegateCreator, String description);
 }

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/IntegrationTest.java Wed Jul 28 06:36:48 2010
@@ -15,6 +15,7 @@
 package org.apache.tapestry5.ioc;
 
 import java.io.File;
+import java.lang.reflect.Method;
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.sql.PreparedStatement;
@@ -31,6 +32,7 @@ import org.apache.tapestry5.ioc.internal
 import org.apache.tapestry5.ioc.internal.IOCInternalTestCase;
 import org.apache.tapestry5.ioc.internal.PrivateConstructorModule;
 import org.apache.tapestry5.ioc.internal.UpcaseService;
+import org.apache.tapestry5.ioc.internal.services.SimpleAnnotation;
 import org.apache.tapestry5.ioc.internal.services.StartupModule2;
 import org.apache.tapestry5.ioc.services.Builtin;
 import org.apache.tapestry5.ioc.services.ServiceActivity;
@@ -409,6 +411,26 @@ public class IntegrationTest extends IOC
 
         r.shutdown();
     }
+    
+    @Test
+    public void proxy_annotations() throws Exception
+    {
+        Registry r = buildRegistry(AutobuildModule.class);
+
+        StringHolder sh = r.getService(StringHolder.class);
+        
+        SimpleAnnotation annotation = sh.getClass().getAnnotation(SimpleAnnotation.class);
+        assertNotNull(annotation);
+        assertEquals(annotation.value(), "StringHolderImpl");
+        
+        Method method = sh.getClass().getMethod("getValue");
+        
+        annotation = method.getAnnotation(SimpleAnnotation.class);
+        assertNotNull(annotation);
+        assertEquals(annotation.value(), "StringHolderImpl#getValue()");
+
+        r.shutdown();
+    }
 
     @Test
     public void exception_in_autobuild_service_constructor()

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/StringHolderImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/StringHolderImpl.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/StringHolderImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/StringHolderImpl.java Wed Jul 28 06:36:48 2010
@@ -14,13 +14,17 @@
 
 package org.apache.tapestry5.ioc;
 
+import org.apache.tapestry5.ioc.internal.services.SimpleAnnotation;
+
 /**
  *
  */
+@SimpleAnnotation("StringHolderImpl")
 public class StringHolderImpl implements StringHolder
 {
     private String value;
 
+    @SimpleAnnotation("StringHolderImpl#getValue()")
     public String getValue()
     {
         return value;

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/RecursiveServiceCreationCheckWrapperTest.java Wed Jul 28 06:36:48 2010
@@ -32,7 +32,7 @@ public class RecursiveServiceCreationChe
         ObjectCreator delegate = mockObjectCreator();
         Object service = new Object();
 
-        ServiceDef def = new ServiceDefImpl(Runnable.class, "Bar", null, "singleton", false, false, source);
+        ServiceDef def = new ServiceDefImpl(Runnable.class, null, "Bar", null, "singleton", false, false, source);
 
         train_createObject(delegate, service);
 
@@ -70,7 +70,7 @@ public class RecursiveServiceCreationChe
         ObjectCreator delegate = mockObjectCreator();
         Object service = new Object();
 
-        ServiceDef def = new ServiceDefImpl(Runnable.class, "Bar", null, "singleton", false, false, source);
+        ServiceDef def = new ServiceDefImpl(Runnable.class, null, "Bar", null, "singleton", false, false, source);
 
         expect(delegate.createObject()).andThrow(failure);
 

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFabImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFabImplTest.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFabImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFabImplTest.java Wed Jul 28 06:36:48 2010
@@ -14,9 +14,24 @@
 
 package org.apache.tapestry5.ioc.internal.services;
 
+import static java.util.Arrays.asList;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.zip.DataFormatException;
+
 import javassist.CtClass;
+
 import org.apache.tapestry5.ioc.BaseLocatable;
+import org.apache.tapestry5.ioc.annotations.ServiceId;
 import org.apache.tapestry5.ioc.internal.services.LoggingDecoratorImplTest.ToStringService;
+import org.apache.tapestry5.ioc.internal.services.TestAnnotation.Color;
+import org.apache.tapestry5.ioc.internal.services.TestAnnotation.TestAnnotation2;
 import org.apache.tapestry5.ioc.services.ClassFab;
 import org.apache.tapestry5.ioc.services.MethodSignature;
 import org.apache.tapestry5.ioc.services.PropertyAccess;
@@ -24,13 +39,6 @@ import org.apache.tapestry5.ioc.test.IOC
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.Test;
 
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.util.List;
-import java.util.Map;
-import java.util.zip.DataFormatException;
-
 public class ClassFabImplTest extends IOCTestCase
 {
     private final CtClassSource source;
@@ -50,6 +58,46 @@ public class ClassFabImplTest extends IO
     {
         String toString();
     }
+    
+    public interface AnnotatedService
+    {
+        void doWork(final String value);
+    }
+    
+    @ServiceId(value = "myService")
+    @TestAnnotation(annotationValue={@TestAnnotation2(colors={Color.RED, Color.GREEN})},
+            booleanValue = true, 
+            charValue = 'I', 
+            byteValue = 97, 
+            classValue = AnnotatedServiceImpl.class, 
+            doubleValue = 3.14, 
+            enumValue = Color.RED, 
+            floatValue = 2.718F, 
+            intValue = 123, 
+            longValue = 456L, 
+            shortValue = 3, 
+            stringValue = "foo")
+    public class AnnotatedServiceImpl implements AnnotatedService
+    {
+
+        @TestAnnotation(annotationValue=@TestAnnotation2(colors={Color.BLUE, Color.GREEN}),
+                arrayValue={"barney"},
+                booleanValue = false, 
+                charValue = 'D', 
+                byteValue = 56, 
+                classValue = String.class, 
+                doubleValue = 3.14, 
+                enumValue = Color.BLUE, 
+                floatValue = 2.718F, 
+                intValue = 456, 
+                longValue = 789L, 
+                shortValue = 4, 
+                stringValue = "bar")
+        public void doWork(final String value)
+        {
+
+        }
+    }
 
     public ClassFabImplTest()
     {
@@ -424,6 +472,68 @@ public class ClassFabImplTest extends IO
         assertEquals(access.get(instance, "int"), 0);
         assertEquals(access.get(instance, "double"), 0.0d);
     }
+    
+
+    @Test
+    public void add_annotation() throws Exception
+    {
+        final ClassFab cf = newClassFab("AnnotatedClass", Object.class);
+
+        cf.addField("_delegate", AnnotatedService.class);
+        cf.addConstructor(new Class[] { AnnotatedService.class }, null, "_delegate = $1;");
+
+        cf.proxyMethodsToDelegate(AnnotatedService.class, "_delegate", "Bla bla");
+        cf.copyClassAnnotationsFromDelegate(AnnotatedServiceImpl.class);
+        cf.copyMethodAnnotationsFromDelegate(AnnotatedService.class, AnnotatedServiceImpl.class);
+
+        final Class targetClass = cf.createClass();
+
+        final TestAnnotation a = (TestAnnotation) targetClass.getAnnotation(TestAnnotation.class);
+
+        assertNotNull(a);
+        
+        TestAnnotation2 a2 = a.annotationValue()[0];
+
+        assertNotNull(a2);
+        assertEquals(asList(a2.colors()), asList(Color.RED, Color.GREEN));
+        
+        assertEquals(asList(a.arrayValue()), asList("foo", "bar"));
+        assertTrue(a.booleanValue());
+        assertEquals(a.byteValue(), 97);
+        assertEquals(a.charValue(), 'I');
+        assertEquals(a.classValue(), AnnotatedServiceImpl.class);
+        assertEquals(a.doubleValue(), 3.14);
+        assertEquals(a.enumValue(), Color.RED);
+        assertEquals(a.floatValue(), 2.718F);
+        assertEquals(a.intValue(), 123);
+        assertEquals(a.longValue(), 456L);
+        assertEquals(a.shortValue(), 3);
+        assertEquals(a.stringValue(), "foo");
+
+        assertNotNull(targetClass.getAnnotation(ServiceId.class));
+        
+        Method method = targetClass.getMethod("doWork", String.class);
+        TestAnnotation methodAnnotation = method.getAnnotation(TestAnnotation.class);
+        
+        assertNotNull(methodAnnotation);
+        
+        a2 = methodAnnotation.annotationValue()[0];
+        
+        assertNotNull(a2);
+        assertEquals(asList(a2.colors()), asList(Color.BLUE, Color.GREEN));
+        assertEquals(Arrays.asList(methodAnnotation.arrayValue()), Arrays.asList("barney"));
+        assertFalse(methodAnnotation.booleanValue());
+        assertEquals(methodAnnotation.byteValue(), 56);
+        assertEquals(methodAnnotation.charValue(), 'D');
+        assertEquals(methodAnnotation.classValue(), String.class);
+        assertEquals(methodAnnotation.doubleValue(), 3.14);
+        assertEquals(methodAnnotation.enumValue(), Color.BLUE);
+        assertEquals(methodAnnotation.floatValue(), 2.718F);
+        assertEquals(methodAnnotation.intValue(), 456);
+        assertEquals(methodAnnotation.longValue(), 789L);
+        assertEquals(methodAnnotation.shortValue(), 4);
+        assertEquals(methodAnnotation.stringValue(), "bar");
+    }  
 
     private void assertContains(String actual, String expectedSubstring)
     {

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImplTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImplTest.java?rev=979956&r1=979955&r2=979956&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImplTest.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ClassFactoryImplTest.java Wed Jul 28 06:36:48 2010
@@ -14,7 +14,12 @@
 
 package org.apache.tapestry5.ioc.internal.services;
 
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
 import org.apache.tapestry5.ioc.Location;
+import org.apache.tapestry5.ioc.ObjectCreator;
 import org.apache.tapestry5.ioc.internal.util.LocationImpl;
 import org.apache.tapestry5.ioc.services.ClassFab;
 import org.apache.tapestry5.ioc.services.ClassFabUtils;
@@ -23,10 +28,6 @@ import org.apache.tapestry5.ioc.services
 import org.apache.tapestry5.ioc.test.IOCTestCase;
 import org.testng.annotations.Test;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-
 public class ClassFactoryImplTest extends IOCTestCase
 {
     public static class BaseClass
@@ -170,4 +171,47 @@ public class ClassFactoryImplTest extend
 
         assertSame(factory.importClass(alienClass), clazz);
     }
+    
+    
+    @Test
+    public void with_annotations() throws Exception
+    {
+        ClassFactory factory = new ClassFactoryImpl();
+
+        TestService proxy = factory.createProxy(TestService.class, TestServiceImpl.class, new ObjectCreator()
+        {
+            public Object createObject()
+            {
+                return new TestServiceImpl();
+            }
+        }, "Proxy<TestService>");
+        
+        Class clazz =  proxy.getClass();
+        
+        SimpleAnnotation annotation = (SimpleAnnotation) clazz.getAnnotation(SimpleAnnotation.class);
+        
+        assertNotNull(annotation);
+        assertEquals(annotation.value(), "TestServiceImpl");
+        
+        Method method = clazz.getMethod("doSomething");
+
+        annotation = method.getAnnotation(SimpleAnnotation.class);
+        assertEquals(annotation.value(), "TestServiceImpl#doSomething");
+    }
+    
+
+    public interface TestService
+    {
+        void doSomething();
+    }
+    
+    @SimpleAnnotation("TestServiceImpl")
+    public class TestServiceImpl implements TestService
+    {
+        @SimpleAnnotation("TestServiceImpl#doSomething")
+        public void doSomething()
+        {
+            
+        }
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java?rev=979956&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java Wed Jul 28 06:36:48 2010
@@ -0,0 +1,30 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.internal.services;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({ TYPE, METHOD })
+@Retention(RUNTIME)
+@Documented
+public @interface SimpleAnnotation
+{
+    String value();
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/SimpleAnnotation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java?rev=979956&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java Wed Jul 28 06:36:48 2010
@@ -0,0 +1,68 @@
+// Copyright 2010 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package org.apache.tapestry5.ioc.internal.services;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+@Target({ TYPE, METHOD })
+@Retention(RUNTIME)
+@Documented
+public @interface TestAnnotation
+{
+
+    TestAnnotation2[] annotationValue();
+
+    String[] arrayValue() default { "foo", "bar" };
+
+    boolean booleanValue();
+
+    byte byteValue();
+
+    char charValue();
+
+    Class classValue();
+
+    double doubleValue();
+
+    Color enumValue();
+
+    float floatValue();
+
+    int intValue();
+
+    long longValue();
+
+    short shortValue();
+
+    String stringValue();
+    
+    public enum Color
+    {
+        RED, GREEN, BLUE
+    }
+    
+    @Target({ TYPE, METHOD })
+    @Retention(RUNTIME)
+    @Documented
+    public @interface TestAnnotation2
+    {
+        Color[] colors();
+    }
+}

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/TestAnnotation.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain