NIFI-5271 Moved JSON_VALIDATOR to its own maven module.

This closes #2765

Signed-off-by: zenfenan <zenfenan@apache.org>
This commit is contained in:
Mike Thomsen 2018-06-06 07:29:01 -04:00 committed by zenfenan
parent ff00050266
commit d2fd7e5e7d
16 changed files with 242 additions and 90 deletions

View File

@ -0,0 +1,39 @@
<?xml version="1.0"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-commons</artifactId>
<version>1.7.0-SNAPSHOT</version>
</parent>
<artifactId>nifi-json-utils</artifactId>
<version>1.7.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-api</artifactId>
<version>1.7.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,49 @@
/*
* 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.processor.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import java.util.List;
import java.util.Map;
public class JsonValidator implements Validator {
public static final JsonValidator INSTANCE = new JsonValidator();
@Override
public ValidationResult validate(String subject, String input, ValidationContext context) {
ObjectMapper mapper = new ObjectMapper();
if (context.isExpressionLanguageSupported(subject) && context.isExpressionLanguagePresent(input)) {
return new ValidationResult.Builder().subject(subject).input(input).explanation("Expression Language Present").valid(true).build();
}
try {
Class clz = input.startsWith("[") ? List.class : Map.class;
mapper.readValue(input, clz);
} catch (Exception e) {
return new ValidationResult.Builder().subject(subject).input(input).valid(false)
.explanation(subject + " is not a valid JSON representation due to " + e.getLocalizedMessage())
.build();
}
return new ValidationResult.Builder().subject(subject).input(input).valid(true).build();
}
}

View File

@ -0,0 +1,101 @@
/*
* 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.processor
import org.apache.nifi.components.ValidationContext
import org.apache.nifi.components.ValidationResult
import org.apache.nifi.components.Validator
import org.apache.nifi.processor.util.JsonValidator
import org.junit.Before
import org.junit.Test
import static org.junit.Assert.assertFalse
import static org.junit.Assert.assertTrue
import static org.mockito.Mockito.mock
import static groovy.json.JsonOutput.*
class TestStandardValidators {
final String DUMMY_JSON_PROPERTY = "JSONProperty"
Validator validator
ValidationContext context
@Before
void setup() {
validator = JsonValidator.INSTANCE
context = mock(ValidationContext.class)
}
@Test
void testFlat() {
def msg = prettyPrint(toJson([
Name: "Crockford, Douglas"
]))
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, msg, context)
assertTrue(validationResult.isValid())
}
@Test
void testNested() {
def msg = prettyPrint(toJson([
Name: "Crockford, Douglas",
ContactInfo: [
Mobile: 987654321,
Email: "mrx@xyz.zyx"
]
]))
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, msg, context)
assertTrue(validationResult.isValid())
}
@Test
void testObjectWithArray() {
def msg = prettyPrint(toJson([
name: "Smith, John",
age: 30,
cars: [ "Ford", "BMW", "Fiat" ]
]))
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, msg, context)
assertTrue(validationResult.isValid())
}
@Test
void testJSONArray() {
def msg = prettyPrint(toJson([
"one", "two", "three"
]))
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, msg, context)
assertTrue(validationResult.isValid())
}
@Test
void testEmpty() {
// Empty JSON
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{}", context)
assertTrue(validationResult.isValid())
}
@Test
void testInvalidJson() {
// Invalid JSON
ValidationResult validationResult = validator.validate(DUMMY_JSON_PROPERTY, "\"Name\" : \"Smith, John\"", context)
assertFalse(validationResult.isValid())
assertTrue(validationResult.getExplanation().contains("not a valid JSON representation"))
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "bncjbhjfjhj", context)
assertFalse(validationResult.isValid())
}
}

View File

@ -40,10 +40,5 @@
<artifactId>nifi-api</artifactId>
<version>1.7.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
</dependency>
</dependencies>
</project>

View File

@ -16,6 +16,15 @@
*/
package org.apache.nifi.processor.util;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.expression.AttributeExpression.ResultType;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.processor.DataUnit;
import org.apache.nifi.util.FormatUtils;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
@ -30,18 +39,6 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonSyntaxException;
import org.apache.nifi.components.PropertyValue;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.expression.AttributeExpression.ResultType;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.processor.DataUnit;
import org.apache.nifi.util.FormatUtils;
public class StandardValidators {
//
@ -483,25 +480,6 @@ public class StandardValidators {
public static final Validator FILE_EXISTS_VALIDATOR = new FileExistsValidator(true);
/**
* {@link Validator} that ensures the value is a valid JSON
*/
public static final Validator JSON_VALIDATOR = (subject, input, context) -> {
if (context.isExpressionLanguageSupported(subject) && context.isExpressionLanguagePresent(input)) {
return new ValidationResult.Builder().subject(subject).input(input).explanation("Expression Language Present").valid(true).build();
}
try {
new Gson().fromJson(input, JsonElement.class);
} catch (JsonSyntaxException e) {
return new ValidationResult.Builder().subject(subject).input(input).valid(false)
.explanation(subject + " is not a valid JSON representation due to " + e.getLocalizedMessage())
.build();
}
return new ValidationResult.Builder().subject(subject).input(input).valid(true).build();
};
//
//
// FACTORY METHODS FOR VALIDATORS

View File

@ -16,12 +16,6 @@
*/
package org.apache.nifi.util.validator;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.util.concurrent.TimeUnit;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
@ -29,6 +23,12 @@ import org.apache.nifi.processor.util.StandardValidators;
import org.junit.Test;
import org.mockito.Mockito;
import java.util.concurrent.TimeUnit;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
public class TestStandardValidators {
@Test
@ -288,42 +288,4 @@ public class TestStandardValidators {
vr = val.validate("foo", "2016-01-01T01:01:01.000Z", vc);
assertTrue(vr.isValid());
}
@Test
public void testJSONObjectValidator() {
final Validator validator = StandardValidators.JSON_VALIDATOR;
final ValidationContext context = mock(ValidationContext.class);
final String DUMMY_JSON_PROPERTY = "JSONProperty";
ValidationResult validationResult;
// Flat JSON
validationResult = validator.validate(DUMMY_JSON_PROPERTY,"{\"Name\" : \"Crockford, Douglas\"}", context);
assertTrue(validationResult.isValid());
// Nested JSON
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{ \"Name\" : \"Crockford, Douglas\", \"ContactInfo\": { \"Mobile\" : 0987654321, \"Email\" : \"mrx@xyz.zyx\" } }", context);
assertTrue(validationResult.isValid());
// JSON object with JSON array
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{ \"name\":\"Smith, John\", \"age\":30, \"cars\":[ \"Ford\", \"BMW\", \"Fiat\" ] } ", context);
assertTrue(validationResult.isValid());
// JSON array
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "[\"one\", \"two\", \"three\"]", context);
assertTrue(validationResult.isValid());
// JSON Primitives
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "bncjbhjfjhj", context);
assertTrue(validationResult.isValid());
// Empty JSON
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "{}", context);
assertTrue(validationResult.isValid());
// Invalid JSON
validationResult = validator.validate(DUMMY_JSON_PROPERTY, "\"Name\" : \"Smith, John\"", context);
assertFalse(validationResult.isValid());
assertTrue(validationResult.getExplanation().contains("not a valid JSON representation"));
}
}

View File

@ -31,6 +31,7 @@
<module>nifi-security-utils</module>
<module>nifi-socket-utils</module>
<module>nifi-utils</module>
<module>nifi-json-utils</module>
<module>nifi-web-utils</module>
<module>nifi-write-ahead-log</module>
<module>nifi-site-to-site-client</module>

View File

@ -110,6 +110,12 @@ language governing permissions and limitations under the License. -->
<version>1.7.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-json-utils</artifactId>
<version>1.7.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

View File

@ -24,6 +24,7 @@ import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.util.JsonValidator;
import org.apache.nifi.processor.util.StandardValidators;
import java.io.ByteArrayOutputStream;
@ -55,7 +56,7 @@ public interface ElasticSearchRestProcessor {
"If this parameter is not set, the query will be read from the flowfile content.")
.required(false)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.build();
PropertyDescriptor QUERY_ATTRIBUTE = new PropertyDescriptor.Builder()
.name("el-query-attribute")

View File

@ -80,6 +80,12 @@
<artifactId>json</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-json-utils</artifactId>
<version>1.7.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>

View File

@ -18,6 +18,7 @@ package org.apache.nifi.processors.gcp.credentials.factory;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.util.JsonValidator;
import org.apache.nifi.processor.util.StandardValidators;
/**
@ -83,7 +84,7 @@ public final class CredentialPropertyDescriptors {
.displayName("Service Account JSON")
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.required(false)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.description("The raw JSON containing a Service Account keyfile.")
.sensitive(true)
.build();

View File

@ -45,6 +45,11 @@
<groupId>com.github.stephenc.findbugs</groupId>
<artifactId>findbugs-annotations</artifactId>
<version>1.3.9-1</version>
</dependency>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency> <!-- TODO: Remove this when the next version of google-auth-library-oauth2-http is released and brings this in-->
</dependencies>
</project>

View File

@ -85,5 +85,11 @@
<version>18.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-json-utils</artifactId>
<version>1.7.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -38,6 +38,7 @@ import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.JsonValidator;
import org.apache.nifi.processor.util.StandardValidators;
import org.bson.Document;
import org.bson.json.JsonWriterSettings;
@ -79,7 +80,7 @@ public class GetMongo extends AbstractMongoProcessor {
"that will result in a full collection fetch using a \"{}\" query.")
.required(false)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.build();
static final PropertyDescriptor PROJECTION = new PropertyDescriptor.Builder()
@ -87,14 +88,14 @@ public class GetMongo extends AbstractMongoProcessor {
.description("The fields to be returned from the documents in the result set; must be a valid BSON document")
.required(false)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.build();
static final PropertyDescriptor SORT = new PropertyDescriptor.Builder()
.name("Sort")
.description("The fields by which to sort; must be a valid BSON document")
.required(false)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.build();
static final PropertyDescriptor LIMIT = new PropertyDescriptor.Builder()
.name("Limit")

View File

@ -39,6 +39,7 @@ import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.JsonValidator;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.stream.io.StreamUtils;
import org.apache.nifi.util.StringUtils;
@ -100,7 +101,7 @@ public class PutMongo extends AbstractMongoProcessor {
.displayName("Update Query")
.description("Specify a full MongoDB query to be used for the lookup query to do an update/upsert.")
.required(false)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.build();

View File

@ -19,6 +19,7 @@
package org.apache.nifi.processors.mongodb;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
@ -34,10 +35,9 @@ import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.processor.util.JsonValidator;
import org.bson.Document;
import org.bson.conversions.Bson;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.util.ArrayList;
@ -88,7 +88,7 @@ public class RunMongoAggregation extends AbstractMongoProcessor {
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
.description("The aggregation query to be executed.")
.required(true)
.addValidator(StandardValidators.JSON_VALIDATOR)
.addValidator(JsonValidator.INSTANCE)
.build();
static {