simoncutting
Mar 1st, 2010, 04:58 PM
Hi,
I have a prototype application that is using Spring Security 2.0.5 to secure a JAX-RS annotated application. With JAX-RS there is a single entry point which maps to a bean. Depending on the URL of the requested resource this bean will instantiate another bean (and that bean might instantiate another and so on down the resource hierarchy). We've tried a number of different patterns for instantiating an instance of the bean and are currently using a factory which contains the context.getBean("bean name"). This approach works until I add the intercept-methods to the bean definition I am trying to instantiate which leads to a class cast exception. I have previously added AOP advice to the application which gave me the same error but using the proxy-target-class="true" attribute on the aop config fixed that.
I am pretty new to Spring at this level of detail but it appears that when I add the intercept-methods Spring is using the JDK dynamic proxy which causes all the heartburn when the getBean() method returns a proxy object. I have tried using both the implementation and the interface in the factory and aside from moving the point where the exception is thrown the behaviour is identical.
Any help would be greatly appreciated.
Simon
Snippet from beans.xml
<bean id="Patient" class="com.emc.cto.healthcare.impl.PatientImpl" scope="prototype" autowire="no">
<sec:intercept-methods access-decision-manager-ref="businessAccessDecisionManager" >
<sec:protect method="getPatient" access="ROLE_PHYSICIAN"/>
<sec:protect method="deletePatient" access="ROLE_ADMIN"/>
<sec:protect method="modifyPatient" access="ROLE_ADMIN,ROLE_PHYSICIAN"/>
</sec:intercept-methods>
</bean>
The call to the factory method in the "top level" bean:
@Path("/{pid}")
public Patient getPatientByID(@PathParam("pid")String pid) {
//Patient patient = new Patient(pid);
PatientImpl patient = (PatientImpl) ResourceFactory.getDefaultFactory().newPatient(pid ); << Exception here
patient.setBaseURI(getSelfURI());
return patient;
}
The factory method (Patient is an interface):
public Patient newPatient(String pid) {
Patient obj = null;
obj = (Patient) context.getBean("Patient");
obj.setPid(pid);
System.out.println("newPatient obj.getClass = " + obj.getClass());
return obj;
}
The println above prints "newPatient obj.getClass = class $Proxy43"
Now an excerpt from the stack trace:
Caused by: org.apache.cxf.interceptor.Fault: $Proxy43
at org.apache.cxf.service.invoker.AbstractInvoker.cre ateFault(AbstractInvoker.java:148)
at org.apache.cxf.service.invoker.AbstractInvoker.inv oke(AbstractInvoker.java:114)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvo ker.java:130)
at com.emc.cto.cxf.jaxrs.XJAXRSInvoker.invoke(XJAXRSI nvoker.java:15)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvo ker.java:82)
at org.apache.cxf.interceptor.ServiceInvokerIntercept or$1.run(ServiceInvokerInterceptor.java:58)
at java.util.concurrent.Executors$RunnableAdapter.cal l(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unkn own Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at org.apache.cxf.workqueue.SynchronousExecutor.execu te(SynchronousExecutor.java:37)
at org.apache.cxf.interceptor.ServiceInvokerIntercept or.handleMessage(ServiceInvokerInterceptor.java:98 )
at org.apache.cxf.phase.PhaseInterceptorChain.doInter cept(PhaseInterceptorChain.java:236)
... 47 more
Caused by: java.lang.ClassCastException: $Proxy43
at com.emc.cto.healthcare.impl.PatientsImpl.getPatien tByID(PatientsImpl.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoi npointUsingReflection(AopUtils.java:310)
at org.springframework.aop.framework.ReflectiveMethod Invocation.invokeJoinpoint(ReflectiveMethodInvocat ion.java:182)
at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :149)
at org.springframework.security.intercept.method.aopa lliance.MethodSecurityInterceptor.invoke(MethodSec urityInterceptor.java:66)
at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :171)
at org.springframework.aop.framework.JdkDynamicAopPro xy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy38.getPatientByID(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.cxf.service.invoker.AbstractInvoker.per formInvocation(AbstractInvoker.java:166)
at org.apache.cxf.service.invoker.AbstractInvoker.inv oke(AbstractInvoker.java:82)
... 57 more
I have a prototype application that is using Spring Security 2.0.5 to secure a JAX-RS annotated application. With JAX-RS there is a single entry point which maps to a bean. Depending on the URL of the requested resource this bean will instantiate another bean (and that bean might instantiate another and so on down the resource hierarchy). We've tried a number of different patterns for instantiating an instance of the bean and are currently using a factory which contains the context.getBean("bean name"). This approach works until I add the intercept-methods to the bean definition I am trying to instantiate which leads to a class cast exception. I have previously added AOP advice to the application which gave me the same error but using the proxy-target-class="true" attribute on the aop config fixed that.
I am pretty new to Spring at this level of detail but it appears that when I add the intercept-methods Spring is using the JDK dynamic proxy which causes all the heartburn when the getBean() method returns a proxy object. I have tried using both the implementation and the interface in the factory and aside from moving the point where the exception is thrown the behaviour is identical.
Any help would be greatly appreciated.
Simon
Snippet from beans.xml
<bean id="Patient" class="com.emc.cto.healthcare.impl.PatientImpl" scope="prototype" autowire="no">
<sec:intercept-methods access-decision-manager-ref="businessAccessDecisionManager" >
<sec:protect method="getPatient" access="ROLE_PHYSICIAN"/>
<sec:protect method="deletePatient" access="ROLE_ADMIN"/>
<sec:protect method="modifyPatient" access="ROLE_ADMIN,ROLE_PHYSICIAN"/>
</sec:intercept-methods>
</bean>
The call to the factory method in the "top level" bean:
@Path("/{pid}")
public Patient getPatientByID(@PathParam("pid")String pid) {
//Patient patient = new Patient(pid);
PatientImpl patient = (PatientImpl) ResourceFactory.getDefaultFactory().newPatient(pid ); << Exception here
patient.setBaseURI(getSelfURI());
return patient;
}
The factory method (Patient is an interface):
public Patient newPatient(String pid) {
Patient obj = null;
obj = (Patient) context.getBean("Patient");
obj.setPid(pid);
System.out.println("newPatient obj.getClass = " + obj.getClass());
return obj;
}
The println above prints "newPatient obj.getClass = class $Proxy43"
Now an excerpt from the stack trace:
Caused by: org.apache.cxf.interceptor.Fault: $Proxy43
at org.apache.cxf.service.invoker.AbstractInvoker.cre ateFault(AbstractInvoker.java:148)
at org.apache.cxf.service.invoker.AbstractInvoker.inv oke(AbstractInvoker.java:114)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvo ker.java:130)
at com.emc.cto.cxf.jaxrs.XJAXRSInvoker.invoke(XJAXRSI nvoker.java:15)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvo ker.java:82)
at org.apache.cxf.interceptor.ServiceInvokerIntercept or$1.run(ServiceInvokerInterceptor.java:58)
at java.util.concurrent.Executors$RunnableAdapter.cal l(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unkn own Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at org.apache.cxf.workqueue.SynchronousExecutor.execu te(SynchronousExecutor.java:37)
at org.apache.cxf.interceptor.ServiceInvokerIntercept or.handleMessage(ServiceInvokerInterceptor.java:98 )
at org.apache.cxf.phase.PhaseInterceptorChain.doInter cept(PhaseInterceptorChain.java:236)
... 47 more
Caused by: java.lang.ClassCastException: $Proxy43
at com.emc.cto.healthcare.impl.PatientsImpl.getPatien tByID(PatientsImpl.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.aop.support.AopUtils.invokeJoi npointUsingReflection(AopUtils.java:310)
at org.springframework.aop.framework.ReflectiveMethod Invocation.invokeJoinpoint(ReflectiveMethodInvocat ion.java:182)
at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :149)
at org.springframework.security.intercept.method.aopa lliance.MethodSecurityInterceptor.invoke(MethodSec urityInterceptor.java:66)
at org.springframework.aop.framework.ReflectiveMethod Invocation.proceed(ReflectiveMethodInvocation.java :171)
at org.springframework.aop.framework.JdkDynamicAopPro xy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy38.getPatientByID(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Nativ e Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknow n Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Un known Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.cxf.service.invoker.AbstractInvoker.per formInvocation(AbstractInvoker.java:166)
at org.apache.cxf.service.invoker.AbstractInvoker.inv oke(AbstractInvoker.java:82)
... 57 more