Search code examples
javaspringrmi

How to wire proxy objects in spring?


I am using proxy beans with property-selectable transport protocol. My problem is that bean properties cannot be converted, but I really don't know why. This is the situation:

My property: service.protocol=rmi

<!-- This is the 'multiplexing' factory bean (using this because properties
cannot be used in bean names and aliases -->

   <bean name="dbFormGenWindowComponent" 
  class="org.springframework.beans.factory.config.BeanReferenceFactoryBean">
  <property name="targetBeanName" value="dbFormGenWindowComponent-${service.protocol}invoker" />
 </bean>

<!-- Here are the service invoker beans with two protocols: -->

  <bean name="dbFormGenWindowComponent-rmiinvoker" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
 <property name="serviceUrl" value="${ringwindow.serviceURL.rmi}/${ringwindow.service.name}-dbFormGenWindowComponent"/>
 <property name="serviceInterface" value="foo.bar.service.formgen.windows.FormGenWindowComponent" />
 <property name="lookupStubOnStartup" value="false"/>
  </bean>

The exception on startup is:

org.springframework.beans.TypeMismatchException: Failed to convert property value of type [$Proxy541] to required type [foo.bar.service.formgen.windows.FormGenWindowComponent] for property 'formGenWindowComponent'; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [$Proxy541] to required type [foo.bar.service.formgen.windows.FormGenWindowComponent] for property 'formGenWindowComponent': no matching editors or conversion strategy found

I think nested factory beans should work fine. Do you have any idea how to get this work?


Solution

  • This usually happens when you have defined your injection point types to be concrete classes, rather than interfaces, but you are proxying based on interface. For example:

    public interface Foo { .. }
    public class FooImpl { .. } // this is declared as bean
    
    public class Bar {
        private FooImpl foo; // this fails
        private Foo foo; // correct way
    }
    

    In the case of factory beans this may be due to the factory bean's return type being defined as a concrete class. If you can't change anything in the classes, you can configure spring to use cglib-proxying, by:

    • <aop:scoped-proxy> - inside a bean definition - this will configure proxies of the bean
    • <aop:aspectj-autoproxy proxy-target-class="true"> - changes this globally