Announcement Announcement Module
Collapse
No announcement yet.
Using AOP to register custom property editors -- how? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using AOP to register custom property editors -- how?

    Hi everyone

    If I didn't miss something, a custom property editors' scope is limited to the beans xml file. Which means I can register a CustomDateEditor but it won't convert input data from a web request. To get the editor working there, I'd have to override initBinder from BaseCommandController and register the editor in there.
    Now I don't like the idea of registering an editor by hand in my BaseFormController or any Controller extending that class. I'd rather do this in a central place, the beans xml file.

    So I tried to register the editor in a way similar to the CustomEditorConfigurer with a map which maps class name and editor for that class. I switched over to the DefaultAdvisorAutoProxyCreator. My current config looks like this:

    Code:
    	<bean class="org.springframework.aop.support.DefaultPointcutAdvisor">
    		<property name="pointcut" ref="initBinderPointcut"/>
    		<property name="advice"   ref="initBinderAdvice"/>
    	</bean>
    
    	<bean id="initBinderPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
    		<property name="mappedName" value="initBinder"/>
    	</bean>
    
    	<bean id="initBinderAdvice" class="net.swisstech.treffpunkt.aop.advice.InitBinderAdvice">
    		<property name="propertyEditors">
    			<map>
    				<entry key="java.util.Date" value-ref="customDateEditor"/>
    			</map>
    		</property>
    	</bean>
    
    	<bean id="customDateEditor" class="org.springframework.beans.propertyeditors.CustomDateEditor">
    		<constructor-arg index="0">
    			<bean class="java.text.SimpleDateFormat">
    				<constructor-arg value="yyyy-MM-dd HH&#58;mm"/>
    			</bean>
    		</constructor-arg>
    		<constructor-arg index="1" value="false"/>
    	</bean>
    Code:
    package net.swisstech.treffpunkt.aop.advice;
    
    import java.beans.PropertyEditor;
    import java.util.Iterator;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import org.aopalliance.intercept.MethodInterceptor;
    import org.aopalliance.intercept.MethodInvocation;
    import org.apache.log4j.Logger;
    import org.springframework.web.bind.ServletRequestDataBinder;
    
    public class InitBinderAdvice implements MethodInterceptor &#123;
    	
    	Logger LOGGER = Logger.getLogger&#40;InitBinderAdvice.class&#41;;
    
    	private Map<String, PropertyEditor> propertyEditors;
    	public Map<String, PropertyEditor> getPropertyEditors&#40;&#41; &#123; return propertyEditors; &#125;
    	public void setPropertyEditors&#40;Map<String, PropertyEditor> propertyEditors&#41; &#123; this.propertyEditors = propertyEditors; &#125;
    
    	public Object invoke&#40;MethodInvocation mi&#41; throws Throwable &#123;
    
    		LOGGER.debug&#40;"Handling method invocation for '" + mi.getMethod&#40;&#41;.getDeclaringClass&#40;&#41;.getName&#40;&#41; + "." + mi.getMethod&#40;&#41;.getName&#40;&#41; + "'"&#41;;
    		
    		ServletRequestDataBinder binder = &#40;ServletRequestDataBinder&#41; mi.getArguments&#40;&#41;&#91;1&#93;;
    		
    		Iterator<Entry<String, PropertyEditor>> peIter = getPropertyEditors&#40;&#41;.entrySet&#40;&#41;.iterator&#40;&#41;;
    		while &#40;peIter.hasNext&#40;&#41;&#41; &#123;
    			Entry<String, PropertyEditor> entry = peIter.next&#40;&#41;;
    			String targetClassName = entry.getKey&#40;&#41;;
    			PropertyEditor customEditor = entry.getValue&#40;&#41;;
    			LOGGER.debug&#40;"Registering Property Editor of type '" + customEditor.getClass&#40;&#41;.getName&#40;&#41; + "' for type '" + targetClassName + "'"&#41;;
    			binder.registerCustomEditor&#40;Class.forName&#40;targetClassName&#41;, customEditor&#41;;
    		&#125;
    		
    		return mi.proceed&#40;&#41;;
    	&#125;
    &#125;
    I also tried JdkRegexpMethodPointcut and used org.springframework.web.servlet.mvc.BaseCommandCon troller as pattern there.

    Whatever I tried, my interceptor was not called. From looking at DefaultAdvisorAutoProxyCreator and AbstractAdvisorAutoProxy and AopUtils.canApply(Pointcut pc, Class targetClass) I now know it would work if the method BaseCommandController.initBinder were public.

    Also, using an Introduction doesn't seem to work either since Introductions depend on interfaces and initBinder is not defined in an interface.

    I'm sure this is not a new problem. I hope someone can help me on this problem. Is there a way to declaratively inject and register the property editors into all controllers extending SimpleFormController? Or is there a different approach to this problem I haven't found yet in the docs, forums, etc... ?

    Thanks
    Patrick

  • #2
    I've been searching some more and found some thread google didn't show:

    http://forum.springframework.org/showthread.php?t=11257
    http://forum.springframework.org/showthread.php?t=10458
    http://forum.springframework.org/showthread.php?t=9970

    Especially the second link makes me think I should just subclass SimpleBaseController and live with that. But I still don't like this approach.

    If someone has an idea to make the initial approach working I'd like like to hear it!!
    Last edited by robyn; May 14th, 2006, 06:02 PM.

    Comment


    • #3
      you can write a subclass with a setEditors attribute that takes a map or properties and load that in the initBinder. then you still get to place the config in the xml.

      Comment

      Working...
      X