Search code examples
javaspringspring-el

Spring expression language extension in xml files


I want to extend and register my own function as detailed here:

http://static.springsource.org/spring/docs/3.0.x/reference/expressions.html see section: 6.5.11 Functions.

However, I wish to use this expression from a spring xml file and not in code as presented in the page.

How do I get a reference to the "StandardEvaluationContext" object used by spring while parsing my xml file? without having that spring can't find my registered function.

Thanks,

Yair


Solution

  • So, the solution I found is:

    public class DBCustomExpressionRegistration implements BeanFactoryAware {
    
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        if (beanFactory instanceof ConfigurableBeanFactory) {
            ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
            cbf.setBeanExpressionResolver(new StandardBeanExpressionResolver(){
                @Override
                protected void customizeEvaluationContext(
                        StandardEvaluationContext evalContext) {
                    evalContext.addMethodResolver(new InfraReflectiveMethodResolver());
                }
            });
        }
    
    }
    
    public String getDbConfig(String param){
        Configuration configuration  = ConfigurationFactory.getConfiguration();             
        @SuppressWarnings("unchecked")
        Iterator<String> keys = configuration.getKeys();
        while(keys.hasNext()){
            String key = keys.next();
            String value = configuration.getString(key);
            String tempKey = "database.*."+param;
            if (key.matches(tempKey)){
                return value;
            }
        }
    
        throw new IllegalArgumentException("could find pattern for: database.<string>" + param);
    }
    
    
    private class InfraReflectiveMethodResolver extends ReflectiveMethodResolver {
    
        @Override
        public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name, List<TypeDescriptor> argumentTypes) throws AccessException {
    
            if ("getDbConfig".equals(name)){
                return new DBMethodExecutor();
            }
            return super.resolve(context, targetObject, name, argumentTypes);
        }
    
    }
    
    private class DBMethodExecutor implements MethodExecutor {
    
        @Override
        public TypedValue execute(EvaluationContext context, Object target, Object... arguments) throws AccessException {
    
            try {
                return new TypedValue(getDbConfig((String)arguments[0]), new TypeDescriptor(new MethodParameter(DBCustomExpressionRegistration.class.getDeclaredMethod("getDbConfig",new Class[] { String.class }), -1)));
            }
            catch (Exception ex) {
                throw new AccessException("Problem invoking method: getDbConfig" , ex);
            }
    
        }
    
    }
    

    }

    you use from the spring file like this:

    <bean id="dbCustomExpressionRegistration" class="com.db.util.DBCustomExpressionRegistration"/>
    

    in a bean that needs to use the getDbConfig function:

    <property name="user" value="#{getDbConfig('username')}" />