PDA

View Full Version : Abstract Schema



oliverhutchison
Oct 28th, 2004, 12:41 AM
As part of a project to get a better understanding of how to use CGLIB I've been creating an implementation of Rickard Öberg's "abstract schema" approach to AOP introduction and interception targeted for Spring's AOP subsystem. I've managed to get everything working nicely if I programmatically create my proxies using ProxyFactory however I've run into a small problem with creating proxies using an application context.

With "abstract schema" the target class declares it requires a specific introduction by declaring that it implements a particular interface but then *not* actually implementing any of the interface's methods. For example the following class requires that an implementation for the interfaces Foo and Bar be provided by the AOP system



public abstract class SomeClass
implements Foo,Bar
{
public String someMethod() {..}
}


I would like to be able to configure the introductions for this class in an application context using some config along these lines:



<beans>
<bean id="someClass" class="SomeClass" />

<bean id="autoProxyCreator"
class="...DefaultAdvisorAutoProxyCreator">
</bean>

<bean id="fooImpl" class="FooImpl" />
<bean id="fooIntroduction
class="...DelegatingIntroductionInterceptor">
<constructor-arg><ref local="fooImpl"/</constructor-arg>
</bean>

<bean id="barImpl" class="BarImpl" />
<bean id="barIntroduction
class="...DelegatingIntroductionInterceptor">
<constructor-arg><ref local="BarImpl"/</constructor-arg>
</bean>
</beans>


However as "SomeClass" is abstract the bean factory is unable to instantiate it.

So how do I instantiate this class? My first thought was to use a BeanFactoryPostProcessor that would find the bean definition for the abstract class, generate a new concrete subclass and replace the abstract class with this new subclass.



public void postProcessBeanFactory&#40;
ConfigurableListableBeanFactory beanFactoryToProcess&#41;
throws BeansException &#123;
String&#91;&#93; beanNames = beanFactoryToProcess.getBeanDefinitionNames&#40;&#41;;
for &#40;int i = 0; i < beanNames.length; i++&#41; &#123;
BeanDefinition bd = beanFactoryToProcess
.getBeanDefinition&#40;beanNames&#91;i&#93;&#41;;
Class beanType = beanFactoryToProcess.getType&#40;beanNames&#91;i&#93;&#41;;
if &#40;Modifier.isAbstract&#40;beanType.getModifiers&#40;&#41;&#41;&#41; &#123;
&#40;&#40;AbstractBeanDefinition&#41;bd&#41;.setBeanClass&#40;createCo ntreteClass&#40;beanType&#41;&#41;;
&#125;
&#125;
&#125;

private Class createContreteClass&#40;Class abstractClass&#41; &#123;
...
&#125;


Unfortunately as I am generating the concrete subclass using a CGLIB enhancer I must use the Enhancer.create() method to create the instance so that the callbacks are correctly installed....

What about using my BeanFactoryPostProcessor to install a new InstantiationStrategy into the bean factory? Unfortunately the instantiationStrategy property on AbstractAutowireCapableBeanFactory is protected so I can't access it... As a stop gap measure I've resorted to setting the InstantiationStrategy using reflection.

Does anyone have a suggestion of how I can get around this? My first thought was that setInstantiationStrategy could be made public and moved over to ConfigurableBeanFactory but I assume there are strong reason this was not done when this interface was created.

Thanks,

Ollie

PS. If anyone's interested here's the programmatic configuration for this problem



SomeClass someClassTarget = &#40;SomeClass&#41; new MethodReplaceableSubclassCreator&#40;
SomeClass.class, AbstractMethodMatcher.INSTANCE&#41;
.instantiate&#40;null, null&#41;;
&#40;&#40;MethodReplaceable&#41;someClassTarget&#41;
.setMethodReplacer&#40;CurrentAopProxyMethodReplacer.I NSTANCE&#41;;

ProxyFactory pf = new ProxyFactory&#40;someClassTarget&#41;;
pf.setExposeProxy&#40;true&#41;;
pf.setProxyTargetClass&#40;true&#41;;
pf.addAdvice&#40;new DelegatingIntroductionInterceptor&#40;
new FooImpl&#40;&#41;&#41;&#41;;
pf.addAdvice&#40;new DelegatingIntroductionInterceptor&#40;
new BarImpl&#40;&#41;&#41;&#41;;
SomeClass someClass = &#40;SomeClass&#41;pf.getProxy&#40;&#41;

someClass.foo&#40;&#41;;
...

Rod Johnson
Nov 1st, 2004, 03:01 AM
Oliver,

I've got an almost complete implementation of abstract schema, intended for Spring 1.2, but not in the sandbox yet, as I haven't had time to address all issues.

It might be best if we take this offline--send me a private message and we can compare notes. I would like to see your implementation. In my implementation, the abstract schema subclass is generated by an advice factory, so there don't need to be any changes to the IoC container.

R