From: Kai Moritz Date: Mon, 27 Feb 2017 17:47:26 +0000 (+0100) Subject: Ported app to Thymeleaf 3.0.x X-Git-Url: https://juplo.de/gitweb/?p=juplo-dialect;a=commitdiff_plain;h=700dc21ccb3b89bf961e908ccdefb8525791bd22 Ported app to Thymeleaf 3.0.x * Proted the dialect to the new Thymeleaf-API * Removed modified configuration of the default-template-resolver, because it is not needed any more: Thymeleaf 3.0.x resolves its templates via Spring's resource-chain by default. --- diff --git a/pom.xml b/pom.xml index 896f59a..8a5be94 100644 --- a/pom.xml +++ b/pom.xml @@ -41,6 +41,7 @@ UTF-8 1.8 1.0.0 + 3.0.3.RELEASE @@ -78,7 +79,7 @@ org.springframework.boot spring-boot-dependencies - 1.3.6.RELEASE + 1.5.1.RELEASE pom import diff --git a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java deleted file mode 100644 index aac37a6..0000000 --- a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java +++ /dev/null @@ -1,314 +0,0 @@ -package de.juplo.thymeleaf; - - -import com.fasterxml.jackson.core.JsonFactory; -import de.juplo.jackson.SimpleMapper; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.thymeleaf.Arguments; -import org.thymeleaf.Configuration; -import org.thymeleaf.TemplateProcessingParameters; -import org.thymeleaf.context.IContext; -import org.thymeleaf.context.VariablesMap; -import org.thymeleaf.dom.Element; -import org.thymeleaf.dom.Node; -import org.thymeleaf.exceptions.TemplateProcessingException; -import org.thymeleaf.processor.ProcessorResult; -import org.thymeleaf.processor.attr.AbstractAttrProcessor; -import org.thymeleaf.resourceresolver.IResourceResolver; -import org.thymeleaf.standard.expression.IStandardExpression; -import org.thymeleaf.standard.expression.IStandardExpressionParser; -import org.thymeleaf.standard.expression.StandardExpressions; -import org.thymeleaf.templateresolver.ITemplateResolver; -import org.thymeleaf.templateresolver.TemplateResolution; - - - -/** - * Retrievs and parses JSON-data and imports the parsed variables as node-local - * variables. - * @author Kai Moritz - */ -public class ImportVariablesAttrProcessor extends AbstractAttrProcessor -{ - private static final Logger LOG = - LoggerFactory.getLogger(ImportVariablesAttrProcessor.class); - private static final JsonFactory FACTORY = new JsonFactory(); - private static final String PROPERTY_NAME = - ImportVariablesAttrProcessor.class.getCanonicalName() + "_VARIABLES"; - - public static final Pattern PATTERN = - Pattern.compile( - "^\\s*(?:(?:(merge)|replace):)?\\s*(?:(\\{.*\\})|(.*))\\s*$", - Pattern.DOTALL | Pattern.CASE_INSENSITIVE - ); - public static final int ATTR_PRECEDENCE = 200; - - - public ImportVariablesAttrProcessor() - { - super("variables"); - } - - - @Override - public final ProcessorResult processAttribute( - final Arguments arguments, - final Element element, - final String name - ) - { - Configuration config = arguments.getConfiguration(); - - Configuration configuration = arguments.getConfiguration(); - - String parameter = element.getAttributeValue(name); - try - { - IStandardExpressionParser parser = - StandardExpressions.getExpressionParser(configuration); - IStandardExpression expression = - parser.parseExpression(configuration, arguments, parameter); - parameter = (String)expression.execute(configuration, arguments); - } - catch (TemplateProcessingException e) { } - - if (parameter != null && !parameter.trim().isEmpty()) - { - LOG.info("ignoring empty parameter"); - return ProcessorResult.OK; - } - - Iterator> it = null; - - Matcher matcher = PATTERN.matcher(parameter); - boolean merge = false; - String json = null; - String resource = parameter; - - if (matcher.matches()) - { - merge = matcher.group(1) != null; - json = matcher.group(2); - resource = matcher.group(3); - } - - if (json != null) - { - LOG.info("parsing parameter as JSON"); - LOG.debug("parameter: {}", json); - try - { - it = SimpleMapper.getObjectIterator(FACTORY.createParser(json)); - } - catch (IOException e) - { - LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage()); - throw new RuntimeException(e); - } - } - else - { - LOG.info("retriving {} as JSON-template", resource); - TemplateProcessingParameters params = - new TemplateProcessingParameters( - config, - resource, - new IContext() // << We will not execute the template, hence we need no context - { - @Override - public VariablesMap getVariables() - { - return new VariablesMap<>(); - } - - @Override - public Locale getLocale() - { - return Locale.getDefault(); - } - - @Override - public void addContextExecutionInfo(String templateName) - { - } - }); - - for (ITemplateResolver t_resolver : config.getTemplateResolvers()) - { - TemplateResolution resolution = t_resolver.resolveTemplate(params); - if (resolution == null) - continue; - if (!"JSON".equals(resolution.getTemplateMode())) - continue; - IResourceResolver r_resolver = resolution.getResourceResolver(); - InputStream is = - r_resolver.getResourceAsStream(params, resolution.getResourceName()); - if (is == null) - continue; - - try - { - it = SimpleMapper.getObjectIterator(FACTORY.createParser(is)); - break; - } - catch (IOException | IllegalArgumentException e) - { - LOG.error("cannot retreive {} as JSON: {}", parameter, e.getMessage()); - throw new RuntimeException(e); - } - } - - if (it == null) - { - LOG.error("cannot resolve {} as JSON (not found)!", parameter); - throw new RuntimeException("Template not found: " + parameter); - } - } - - try - { - Map variables = getVariables(element); - if (merge) - { - while(it.hasNext()) - { - Entry variable = it.next(); - String key = variable.getKey(); - Object value = variable.getValue(); - Object existing = variables.get(key); - if (existing != null) - { - if (value instanceof String) - { - if (!(existing instanceof String)) - { - LOG.error( - "cannot merge variable {} of type {} with a string", - key, - existing.getClass() - ); - throw new RuntimeException( - "Type-Missmatch for variable " + key - ); - } - - String string = ((String)existing).concat((String) value); - LOG.info("appending variable to string {}", key); - element.setNodeLocalVariable(key, string); - } - else if (value instanceof Map) - { - if (!(existing instanceof Map)) - { - LOG.error( - "cannot merge variable {} of type {} with a map", - key, - existing.getClass() - ); - throw new RuntimeException( - "Type-Missmatch for variable " + key - ); - } - - Map map = ((Map)existing); - map.putAll((Map) value); - LOG.info("merging variable with map {}", key); - element.setNodeLocalVariable(key, map); - } - else if (value instanceof List) - { - if (!(existing instanceof List)) - { - LOG.error( - "cannot merge variable {} of type {} with a list", - key, - existing.getClass() - ); - throw new RuntimeException( - "Type-Missmatch for variable " + key - ); - } - - List list = ((List)existing); - list.addAll((List) value); - LOG.info("appending contents of variable to list {}", key); - element.setNodeLocalVariable(key, list); - } - else - { - LOG.error( - "variable {} is of unexpected type {}", key, value.getClass() - ); - throw new RuntimeException( - "Found variable of unexpected type: " + key - ); - } - } - else - { - LOG.info("adding new variable {}", key); - element.setNodeLocalVariable(key, value); - } - } - } - else - while(it.hasNext()) - { - Entry variable = it.next(); - String key = variable.getKey(); - Object value = variable.getValue(); - LOG.info("adding variable {}", key); - variables.put(key, value); - element.setNodeLocalVariable(key, value); - } - } - catch (IllegalArgumentException e) - { - LOG.error("cannot parse {} as JSON: {}", parameter, e.getMessage()); - throw new RuntimeException(e); - } - - element.removeAttribute(name); - - return ProcessorResult.OK; - } - - - Map getVariables(Node node) - { - Node parent = node; - do - { - Map variables = - (Map)parent.getNodeProperty(PROPERTY_NAME); - - if (variables != null) - return variables; - - parent = parent.getParent(); - } - while (parent != null); - - Map variables = new HashMap<>(); - node.setNodeProperty(PROPERTY_NAME, variables); - return variables; - } - - - @Override - public int getPrecedence() - { - return ATTR_PRECEDENCE; - } -} diff --git a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttributeProcessor.java b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttributeProcessor.java new file mode 100644 index 0000000..4190767 --- /dev/null +++ b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttributeProcessor.java @@ -0,0 +1,382 @@ +package de.juplo.thymeleaf; + + +import com.fasterxml.jackson.core.JsonFactory; +import de.juplo.jackson.SimpleMapper; +import java.io.IOException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.thymeleaf.Arguments; +import org.thymeleaf.Configuration; +import org.thymeleaf.TemplateProcessingParameters; +import org.thymeleaf.context.IContext; +import org.thymeleaf.context.VariablesMap; +import org.thymeleaf.dom.Element; +import org.thymeleaf.dom.Node; +import org.thymeleaf.IEngineConfiguration; +import org.thymeleaf.context.ITemplateContext; +import org.thymeleaf.engine.AttributeName; +import org.thymeleaf.engine.EngineEventUtils; +import org.thymeleaf.exceptions.TemplateProcessingException; +import org.thymeleaf.model.IProcessableElementTag; +import org.thymeleaf.processor.element.AbstractAttributeTagProcessor; +import org.thymeleaf.processor.element.IElementTagStructureHandler; +import org.thymeleaf.standard.expression.FragmentExpression; +import org.thymeleaf.standard.expression.FragmentExpression.ExecutedFragmentExpression; +import org.thymeleaf.standard.expression.IStandardExpression; +import org.thymeleaf.standard.expression.NoOpToken; +import org.thymeleaf.standard.expression.StandardExpressionExecutionContext; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ITemplateResolver; +import org.thymeleaf.templateresolver.TemplateResolution; + + + +/** + * Retrievs and parses JSON-data and imports the parsed variables as node-local + * variables. + * @author Kai Moritz + */ +public class ImportVariablesAttributeProcessor extends AbstractAttributeTagProcessor +{ + private static final Logger LOG = + LoggerFactory.getLogger(ImportVariablesAttributeProcessor.class); + private static final JsonFactory FACTORY = new JsonFactory(); + private static final String PROPERTY_NAME = + ImportVariablesAttributeProcessor.class.getCanonicalName() + "_VARIABLES"; + + public static final Pattern PATTERN = + Pattern.compile( + "^\\s*(?:(?:(merge)|replace):)?\\s*(?:(\\{.*\\})|(.*))\\s*$", + Pattern.DOTALL | Pattern.CASE_INSENSITIVE + ); + + public static final String ATTR_NAME = "variables"; + public static final int ATTR_PRECEDENCE = 200; + + + public ImportVariablesAttributeProcessor(String prefix) + { + super(TemplateMode.HTML, prefix, null, false, ATTR_NAME, true, ATTR_PRECEDENCE, true); + } + + + @Override + protected void doProcess( + final ITemplateContext context, + final IProcessableElementTag element, + final AttributeName name, + final String attribute, + final IElementTagStructureHandler handler + ) + { + if (attribute == null) + return; + + String location; + try + { + final Object result; + final IStandardExpression expression = + EngineEventUtils.computeAttributeExpression( + context, + element, + name, + attribute + ); + + if (expression != null && expression instanceof FragmentExpression) + { + final ExecutedFragmentExpression executedFragmentExpression = + FragmentExpression.createExecutedFragmentExpression( + context, + (FragmentExpression) expression, + StandardExpressionExecutionContext.NORMAL + ); + result = + FragmentExpression.resolveExecutedFragmentExpression( + context, + executedFragmentExpression, + true + ); + } + else + { + result = expression.execute(context); + } + + // If the result of this expression is NO-OP, there is nothing to execute + if (result == NoOpToken.VALUE) + { + handler.removeAttribute(name); + return; + } + + location = result.toString(); + } + catch (final TemplateProcessingException e) + { + location = attribute; + } + + + Iterator> it = null; + + Matcher matcher = PATTERN.matcher(location); + boolean merge = false; + String json = null; + + if (matcher.matches()) + { + merge = matcher.group(1) != null; + json = matcher.group(2); + location = matcher.group(3); + } + + if (json != null) + { + LOG.info("parsing parameter as JSON"); + LOG.debug("parameter: {}", json); + try + { + it = SimpleMapper.getObjectIterator(FACTORY.createParser(json)); + } + catch (IOException e) + { + LOG.error("cannot parse parameter as JSON: {}", json, e.getMessage()); + return; + } + } + else + { + LOG.info("retriving {} as Spring-resource", location); + IEngineConfiguration config = context.getConfiguration(); + for (ITemplateResolver resolver : config.getTemplateResolvers()) + { + TemplateResolution resolution = + resolver.resolveTemplate( + config, + context.getTemplateData().getTemplate(), + location, + null + ); + if (resolution != null) + { + try + { + it = SimpleMapper.getObjectIterator(FACTORY.createParser(resolution.getTemplateResource().reader())); + break; + } + catch (IOException e) {} + } + } + + if (it == null) + { + LOG.error("cannot resolve {} as JSON (not found)!", location); + return; + } + } + + try + { + Map variables = getVariables(context); + if (merge) + { + while(it.hasNext()) + { + Entry variable = it.next(); + String key = variable.getKey(); + Object value = variable.getValue(); + Object existing = context.getVariable(key); + if (existing != null) + { + if (value instanceof String) + { + if (!(existing instanceof String)) + { + LOG.error( + "cannot merge variable {} of type {} with a string", + key, + existing.getClass() + ); + throw new RuntimeException( + "Type-Missmatch for variable " + key + ); + } + + String string = ((String)existing).concat((String) value); + LOG.info("appending variable to string {}", key); + handler.setLocalVariable(key, string); + } + else if (value instanceof Map) + { + if (!(existing instanceof Map)) + { + LOG.error( + "cannot merge variable {} of type {} with a map", + key, + existing.getClass() + ); + throw new RuntimeException( + "Type-Missmatch for variable " + key + ); + } + + Map map = ((Map)existing); + map.putAll((Map) value); + LOG.info("merging variable with map {}", key); + handler.setLocalVariable(key, map); + } + else if (value instanceof List) + { + if (!(existing instanceof List)) + { + LOG.error( + "cannot merge variable {} of type {} with a list", + key, + existing.getClass() + ); + throw new RuntimeException( + "Type-Missmatch for variable " + key + ); + } + + List list = ((List)existing); + list.addAll((List) value); + LOG.info("appending contents of variable to list {}", key); + handler.setLocalVariable(key, list); + } + else + { + LOG.error( + "variable {} is of unexpected type {}", key, value.getClass() + ); + throw new RuntimeException( + "Found variable of unexpected type: " + key + ); + } + } + else + { + LOG.info("adding new variable {}", key); + handler.setLocalVariable(key, value); + } + } + } + else + while(it.hasNext()) + { + Entry variable = it.next(); + String key = variable.getKey(); + Object value = variable.getValue(); + LOG.info("adding variable {}", key); + variables.put(key, value); + handler.setLocalVariable(key, value); + } + } + catch (IllegalArgumentException e) + { + LOG.error("cannot parse {} as JSON: {}", location, e.getMessage()); + throw new RuntimeException(e); + } + + handler.removeAttribute(name); + } + + + Map getVariables(ITemplateContext context) + { + Map variables = new HashMap<>(); + return variables; + } + + + static Object convert(JsonParser parser) throws IOException + { + JsonToken token = parser.getCurrentToken(); + if (token == null) + fail(parser, "unexpected EOF"); + + switch (token) + { + case VALUE_STRING: return parser.getText(); + case VALUE_NUMBER_INT: return parser.getIntValue(); + case VALUE_NUMBER_FLOAT: return parser.getDoubleValue(); + case START_OBJECT: return convertObject(parser); + case START_ARRAY: return convertArray(parser); + case VALUE_TRUE: return Boolean.TRUE; + case VALUE_FALSE: return Boolean.FALSE; + case VALUE_NULL: return null; + } + + fail(parser, "unexpected token " + token.toString()); + return null; // << Will never be reached, because fail always throws an exception + } + + static Map convertObject(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + + Map map = new LinkedHashMap<>(); + + while (!JsonToken.END_OBJECT.equals(token)) + { + if (!JsonToken.FIELD_NAME.equals(token)) + fail(parser, "expected a field-name"); + + String name = parser.getText(); + parser.nextToken(); + Object value = convert(parser); + map.put(name, value); + + token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + } + + return map; + } + + static List convertArray(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + + List list = new LinkedList<>(); + + while (!JsonToken.END_ARRAY.equals(token)) + { + list.add(convert(parser)); + + token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + } + + return list; + } + + static void fail(JsonParser parser, String message) + { + JsonLocation location = parser.getCurrentLocation(); + LOG.error( + "{} at char-offset {} (line {}, column {})", + message, + location.getCharOffset(), + location.getLineNr(), + location.getColumnNr() + ); + throw new RuntimeException("Cannot parse JSON: " + message); + } +} diff --git a/src/main/java/de/juplo/thymeleaf/JuploDialect.java b/src/main/java/de/juplo/thymeleaf/JuploDialect.java index e4d2d5b..f6e2e96 100644 --- a/src/main/java/de/juplo/thymeleaf/JuploDialect.java +++ b/src/main/java/de/juplo/thymeleaf/JuploDialect.java @@ -3,7 +3,7 @@ package de.juplo.thymeleaf; import java.util.HashSet; import java.util.Set; -import org.thymeleaf.dialect.AbstractDialect; +import org.thymeleaf.dialect.IProcessorDialect; import org.thymeleaf.processor.IProcessor; @@ -11,17 +11,18 @@ import org.thymeleaf.processor.IProcessor; * A collection of usefull tools. * @author Kai Moritz */ -public class JuploDialect extends AbstractDialect +public class JuploDialect implements IProcessorDialect { public static final String DIALECT_PREFIX = "juplo"; + public static final int DIALEXT_PRECEDENCE = 200; - public JuploDialect() + @Override + public String getName() { - super(); + return DIALECT_PREFIX; } - @Override public String getPrefix() { @@ -29,12 +30,18 @@ public class JuploDialect extends AbstractDialect } @Override - public Set getProcessors() + public int getDialectProcessorPrecedence() + { + return DIALEXT_PRECEDENCE; + } + + @Override + public Set getProcessors(final String prefix) { final Set processors = new HashSet<>(); processors.add(new ActiveAttrProcessor()); processors.add(new InactiveAttrProcessor()); - processors.add(new ImportVariablesAttrProcessor()); + processors.add(new ImportVariablesAttributeProcessor(prefix)); return processors; } } diff --git a/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java b/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java index e8e188e..d36c26d 100644 --- a/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java +++ b/src/test/java/de/juplo/thymeleaf/ImportVariablesAttrProcessorTest.java @@ -23,51 +23,51 @@ public class ImportVariablesAttrProcessorTest { Matcher matcher; - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("{}"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("{}"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" { } "); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(" { } "); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\t{\t}\t"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("\t{\t}\t"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n{\n}\n"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("\n{\n}\n"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" \t\n{ \t\n} \t\n"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(" \t\n{ \t\n} \t\n"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("{\"foo\":\"bar\",\"foobar\":{\"foo\":\"bar\"}"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("{\"foo\":\"bar\",\"foobar\":{\"foo\":\"bar\"}"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(" { \"foo\":\"bar\", \"foobar\": { \"foo\": \"bar\" } "); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(" { \"foo\":\"bar\", \"foobar\": { \"foo\": \"bar\" } "); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\t{\t\"foo\":\t\"bar\"\t,\t\"foobar\":\t{\t\"foo\":\"bar\"\t}"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("\t{\t\"foo\":\t\"bar\"\t,\t\"foobar\":\t{\t\"foo\":\"bar\"\t}"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n{\n\"foo\":\n\"bar\"\n,\n\"foobar\":\n{\n\"foo\":\"bar\"\n}"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("\n{\n\"foo\":\n\"bar\"\n,\n\"foobar\":\n{\n\"foo\":\"bar\"\n}"); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("\n\t {\n\t \"foo\":\n\t \"bar\"\n\t ,\n\t \"foobar\":\n\t {\n\t \"foo\":\"bar\"\n\t }"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("\n\t {\n\t \"foo\":\n\t \"bar\"\n\t ,\n\t \"foobar\":\n\t {\n\t \"foo\":\"bar\"\n\t }"); assertTrue(matcher.matches()); String json; json = read("/json/1.json"); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(json); assertTrue(matcher.matches()); json = read("/json/2.json"); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(json); assertTrue(matcher.matches()); json = read("/json/3.json"); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher(json); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher(json); assertTrue(matcher.matches()); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("foo:bar"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("foo:bar"); assertTrue(matcher.matches()); assertNull(matcher.group(1)); assertNull(matcher.group(2)); assertEquals("foo:bar", matcher.group(3)); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("replace:foo"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("replace:foo"); assertTrue(matcher.matches()); assertNull(matcher.group(1)); assertNull(matcher.group(2)); assertEquals("foo", matcher.group(3)); - matcher = ImportVariablesAttrProcessor.PATTERN.matcher("merge:foo"); + matcher = ImportVariablesAttributeProcessor.PATTERN.matcher("merge:foo"); assertTrue(matcher.matches()); assertEquals("merge", matcher.group(1)); assertNull(matcher.group(2));