PDA

View Full Version : Method implementation can not be a final method?


Mike Plavsky
06-21-2007, 02:20 PM
when I am trying to replace public virtual method in the class by implementing IMethodReplacer, I am getting the following error when loading application context from xml file:

Test method TestSpring.AopLoggingTest.TestLogging threw exception: Spring.Objects.Factory.ObjectCreationException: Error creating object with name 'SourcePermissions' defined in 'assembly [TestSpring, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null], resource [TestSpring.Resources.autoProxyLogging.xml]' : Initialization of object failed : Declaration referenced in a method implementation cannot be a final method. Type: 'DecoratorAopProxy_0f74d1e826c240c790b18c2b2fc0618 0'. Assembly: 'Spring.Proxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. ---> System.TypeLoadException: Declaration referenced in a method implementation cannot be a final method. Type: 'DecoratorAopProxy_0f74d1e826c240c790b18c2b2fc0618 0'. Assembly: 'Spring.Proxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'..

With the following Stack Trace:

at System.Reflection.Emit.TypeBuilder.TermCreateClass (Int32 handle, Module module)
at System.Reflection.Emit.TypeBuilder.CreateTypeNoLoc k()
at System.Reflection.Emit.TypeBuilder.CreateType()
at Spring.Aop.Framework.DynamicProxy.DecoratorAopProx yTypeBuilder.BuildProxyType()
at Spring.Aop.Framework.DefaultAopProxyFactory.Create AopProxy(AdvisedSupport advisedSupport)
at Spring.Aop.Framework.AdvisedSupport.CreateAopProxy ()
at Spring.Aop.Framework.ProxyFactory.GetProxy()
at Spring.Aop.Framework.AutoProxy.AbstractAutoProxyCr eator.PostProcessAfterInitialization(Object obj, String name)
at Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.ApplyObjectPostProcessorsAfterIn itialization(Object instance, String name)
at Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.ConfigureObject(String name, RootObjectDefinition definition, IObjectWrapper wrapper)
at Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.CreateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching)
--- End of inner exception stack trace ---
at Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.CreateObject(String name, RootObjectDefinition definition, Object[] arguments, Boolean allowEagerCaching)
at Spring.Objects.Factory.Support.AbstractAutowireCap ableObjectFactory.CreateObject(String name, RootObjectDefinition definition, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFacto ry.CreateAndCacheSingletonInstance(String objectName, RootObjectDefinition objectDefinition, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObject(String name, Type requiredType, Object[] arguments)
at Spring.Objects.Factory.Support.AbstractObjectFacto ry.GetObject(String name, Object[] arguments)
at Spring.Objects.Factory.Support.DefaultListableObje ctFactory.PreInstantiateSingletons()
at Spring.Context.Support.AbstractApplicationContext. Refresh()
at Spring.Context.Support.XmlApplicationContext..ctor (String[] configurationLocations)
at TestSpring.AopLoggingTest.TestLogging() in C:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\TestSpring\TestSpring\AopLoggingTest .cs:line 26

Mike Plavsky
06-21-2007, 07:05 PM
It looks like the problem exists only if the property ProxyTargetType is true. If it is false, everything is fine. So this configuration doesn't work:

<object id ="ProxyCreator" type="Spring.Aop.Framework.AutoProxy.ObjectNameAutoProxy Creator, Spring.Aop">

<property name="ProxyTargetType" value="true"/> <property name="ExposeProxy" value="true"/>

<property name="ObjectNames">
<list>
<value>Source*</value>
</list>
</property>

<property name="interceptorNames">
<list>
<value>Logger</value>
</list>
</property>

</object>

Bruno Baia
06-24-2007, 11:57 PM
Hi,

ProxyTargetType=true uses Decorator proxies which make your proxy inherit from the target type and override virtual methods, but if a method is final it should not throw an error.
Can you post the definition of your class that cause the pb ('SourcePermissions' object) ?


Bruno

Mike Plavsky
06-25-2007, 08:11 PM
Sure here it is, as far as I can see nothing about 'final':

namespace TestSpring
{
public class SourcePermissions : ISourceSharePointPermissions
{
public void GetPermissions()
{
sourceSharePoint.GetSourceName();
}

public ISourceSharePoint SourceSharePoint
{
get { return sourceSharePoint;}
set { sourceSharePoint = value;}
}

public virtual void MakeIt()
{ }

public virtual void TransferPermissions(String permission)
{
This().MakeIt();
}

public virtual void TransferPermissions(String permission, String permission1)
{ }

public virtual ISourceSharePointPermissions This()
{
return this;
}

ISourceSharePoint sourceSharePoint;
}
}

And:

namespace TestSpring
{
public interface ISourceSharePointPermissions
{
void GetPermissions();
void TransferPermissions(String permission);
void TransferPermissions(String permission, String permission1);
void MakeIt();
}
}

Bruno Baia
06-25-2007, 09:47 PM
Methods are by default 'final' in C# (!= JAVA), so to use ProxyFactoryType=true, you need to mark every methods that does not belong to the ISourceSharePointPermissions interface as 'virtual'.

Anyway, you should only use ProxyFactoryType=true when necessary, there is too many side effects.
12.5.4. Proxying Classes (http://www.springframework.net/doc-1.1-M1/reference/html/aop.html#d0e7675)


HTH,
Bruno

Mike Plavsky
06-26-2007, 07:58 PM
Hi Bruno,

Sorry for this but I marked all methods as virtual (in fact only property SourceSharePoint wasn't virtual), and still the same error :(

Test method TestSpring.AopLoggingTest.TestLogging threw exception: Spring.Objects.Factory.ObjectCreationException: Error creating object with name 'SourcePermissions' defined in 'assembly [TestSpring, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null], resource [TestSpring.Resources.autoProxyLogging.xml]' : Initialization of object failed : Declaration referenced in a method implementation cannot be a final method. Type: 'DecoratorAopProxy_d40c1b9ffb7942a6a8e818aa8a40a7f a'. Assembly: 'Spring.Proxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. ---> System.TypeLoadException: Declaration referenced in a method implementation cannot be a final method. Type: 'DecoratorAopProxy_d40c1b9ffb7942a6a8e818aa8a40a7f a'. Assembly: 'Spring.Proxy, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'..

Here is the new version of the class:

public class SourcePermissions : ISourceSharePointPermissions
{
virtual public void GetPermissions()
{
sourceSharePoint.GetSourceName();
}

virtual public ISourceSharePoint SourceSharePoint
{
get { return sourceSharePoint;}
set { sourceSharePoint = value;}
}

public virtual void MakeIt()
{ }

public virtual void TransferPermissions(String permission)
{
This().MakeIt();
}

public virtual void TransferPermissions(String permission, String permission1)
{ }

public virtual ISourceSharePointPermissions This()
{
return this;
}

ISourceSharePoint sourceSharePoint;
}

Bruno Baia
06-26-2007, 08:47 PM
Hi,

hmmm.. what's your configuration ?
Spring version, OS, Spring dll in GAC, Debug or Release version ?


Bruno

Mike Plavsky
06-27-2007, 06:32 PM
I don't use GAC.

Spring.Core 1.1.0.2 Release
Spring.Aop 1.1.0.2 Release
mscorlib, Version 2.0.0.0
Microsoft Windows Server 2003 SP1

BTW I use method replace:

<object id="SourcePermissions" type="TestSpring.SourcePermissions" autowire="byName">
<replaced-method name="This" replacer="ReplaceThis"/>
</object>

And

public class ReplaceThis : IMethodReplacer
{
public object Implement(object target, System.Reflection.MethodInfo method, object[] arguments)
{
return AopContext.CurrentProxy;
}
}

Bruno Baia
06-27-2007, 11:26 PM
Oki, you are using method injection.

What you are trying to do (returning proxy instead of this) should be done by AOP proxies.
Have you tried without method injection ?


Bruno

Mike Plavsky
07-03-2007, 06:08 PM
If object calls itself, it is not being proxied as 'this' here is the pointer to the actual instance - not to the proxy. But I wanted to catch these calls to itself. For example to do logging. So I tried to override This() if object was created through Spring, and use the actual 'this', if there is no Spring. So class knows nothing about Spring (except it has to call itself through This() function – but there is still no coupling to Spring), but it is still possible to catch internal calls. Just AOP would not work here. Does it make sense?

Bruno Baia
08-07-2007, 06:09 PM
Hi,

I've been able to reproduce your pb.
I detected a bug in method injection, I'll keep you informed.


Bruno

Bruno Baia
08-21-2007, 09:35 AM
Hi,

the bug has been resolved in 1.1 RC1.
You should be able to proxy 'this' using method injection now.

Note that ProxyTargetType=true is not required, you just need to mark your "This" method as virtual to get method injection working.

I've uploaded an example to the wiki's forum question (http://opensource.atlassian.com/confluence/spring/display/NET/Forum+Questions) page based on the Spring.AopQuickStart sample:
Thread 3030 - Proxying 'this' with Spring.Aop and method injection


Related thread (http://forum.springframework.net/showthread.php?t=3328).

- Bruno