All Downloads are FREE. Search and download functionalities are using the official Maven repository.

leap.spring.boot.spel.SpringExpressionFactory Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package leap.spring.boot.spel;

import leap.core.annotation.Inject;
import leap.core.spring.ExpressionFactory;
import leap.core.variable.VariableEnvironment;
import leap.lang.annotation.Init;
import leap.lang.expression.Expression;
import leap.lang.logging.Log;
import leap.lang.logging.LogFactory;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.*;
import org.springframework.expression.spel.SpelCompilerMode;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.util.HashMap;
import java.util.Map;

public class SpringExpressionFactory implements ExpressionFactory {

    private static final Log log = LogFactory.get(SpringExpressionFactory.class);

    @Inject
    protected VariableEnvironment env;

    @Inject
    protected BeanFactory beanFactory;

    @Inject
    protected SpringExpressionInitializer[] initializers;

    protected EnvPropertyAccessor       envProperty;
    protected SpelExpressionParser      spelParser;
    protected StandardEvaluationContext evalContext;
    protected Map       globalVariables = new HashMap<>();

    @Init
    public void init() {
        if (null == beanFactory) {
            log.error("Spring context not found, can't use spring expression factory");
            return;
        }

        SpelParserConfiguration c = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, this.getClass().getClassLoader());
        spelParser = new SpelExpressionParser(c);

        evalContext = new StandardEvaluationContext();
        envProperty = new EnvPropertyAccessor(env);
        globalVariables.put("env", envProperty);

        evalContext.getPropertyAccessors().add(0, envProperty);
        evalContext.getPropertyAccessors().add(0, new MapPropertyAccessor());
        evalContext.setBeanResolver(new BeanFactoryResolver(beanFactory));

        for(SpringExpressionInitializer initializer : initializers) {
            initializer.initExpressionContext(evalContext, globalVariables);
        }
    }

    public Expression createExpression(String expr) {
        return new SpringExpression(createSpringExpression(expr), evalContext, globalVariables);
    }

    public org.springframework.expression.Expression createSpringExpression(String expr) {
        boolean template;

        int index = expr.indexOf("#{");
        if (index < 0) {
            template = false;
        } else if (index > 0) {
            template = true;
        } else if (index == 0 && expr.endsWith("}") && expr.indexOf("#{", 2) < 0) {
            template = false;
            expr = expr.substring(2, expr.length() - 1);
        } else {
            template = true;
        }

        return template ?
                spelParser.parseExpression(expr, ParserContext.TEMPLATE_EXPRESSION) :
                spelParser.parseExpression(expr);
    }

    protected static class EnvPropertyAccessor implements PropertyAccessor {
        private static final Class[] TARGET_CLASSES = new Class[]{EnvPropertyAccessor.class};

        private final VariableEnvironment env;

        public EnvPropertyAccessor(VariableEnvironment env) {
            this.env = env;
        }

        @Override
        public Class[] getSpecificTargetClasses() {
            return TARGET_CLASSES;
        }

        @Override
        public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
            return this == target;
        }

        @Override
        public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
            Object value = env.resolveVariable(name);
            if (null == value && !env.checkVariableExists(name)) {
                throw new AccessException("Environment variable 'env." + name + "' not exists!");
            }
            return null == value ? TypedValue.NULL : new TypedValue(value);
        }

        @Override
        public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
            return false;
        }

        @Override
        public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
            throw new AccessException("Can't write env variable");
        }
    }

    protected static class MapPropertyAccessor implements PropertyAccessor {

        private static final Class[] TARGET_CLASSES = new Class[]{Map.class};

        @Override
        public Class[] getSpecificTargetClasses() {
            return TARGET_CLASSES;
        }

        @Override
        public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
            return target instanceof Map;
        }

        @Override
        public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
            Map map = (Map) target;

            Object value;
            if (map.containsKey(name)) {
                value = map.get(name);
            } else {
                value = getIgnoreCase(map, name);
            }
            return null == value ? TypedValue.NULL : new TypedValue(value);
        }

        @Override
        public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
            return target instanceof Map;
        }

        @Override
        public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
            ((Map) target).put(name, newValue);
        }

        protected Object getIgnoreCase(Map map, String name) throws AccessException {
            for (Map.Entry entry : map.entrySet()) {
                Object key = entry.getKey();
                if (key instanceof String && name.equalsIgnoreCase((String) key)) {
                    return entry.getValue();
                }
            }
            throw new AccessException("The variable '" + name + "' not found");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy