BATCH-2002: Initial support for complex conditional replacements
This commit is contained in:
committed by
Michael Minella
parent
65d2df652a
commit
e1f6de38e0
@@ -57,7 +57,6 @@ import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
@@ -74,11 +73,9 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BatchPropertyBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private JsrExpressionParser jsrExpressionParser;
|
||||
private BatchPropertyContext batchPropertyContext;
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
private BeanExpressionContext beanExpressionContext;
|
||||
private BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
|
||||
private Set<Class<? extends Annotation>> requiredAnnotations = new HashSet<Class<? extends Annotation>>();
|
||||
|
||||
public BatchPropertyBeanPostProcessor() {
|
||||
@@ -189,7 +186,7 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor, BeanFa
|
||||
if (batchArtifactProperties.containsKey(propertyKey)) {
|
||||
String propertyValue = (String) batchArtifactProperties.get(propertyKey);
|
||||
|
||||
return (String) expressionResolver.evaluate(propertyValue, beanExpressionContext);
|
||||
return jsrExpressionParser.parseExpression(propertyValue);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -221,8 +218,12 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor, BeanFa
|
||||
"BatchPropertyBeanPostProcessor requires a ConfigurableListableBeanFactory");
|
||||
}
|
||||
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
this.beanExpressionContext = new BeanExpressionContext(this.beanFactory, this.beanFactory.getBean(StepScope.class));
|
||||
ConfigurableListableBeanFactory configurableListableBeanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
|
||||
BeanExpressionContext beanExpressionContext = new BeanExpressionContext(configurableListableBeanFactory,
|
||||
configurableListableBeanFactory.getBean(StepScope.class));
|
||||
|
||||
this.jsrExpressionParser = new JsrExpressionParser(new StandardBeanExpressionResolver(), beanExpressionContext);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2013 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 org.springframework.batch.core.jsr.configuration.support;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Support class for parsing JSR-352 expressions. The JSR-352 expression syntax, for
|
||||
* example conditional/elvis statements need to be massaged a bit to work as SPeL expressions.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsrExpressionParser {
|
||||
public static final String QUOTE = "'";
|
||||
private static final String ELVIS_RHS = ":";
|
||||
private static final String ELVIS_LHS = "\\?";
|
||||
private static final String ELVIS_OPERATOR = "?:";
|
||||
private static final String EXPRESSION_SUFFIX = "}";
|
||||
private static final String EXPRESSION_PREFIX = "#{";
|
||||
private static final String DEFAULT_VALUE_SEPARATOR = ";";
|
||||
private static final Pattern CONDITIONAL_EXPRESSION = Pattern.compile("(#\\{\\w[^;]+)");
|
||||
|
||||
private BeanExpressionContext beanExpressionContext;
|
||||
private BeanExpressionResolver beanExpressionResolver;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a new instances of this expression parser with the provided expression resolver and context to evaluate
|
||||
* against.
|
||||
* </p>
|
||||
*
|
||||
* @param beanExpressionResolver the expression resolver to use when resolving expressions
|
||||
* @param beanExpressionContext the expression context to resolve expressions against
|
||||
*/
|
||||
public JsrExpressionParser(BeanExpressionResolver beanExpressionResolver, BeanExpressionContext beanExpressionContext) {
|
||||
this.beanExpressionContext = beanExpressionContext;
|
||||
this.beanExpressionResolver = beanExpressionResolver;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Parses the provided expression, applying any transformations needed to evaluate as a SPeL expression.
|
||||
* </p>
|
||||
*
|
||||
* @param expression the expression to parse and transform
|
||||
* @return a JSR-352 transformed expression that can be evaluated by a SPeL parser
|
||||
*/
|
||||
public String parseExpression(String expression) {
|
||||
if (StringUtils.countOccurrencesOf(expression, ELVIS_OPERATOR) > 0) {
|
||||
String expressionToParse = expression;
|
||||
|
||||
Matcher conditionalExpressionMatcher = CONDITIONAL_EXPRESSION.matcher(expressionToParse);
|
||||
|
||||
while (conditionalExpressionMatcher.find()) {
|
||||
String conditionalExpression = conditionalExpressionMatcher.group(1);
|
||||
|
||||
String value = conditionalExpression.split(ELVIS_LHS)[0];
|
||||
String defaultValue = conditionalExpression.split(ELVIS_RHS)[1];
|
||||
|
||||
StringBuilder parsedExpression = new StringBuilder()
|
||||
.append(EXPRESSION_PREFIX)
|
||||
.append((String) beanExpressionResolver.evaluate(value, beanExpressionContext))
|
||||
.append(ELVIS_OPERATOR)
|
||||
.append(QUOTE)
|
||||
.append((String) beanExpressionResolver.evaluate(defaultValue, beanExpressionContext))
|
||||
.append(QUOTE)
|
||||
.append(EXPRESSION_SUFFIX);
|
||||
|
||||
expressionToParse = expressionToParse.replace(conditionalExpression, parsedExpression);
|
||||
}
|
||||
|
||||
expressionToParse = expressionToParse.replace(DEFAULT_VALUE_SEPARATOR, "");
|
||||
|
||||
return (String) beanExpressionResolver.evaluate(expressionToParse, beanExpressionContext);
|
||||
}
|
||||
|
||||
return (String) beanExpressionResolver.evaluate(expression, beanExpressionContext);
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,10 @@ public class JobPropertySubstitutionTests {
|
||||
@Test
|
||||
public void testPropertySubstitutionSimple() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job,
|
||||
new JobParametersBuilder().addString("testParam", "testParamValue").toJobParameters());
|
||||
new JobParametersBuilder()
|
||||
.addString("testParam", "testParamValue")
|
||||
.addString("file.name.junit", "myfile2")
|
||||
.toJobParameters());
|
||||
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
|
||||
}
|
||||
|
||||
@@ -122,9 +125,19 @@ public class JobPropertySubstitutionTests {
|
||||
@BatchProperty
|
||||
String processorProperty1;
|
||||
|
||||
@Inject
|
||||
@BatchProperty
|
||||
String processorProperty2;
|
||||
|
||||
@Inject
|
||||
@BatchProperty
|
||||
String processorProperty3;
|
||||
|
||||
@Override
|
||||
public Object processItem(Object item) throws Exception {
|
||||
assertEquals("testParamValue", processorProperty1);
|
||||
assertEquals("myfile1.txt", processorProperty2);
|
||||
assertEquals("/myfile2.txt", processorProperty3);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<processor ref="testProcessor">
|
||||
<properties>
|
||||
<property name="processorProperty1" value="#{jobParameters['testParam']}"/>
|
||||
<property name="processorProperty2" value="#{jobParameters['unresolving.prop']}?:myfile1.txt;"/>
|
||||
<property name="processorProperty3" value="#{jobParameters['unresolving.prop']}?:#{systemProperties['file.separator']};#{jobParameters['infile.name']}?:#{jobParameters['file.name.junit']};.txt" />
|
||||
</properties>
|
||||
</processor>
|
||||
<writer ref="testWriter">
|
||||
|
||||
Reference in New Issue
Block a user