From ebd11b1d8f7e656d8b38d5b2ba76377278df5b1b Mon Sep 17 00:00:00 2001 From: Devin Fisher Date: Sun, 3 Jul 2016 01:53:16 +0200 Subject: [PATCH] EscapeJson function added to expression-language Made use of org.apache.commons.lang3.StringEscapeUtils to do that actual processing Signed-off-by: Matt Burgess --- .../language/antlr/AttributeExpressionLexer.g | 13 ++--- .../antlr/AttributeExpressionParser.g | 14 +++--- .../attribute/expression/language/Query.java | 6 +++ .../functions/EscapeJsonEvaluator.java | 47 +++++++++++++++++++ .../expression/language/TestQuery.java | 8 ++++ 5 files changed, 75 insertions(+), 13 deletions(-) create mode 100644 nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/EscapeJsonEvaluator.java diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g index 37cb02a2a7..1c1171c9d0 100644 --- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g +++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionLexer.g @@ -41,7 +41,7 @@ lexer grammar AttributeExpressionLexer; } sb.append(", column ").append(e.charPositionInLine); sb.append(". Query: ").append(e.input.toString()); - + throw new AttributeExpressionLanguageParsingException(sb.toString()); } @@ -58,9 +58,9 @@ lexer grammar AttributeExpressionLexer; } sb.append(", column ").append(e.charPositionInLine); sb.append(". Query: ").append(e.input.toString()); - + throw new AttributeExpressionLanguageParsingException(sb.toString()); - } + } } @@ -117,6 +117,7 @@ URL_DECODE : 'urlDecode'; NOT : 'not'; COUNT : 'count'; RANDOM : 'random'; +ESCAPE_JSON : 'escapeJson'; // 1 arg functions SUBSTRING_AFTER : 'substringAfter'; @@ -174,7 +175,7 @@ STRING_LITERAL '"' ( escaped=ESC {lBuf.append(getText());} | - normal = ~( '"' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);} + normal = ~( '"' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);} )* '"' ) @@ -186,7 +187,7 @@ STRING_LITERAL '\'' ( escaped=ESC {lBuf.append(getText());} | - normal = ~( '\'' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);} + normal = ~( '\'' | '\\' | '\n' | '\r' | '\t' ) { lBuf.appendCodePoint(normal);} )* '\'' ) @@ -206,7 +207,7 @@ ESC | 'n' { setText("\n"); } | 't' { setText("\t"); } | '\\' { setText("\\\\"); } - | nextChar = ~('"' | '\'' | 'r' | 'n' | 't' | '\\') + | nextChar = ~('"' | '\'' | 'r' | 'n' | 't' | '\\') { StringBuilder lBuf = new StringBuilder(); lBuf.append("\\\\").appendCodePoint(nextChar); setText(lBuf.toString()); } diff --git a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g index 726246d3c1..5b2040342f 100644 --- a/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g +++ b/nifi-commons/nifi-expression-language/src/main/antlr3/org/apache/nifi/attribute/expression/language/antlr/AttributeExpressionParser.g @@ -50,7 +50,7 @@ tokens { } sb.append(", column ").append(e.charPositionInLine); sb.append(". Query: ").append(e.input.toString()); - + throw new AttributeExpressionLanguageParsingException(sb.toString()); } @@ -67,13 +67,13 @@ tokens { } sb.append(", column ").append(e.charPositionInLine); sb.append(". Query: ").append(e.input.toString()); - + throw new AttributeExpressionLanguageParsingException(sb.toString()); - } + } } // functions that return Strings -zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECODE) LPAREN! RPAREN!; +zeroArgString : (TO_UPPER | TO_LOWER | TRIM | TO_STRING | URL_ENCODE | URL_DECODE | ESCAPE_JSON) LPAREN! RPAREN!; oneArgString : ((SUBSTRING_BEFORE | SUBSTRING_BEFORE_LAST | SUBSTRING_AFTER | SUBSTRING_AFTER_LAST | REPLACE_NULL | REPLACE_EMPTY | PREPEND | APPEND | FORMAT | STARTS_WITH | ENDS_WITH | CONTAINS | JOIN | JSON_PATH) LPAREN! anyArg RPAREN!) | (TO_RADIX LPAREN! anyArg (COMMA! anyArg)? RPAREN!); @@ -113,7 +113,7 @@ attrName : singleAttrName | multiAttrName; singleAttrRef : ATTRIBUTE_NAME | STRING_LITERAL; singleAttrName : singleAttrRef -> ^(ATTR_NAME singleAttrRef); - + multiAttrFunction : ANY_ATTRIBUTE | ANY_MATCHING_ATTRIBUTE | ALL_ATTRIBUTES | ALL_MATCHING_ATTRIBUTES | ANY_DELINEATED_VALUE | ALL_DELINEATED_VALUES; multiAttrName : multiAttrFunction LPAREN stringArg (COMMA stringArg)* RPAREN -> @@ -121,14 +121,14 @@ multiAttrName : multiAttrFunction LPAREN stringArg (COMMA stringArg)* RPAREN -> attributeRef : subject -> ^(ATTRIBUTE_REFERENCE subject); - + functionCall : functionRef -> ^(FUNCTION_CALL functionRef); booleanLiteral : TRUE | FALSE; zeroArgStandaloneFunction : (IP | UUID | NOW | NEXT_INT | HOSTNAME | RANDOM) LPAREN! RPAREN!; -oneArgStandaloneFunction : (TO_LITERAL^ LPAREN! anyArg RPAREN!) | +oneArgStandaloneFunction : (TO_LITERAL^ LPAREN! anyArg RPAREN!) | (HOSTNAME^ LPAREN! booleanLiteral RPAREN!); standaloneFunction : zeroArgStandaloneFunction | oneArgStandaloneFunction; diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java index 91628156e4..f4f994f660 100644 --- a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/Query.java @@ -93,6 +93,7 @@ import org.apache.nifi.attribute.expression.language.evaluation.functions.ToUppe import org.apache.nifi.attribute.expression.language.evaluation.functions.TrimEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UrlDecodeEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UrlEncodeEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.functions.EscapeJsonEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.functions.UuidEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.literals.BooleanLiteralEvaluator; import org.apache.nifi.attribute.expression.language.evaluation.literals.NumberLiteralEvaluator; @@ -191,6 +192,7 @@ import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpre import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.TRUE; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_DECODE; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.URL_ENCODE; +import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.ESCAPE_JSON; import static org.apache.nifi.attribute.expression.language.antlr.AttributeExpressionParser.UUID; import org.apache.nifi.attribute.expression.language.evaluation.selection.MappingEvaluator; @@ -922,6 +924,10 @@ public class Query { verifyArgCount(argEvaluators, 0, "urlDecode"); return addToken(new UrlDecodeEvaluator(toStringEvaluator(subjectEvaluator)), "urlDecode"); } + case ESCAPE_JSON: { + verifyArgCount(argEvaluators, 0, "escapeJson"); + return addToken(new EscapeJsonEvaluator(toStringEvaluator(subjectEvaluator)), "urlDecode"); + } case SUBSTRING_BEFORE: { verifyArgCount(argEvaluators, 1, "substringBefore"); return addToken(new SubstringBeforeEvaluator(toStringEvaluator(subjectEvaluator), diff --git a/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/EscapeJsonEvaluator.java b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/EscapeJsonEvaluator.java new file mode 100644 index 0000000000..d8ad1b48cd --- /dev/null +++ b/nifi-commons/nifi-expression-language/src/main/java/org/apache/nifi/attribute/expression/language/evaluation/functions/EscapeJsonEvaluator.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.nifi.attribute.expression.language.evaluation.functions; + +import java.util.Map; + +import org.apache.nifi.attribute.expression.language.evaluation.Evaluator; +import org.apache.nifi.attribute.expression.language.evaluation.QueryResult; +import org.apache.nifi.attribute.expression.language.evaluation.StringEvaluator; +import org.apache.nifi.attribute.expression.language.evaluation.StringQueryResult; + +import org.apache.commons.lang3.StringEscapeUtils; + +public class EscapeJsonEvaluator extends StringEvaluator { + + private final Evaluator subject; + + public EscapeJsonEvaluator(final Evaluator subject) { + this.subject = subject; + } + + @Override + public QueryResult evaluate(final Map attributes) { + final String subjectValue = subject.evaluate(attributes).getValue(); + return new StringQueryResult(subjectValue == null ? "" : StringEscapeUtils.escapeJson(subjectValue)); + } + + @Override + public Evaluator getSubjectEvaluator() { + return subject; + } + +} diff --git a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java index fd095608b7..2183cb14dd 100644 --- a/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java +++ b/nifi-commons/nifi-expression-language/src/test/java/org/apache/nifi/attribute/expression/language/TestQuery.java @@ -1314,6 +1314,14 @@ public class TestQuery { verifyEquals("${line:getDelimitedField(2)}", attributes, " 32"); } + @Test + public void testEscapeJson() { + final Map attributes = new HashMap<>(); + + attributes.put("string", "making air \"QUOTES\"."); + verifyEquals("${string:escapeJson()}", attributes, "making air \\\"QUOTES\\\"."); + } + private void verifyEquals(final String expression, final Map attributes, final Object expectedResult) { Query.validateExpression(expression, false); assertEquals(String.valueOf(expectedResult), Query.evaluateExpressions(expression, attributes, null));