Skip to content

Commit

Permalink
Merge pull request #23 from suhothayan/master
Browse files Browse the repository at this point in the history
Improve json:setElement(json, path, json.element) to replace values, API docs, and theme
  • Loading branch information
mohanvive authored Jul 4, 2019
2 parents 63ff5f8 + 7ddf5bb commit 3b56002
Show file tree
Hide file tree
Showing 60 changed files with 2,243 additions and 1,165 deletions.
102 changes: 36 additions & 66 deletions README.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,24 @@
@Extension(
name = "tokenizeAsObject",
namespace = "json",
description = "This tokenizes the given JSON based on the path provided and returns the response as an object.",
description = "Stream processor tokenizes the given JSON into to multiple JSON object elements and " +
"sends them as separate events.",
parameters = {
@Parameter(
name = "json",
description = "The input json that is tokenized using the given path.",
description = "The input JSON that needs to be tokenized.",
type = {DataType.STRING, DataType.OBJECT},
dynamic = true),
@Parameter(
name = "path",
description = "The path of the input JSON that the function tokenizes.",
description = "The path of the set of elements that will be tokenized.",
type = {DataType.STRING},
dynamic = true),
@Parameter(
name = "fail.on.missing.attribute",
description = "If this parameter is set to 'true' and a JSON is not provided in the given" +
" path, the event is dropped. If the parameter is set to 'false', the " +
"unavailability of a JSON in the specified path results in the event being created" +
" with a 'null' value for the json element.",
description = "If there are no element on the given path, when set to `true` the system " +
"will drop the event, and when set to `false` the system will pass 'null' value to " +
"the jsonElement output attribute.",
type = {DataType.BOOL},
optional = true,
defaultValue = "true")
Expand All @@ -87,25 +87,37 @@
returnAttributes = {
@ReturnAttribute(
name = "jsonElement",
description = "The JSON element retrieved based on the given path and the JSON.",
description = "The JSON element retrieved based on the given path will be returned " +
"as a JSON object. If the 'path' selects a JSON array then the system returns each " +
"element in the array as a JSON object via a separate events.",
type = {DataType.OBJECT})},
examples = @Example(
syntax = "define stream InputStream (json string,path string);\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenizeAsObject(json, path)\n" +
"select jsonElement\n" +
"insert into OutputStream;",
description = "This query performs a tokenization for the given JSON using the path specified. If " +
"the specified path provides a JSON array, it generates events for each element in the " +
"specified json array by adding an additional attribute as the 'jsonElement' into the " +
"stream.\n`" +
"e.g.,\n jsonInput - {name:\"John\",enrolledSubjects:[\"Mathematics\",\"Physics\"]}, \n " +
"path -" +
" \"$.enrolledSubjects\"\n`\nIf we use the configuration in the above example, it generates " +
"two events with the attributes \"Mathematics\" and \"Physics\".\nIf the specified path " +
"provides a single json element, it adds the specified json element as an additional " +
"attribute named 'jsonElement' into the stream \n`\n e.g.,\n jsonInput - " +
"{name:\"John\",age:25}, \n path - \"$.age\"\n`\n")
examples = {
@Example(
syntax = "define stream InputStream (json string, path string);\n\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenizeAsObject(json, path)\n" +
"select path, jsonElement\n" +
"insert into OutputStream;",
description = "If the input 'json' is `{name:'John', enrolledSubjects:['Mathematics'," +
" 'Physics']}`, and the 'path' is passed as `$.enrolledSubjects` then for both the " +
"elements in the selected JSON array, it generates it generates events as " +
"`('$.enrolledSubjects', 'Mathematics')`, and " +
"`('$.enrolledSubjects', 'Physics')`.\n" +
"For the same input JSON, if the 'path' is passed as `$.name` then it will only " +
"produce one event `('$.name', 'John')` as the 'path' provided a single JSON element."
),
@Example(
syntax = "define stream InputStream (json string, path string);\n\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenizeAsObject(json, path, true)\n" +
"select path, jsonElement\n" +
"insert into OutputStream;",
description = "If the input 'json' is `{name:'John', age:25}`," +
"and the 'path' is passed as `$.salary` then the system will produce " +
"`('$.salary', null)`, as the 'fail.on.missing.attribute' is `true` and there are " +
"no matching element for `$.salary`."
)
}
)
public class JsonTokenizerAsObjectStreamProcessorFunction extends StreamProcessor<State> {
private static final Logger log = Logger.getLogger(JsonTokenizerAsObjectStreamProcessorFunction.class);
Expand All @@ -128,7 +140,8 @@ protected void process(ComplexEventChunk<StreamEvent> streamEventChunk, Processo
}
} catch (PathNotFoundException e) {
filteredJsonElements = null;
log.warn("Cannot find json element for the path '" + path + "' in the input json : " + jsonInput);
log.warn(siddhiQueryContext.getSiddhiAppContext().getName() + ":" + siddhiQueryContext.getName() +
": Cannot find json element for the path '" + path + "' in the input json : " + jsonInput);
} catch (InvalidJsonException e) {
throw new SiddhiAppRuntimeException("The input JSON is not a valid JSON. Input JSON - " + jsonInput, e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,24 +58,24 @@
@Extension(
name = "tokenize",
namespace = "json",
description = "This tokenizes the given json according the path provided",
description = "Stream processor tokenizes the given JSON into to multiple JSON string elements and " +
"sends them as separate events.",
parameters = {
@Parameter(
name = "json",
description = "The input json that should be tokenized using the given path.",
description = "The input JSON that needs to be tokenized.",
type = {DataType.STRING, DataType.OBJECT},
dynamic = true),
@Parameter(
name = "path",
description = "The path that is used to tokenize the given json",
description = "The path of the set of elements that will be tokenized.",
type = {DataType.STRING},
dynamic = true),
@Parameter(
name = "fail.on.missing.attribute",
description = "If this parameter is set to 'true' and a json is not provided in the given" +
" path, the event is dropped. If the parameter is set to 'false', the " +
"unavailability of a json in the specified path results in the event being created" +
" with a 'null' value for the json element.",
description = "If there are no element on the given path, when set to `true` the system " +
"will drop the event, and when set to `false` the system will pass 'null' value to " +
"the jsonElement output attribute.",
type = {DataType.BOOL},
optional = true,
defaultValue = "true")
Expand All @@ -87,24 +87,37 @@
returnAttributes = {
@ReturnAttribute(
name = "jsonElement",
description = "The json element retrieved based on the given path and the json.",
description = "The JSON element retrieved based on the given path will be returned " +
"as a JSON string. If the 'path' selects a JSON array then the system returns each " +
"element in the array as a JSON string via a separate events.",
type = {DataType.STRING})},
examples = @Example(
syntax = "define stream InputStream (json string,path string);\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenize(json, path)\n" +
"select jsonElement\n" +
"insert into OutputStream;",
description = "This query performs a tokenization for the given json using the path specified. If " +
"the specified path provides a json array, it generates events for each element in that " +
"array by adding an additional attributes as the 'jsonElement' to the stream.\n`" +
"e.g.,\n jsonInput - {name:\"John\",enrolledSubjects:[\"Mathematics\",\"Physics\"]}, \n " +
"path -" +
" \"$.enrolledSubjects\"\n`\n If we use the configuration in this example, it generates " +
"two events with the attributes \"Mathematics\", \"Physics\".\nIf the specified path provides" +
" a single json element, it adds the specified json element as an additional attribute " +
"named 'jsonElement' into the stream. \n`\n e.g.,\n jsonInput - {name:\"John\",age:25}, \n " +
"path - \"$.age\"\n`\n")
examples = {
@Example(
syntax = "define stream InputStream (json string, path string);\n\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenizeAsObject(json, path)\n" +
"select path, jsonElement\n" +
"insert into OutputStream;",
description = "If the input 'json' is `{name:'John', enrolledSubjects:['Mathematics'," +
" 'Physics']}`, and the 'path' is passed as `$.enrolledSubjects` then for both the " +
"elements in the selected JSON array, it generates it generates events as " +
"`('$.enrolledSubjects', 'Mathematics')`, and " +
"`('$.enrolledSubjects', 'Physics')`.\n" +
"For the same input JSON, if the 'path' is passed as `$.name` then it will only " +
"produce one event `('$.name', 'John')` as the 'path' provided a single JSON element."
),
@Example(
syntax = "define stream InputStream (json string, path string);\n\n" +
"@info(name = 'query1')\n" +
"from InputStream#json:tokenizeAsObject(json, path, true)\n" +
"select path, jsonElement\n" +
"insert into OutputStream;",
description = "If the input 'json' is `{name:'John', age:25}`," +
"and the 'path' is passed as `$.salary` then the system will produce " +
"`('$.salary', null)`, as the 'fail.on.missing.attribute' is `true` and there are " +
"no matching element for `$.salary`."
)
}
)
public class JsonTokenizerStreamProcessorFunction extends StreamProcessor<State> {
private static final Logger log = Logger.getLogger(JsonTokenizerStreamProcessorFunction.class);
Expand All @@ -128,7 +141,8 @@ protected void process(ComplexEventChunk<StreamEvent> streamEventChunk, Processo
}
} catch (PathNotFoundException e) {
filteredJsonElements = null;
log.warn("Cannot find json element for the path '" + path + "' in the input json : " + jsonInput);
log.warn(siddhiQueryContext.getSiddhiAppContext().getName() + ":" + siddhiQueryContext.getName() +
": Cannot find json element for the path '" + path + "' in the input json : " + jsonInput);
}
if (filteredJsonElements instanceof List) {
List filteredJsonElementsList = (List) filteredJsonElements;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,33 +49,45 @@
@Extension(
name = "getBool",
namespace = "json",
description = "This method returns a 'boolean' value, either 'true' or 'false', based on the value" +
"specified against the JSON element present in the given path." +
"In case there is no valid boolean value found in the given path, the method still returns 'false'.",
description = "Function retrieves the 'boolean' value specified in the given path of the JSON element.",
parameters = {
@Parameter(
name = "json",
description = "The JSON input that holds the boolean value in the given path.",
description = "The JSON input containing boolean value.",
type = {DataType.STRING, DataType.OBJECT},
dynamic = true),
@Parameter(
name = "path",
description = "The path of the input JSON from which the 'getBool' function fetches the" +
"boolean value.",
description = "The JSON path to fetch the boolean value.",
type = {DataType.STRING},
dynamic = true)
},
parameterOverloads = {
@ParameterOverload(parameterNames = {"json", "path"})
},
returnAttributes = @ReturnAttribute(
description = "Returns the boolean value of the input JSON from the input stream.",
description = "Returns the boolean retrieved by the JSON path from the given input JSON, " +
"if no valid boolean found in the given path, it returns `null`.",
type = {DataType.BOOL}),
examples = @Example(
syntax = "json:getBool(json,\"$.name\") as name\n",
description = "This returns the boolean value of the JSON input in the given path."
)
examples = {
@Example(
syntax = "json:getBool(json,'$.married')",
description = "If the `json` is the format `{'name' : 'John', 'married' : true}`, " +
"the function returns `true` as there is a matching boolean at `$.married`."
),
@Example(
syntax = "json:getBool(json,'$.name')",
description = "If the `json` is the format `{'name' : 'John', 'married' : true}`, " +
"the function returns `null` as there is no matching boolean at `$.name`."
),
@Example(
syntax = "json:getBool(json,'$.foo')",
description = "If the `json` is the format `{'name' : 'John', 'married' : true}`, " +
"the function returns `null` as there is no matching element at `$.foo`."
)
}
)

public class GetBoolJSONFunctionExtension extends FunctionExecutor {
private static final Logger log = Logger.getLogger(GetBoolJSONFunctionExtension.class);
private static final Gson gson = new GsonBuilder().serializeNulls().create();
Expand Down Expand Up @@ -142,16 +154,18 @@ protected Object execute(Object[] data, State state) {
try {
filteredJsonElement = JsonPath.read(jsonInput, path);
} catch (PathNotFoundException e) {
log.error("Cannot find the json element for the path '" + path + "'. Hence it returns" +
log.error(siddhiQueryContext.getSiddhiAppContext().getName() + ":" + siddhiQueryContext.getName() +
": Cannot find the json element for the path '" + path + "'. Hence it returns" +
"the default value 'null'");
} catch (InvalidJsonException e) {
throw new SiddhiAppRuntimeException("The input JSON is not a valid JSON. Input JSON - " + jsonInput, e);
}
if (filteredJsonElement instanceof List) {
if (((List) filteredJsonElement).size() != 1) {
filteredJsonElement = null;
log.error("Multiple matches or No matches for the given path '" + path + "' in input json. Please use" +
" valid path which provide exact one match in the given json");
log.error(siddhiQueryContext.getSiddhiAppContext().getName() + ":" + siddhiQueryContext.getName() +
": Multiple matches or No matches for the given path '" + path +
"' in input json. Please use valid path which provide exact one match in the given json");
} else {
filteredJsonElement = ((List) filteredJsonElement).get(0);
}
Expand All @@ -162,8 +176,9 @@ protected Object execute(Object[] data, State state) {
returnValue = Boolean.parseBoolean(filteredJsonElement.toString());
if (!returnValue && !filteredJsonElement.toString().equalsIgnoreCase("false")) {
returnValue = null;
log.error("The value that is retrieved using the given path '" + path + "', is not a valid boolean value." +
" Hence it returns the default value 'null'");
log.error(siddhiQueryContext.getSiddhiAppContext().getName() + ":" + siddhiQueryContext.getName() +
": The value that is retrieved using the given path '" + path +
"', is not a valid boolean value. Hence it returns the default value 'null'");
}
return returnValue;
}
Expand Down
Loading

0 comments on commit 3b56002

Please sign in to comment.