From a7077e8eb0dade62969e5aa09e339b2dc2f58b86 Mon Sep 17 00:00:00 2001 From: Kai Moritz Date: Sat, 18 Jun 2016 13:15:09 +0200 Subject: [PATCH] WIP: variables-dialect --- .../ImportVariablesAttrProcessor.java | 131 +++++++++++++++--- 1 file changed, 114 insertions(+), 17 deletions(-) diff --git a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java index bc3f3da..b4c3b30 100644 --- a/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java +++ b/src/main/java/de/juplo/thymeleaf/ImportVariablesAttrProcessor.java @@ -2,16 +2,18 @@ package de.juplo.thymeleaf; import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonLocation; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; -import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.InputStream; import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; import java.util.Locale; -import java.util.Map.Entry; -import java.util.logging.Level; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -25,10 +27,8 @@ import org.thymeleaf.dom.Element; 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.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.TemplateResolution; -import org.thymeleaf.util.StringUtils; @@ -100,18 +100,15 @@ public class ImportVariablesAttrProcessor extends AbstractAttrProcessor /** Read the JSON and create the variables */ JsonParser parser = FACTORY.createParser(is); - JsonToken root = parser.nextToken(); + JsonToken token = parser.nextToken(); - - JsonNode root = MAPPER.readTree(is); - - if (root == null) + if (token == null) { LOG.warn("found empty content for {}", templateName); break; } - if (!root.isObject()) + if (!JsonToken.START_OBJECT.equals(token)) { LOG.error("{} must contain an object as root-element", templateName); throw new RuntimeException( @@ -120,12 +117,39 @@ public class ImportVariablesAttrProcessor extends AbstractAttrProcessor " has to be an object, that contains the variable-definitions!" ); } -root. - for (Entry entry : root.fields()) + + token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + if (!JsonToken.END_OBJECT.equals(token)) { - Object var = ImportVariablesAttrProcessor.convert(root.get(i)); - element.setNodeLocalVariable(name, var); + LOG.warn("found empty object for {}", templateName); + break; } + + do + { + if (!JsonToken.FIELD_NAME.equals(token)) + fail(parser, "expected a field-name"); + + String var_name = parser.getText(); + Object var_value = convert(parser); + + LOG.debug( + "defining variable {} of type {}", + var_name, + var_value == null ? "NULL" : var_value.getClass().getSimpleName() + ); + element.setNodeLocalVariable(var_name, var_value); + + token = parser.nextToken(); + if (token == null) + fail(parser, "unexpected EOF"); + } + while (!JsonToken.END_OBJECT.equals(token)); + + if (parser.nextToken() != null) + fail(parser, "unexpected data after parsed variables"); } catch (IOException e) { @@ -147,8 +171,81 @@ root. } - public static Object convert(JsonNode node) + static Object convert(JsonParser parser) throws IOException + { + JsonToken token = parser.nextToken(); + 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 HashMap<>(); + + while (!JsonToken.END_OBJECT.equals(token)) + { + if (!JsonToken.FIELD_NAME.equals(token)) + fail(parser, "expected a field-name"); + + map.put(parser.getText(), convert(parser)); + + 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) { - return null; + 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); } } -- 2.20.1