PDA

View Full Version : ProxyTargetType mixed with ProxyInterface


dziegel
04-19-2007, 02:55 PM
Hello,

I've created this test:

using System;
using Spring.Context.Support;
using System.Reflection;
using System.Diagnostics;

namespace SpringProxying
{
public interface Interface1
{
void FunctionInterface1();
}

public interface Interface2
{
void FunctionInterface2();
}

public class ToBeProxied: Interface1, Interface2
{
private int m_someValue = 0;

public ToBeProxied()
{
}

public int someValue
{
get
{
return m_someValue;
}
}

#region Interface1 Member

void Interface1.FunctionInterface1()
{
m_someValue = 1;
}

#endregion

#region Interface2 Member

void Interface2.FunctionInterface2()
{
m_someValue = 2;
}

#endregion
};

class Class1
{
[STAThread]
static void Main(string[] args)
{
XmlApplicationContext c = new XmlApplicationContext("assembly://SpringProxying/SpringProxying/Spring.xml");
ToBeProxied proxied = (ToBeProxied)c.GetObject("proxiedClass");
ToBeProxied unproxied = (ToBeProxied)c.GetObject("unproxiedClass");

// target of proxiedClass == unproxiedClass since unproxiedClass is a singleton
// ProxyTargetType == true
// ProxyInterfaces = ['Interface1'] --- -> Interface2 is NOT proxied!

Debug.WriteLine("Unproxied: " + unproxied.someValue); // Prints "0"
Debug.WriteLine("Proxied: " + proxied.someValue); // Prints "0"

(proxied as Interface1).FunctionInterface1();

Debug.WriteLine("Unproxied: " + unproxied.someValue); // Prints "1"
Debug.WriteLine("Proxied: " + proxied.someValue); // Prints "0"

(proxied as Interface2).FunctionInterface2();

Debug.WriteLine("Unproxied: " + unproxied.someValue); // Prints "1"
Debug.WriteLine("Proxied: " + proxied.someValue); // Prints "2"
}
}
}



<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net">
<object id="unproxiedClass" type="SpringProxying.ToBeProxied" singleton="true" />
<object id="proxiedClass" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="Target" ref="unproxiedClass" />
<property name="ProxyTargetType" value="true" />
<property name="ProxyInterfaces">
<list>
<value>SpringProxying.Interface1</value>
</list>
</property>
</object>
</objects>


Am I misusing Spring if I mix ProxyTargetType=true with ProxyInterface=[<list>]?
It seems Spring does not redirect the unproxied call to FunctionInterface2() to the target. I wanted to use this as a simple way to intercept only calls to FunctionInterface1() in my app...

VS 2003 ZIP archive available on request for debugging.

Spring Nightly 20070418-1234.

Dirk

Erich Eichinger
04-19-2007, 09:53 PM
Hi,

Just out of my mind try the following:

*) Set ProxyTargetType=false
*) Make SomeValue property virtual
*) From within your interface functions, access SomeValue through a property settings

I think this should do what you are trying to achieve.

-Erich

dziegel
04-20-2007, 08:01 AM
Hello,

setting ProxyTargetType to false wouldn't work since the property cannot be accessed in the proxied interface.

The real point of this is the question whether I try to use Spring in a strange way.

As I understood, the way proxying works is that Spring creates a proxy class that redirects all calls to the target instance.
When I use a definition as follows:


<object id="unproxiedClass" type="SpringProxying.ToBeProxied" singleton="true" />
<object id="proxiedClass" type="Spring.Aop.Framework.ProxyFactoryObject, Spring.Aop">
<property name="Target" ref="unproxiedClass" />
<property name="ProxyTargetType" value="true" />
<property name="ProxyInterfaces">
<list>
<value>SpringProxying.Interface1</value>
</list>
</property>
</object>


this means that ALL calls to an instance of proxiedClass are forwarded to the instance of unproxiedClass. That means if I do GetObject("unproxiedClass") I will see the effect of all calls to proxiedClass on it since unproxiedClass is a singleton.

What happens if I tell spring, as in the scenario above, to proxy the whole class in combination with "only Interface1"? My guess is I shouldn't do that since Spring cannot handle this.

Maybe an assertion could be added that using "ProxyTargetType=true" in combination with "ProxyInterfaces" is not supported or does not make sense.

Dirk

Bruno Baia
04-20-2007, 10:42 AM
this means that ALL calls to an instance of proxiedClass are forwarded to the instance of unproxiedClass.
True if your method is virtual or if it belongs to a proxied interface.
So if you don't want to proxy the Interface2, your method needs to be virtual.


#region Interface2 Member

virtual void FunctionInterface2()
{
m_someValue = 2;
}

#endregion


HTH,
Bruno

matthias
07-16-2007, 02:59 PM
this means that ALL calls to an instance of proxiedClass are forwarded to the instance of unproxiedClass.
True if your method is virtual or if it belongs to a proxied interface.
...


Do I understand this right that calls of non-virtual and non-interfaced methods on the proxied class are NOT forwarded to the target? I thought that non-virtual methods cannot be intercepted but would still be forwarded. Am I wrong?

Or, to put it in code:

ProxyFactory factory = new ProxyFactory(new T());
factory.ProxyTargetType = true;
T proxy = (T)factory.GetProxy();


I would expect proxy to behave excactly like an instance of T. Is this correct?

Matthias

Bruno Baia
07-16-2007, 03:42 PM
Hi,

Do I understand this right that calls of non-virtual and non-interfaced methods on the proxied class are NOT forwarded to the target? I thought that non-virtual methods cannot be intercepted but would still be forwarded. Am I wrong?

Nop.
Like in Java, ProxyTargetType=true still uses the decorator pattern.


I would expect proxy to behave excactly like an instance of T. Is this correct?

I got the same reaction too, and we are not alone ( SPRNET-540 (http://opensource.atlassian.com/projects/spring/browse/SPRNET-540) )
We want to support this in furture versions by creating a Inheritance based proxy to support constructor interceptors or calls to 'this' in a proxied class.
The implementation is not so hard, the problem is how make it work with Spring, because Spring manages object instances and not types.


HTH,
Bruno

matthias
07-18-2007, 10:14 AM
Hi Bruno,

thank you for your answer which made things quite clear. It's also consoling to know not to be alone with certain expectations ;-)

Let's hope that there will be soon support for inheritance based proxies. Meanwhile maybe you might want to consider updating chapter 12.5.4 in the documentation to keep others from stumbling into this pitfall.

Currently it reads:
However, there is an important issue to consider: Non-virtual methods can't be advised, as they can't be overridden.

I think it should better say sth. like "... can't be advised and not even successfully called on the proxy ..." Also, some lines before subclassing is mentioned. This all together made me think my approach would work.

BTW: what I was actually trying was to override SoapHttpClientProtocol.GetReaderForMessage the same way on several generated web service proxies to make them validate the responses from the server against the schema in the WSDL (a measure that turned out to be necessary in our specific circumstances :-( ). I was looking for a dynamic approach because there is more than one proxy and they need to be regenerated quite often. I finally managed doing it using CodeDom, but would there have been something in the Spring WebServiceProxyFactory to help me on this?

Matthias