Browse Source

Added option to Suppress exceptions.

pull/41/head
Kalle Stenflo 10 years ago
parent
commit
6ac6b60dd4
  1. 31
      json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Bench.java
  2. 2
      json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Result.java
  3. 35
      json-path-web-test/src/main/java/com/jayway/jsonpath/web/resource/IndexResource.java
  4. 237
      json-path-web-test/src/main/resources/templates/index.mustache
  5. 29
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  6. 11
      json-path/src/main/java/com/jayway/jsonpath/Option.java
  7. 9
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/EvaluationContextImpl.java

31
json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Bench.java

@ -13,24 +13,26 @@ import org.boon.json.implementation.ObjectMapperImpl;
import scala.collection.Iterator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static java.util.Arrays.asList;
import java.util.Map;
public class Bench {
protected final String json;
protected final String path;
private final boolean optionAsValues;
private final boolean optionAllwaysReturnList;
private final boolean optionMergeMultiProps;
private final boolean flagWrap;
private final boolean flagMerge;
private final boolean flagSuppress;
public Bench(String json, String path, boolean optionAsValues, boolean optionAllwaysReturnList, boolean optionMergeMultiProps) {
public Bench(String json, String path, boolean optionAsValues, boolean flagWrap, boolean flagMerge, boolean flagSuppress) {
this.json = json;
this.path = path;
this.optionAsValues = optionAsValues;
this.optionAllwaysReturnList = optionAllwaysReturnList;
this.optionMergeMultiProps = optionMergeMultiProps;
this.flagWrap = flagWrap;
this.flagMerge = flagMerge;
this.flagSuppress = flagSuppress;
}
public Result runJayway() {
@ -41,12 +43,15 @@ public class Bench {
Configuration configuration = Configuration.defaultConfiguration();
if(optionAllwaysReturnList){
if(flagWrap){
configuration = configuration.addOptions(Option.ALWAYS_RETURN_LIST);
}
if(optionMergeMultiProps){
if(flagMerge){
configuration = configuration.addOptions(Option.MERGE_MULTI_PROPS);
}
if(flagSuppress){
configuration = configuration.addOptions(Option.SUPPRESS_EXCEPTIONS);
}
if (!optionAsValues) {
configuration = configuration.addOptions(Option.AS_PATH_LIST);
}
@ -129,8 +134,12 @@ public class Bench {
}
}
public List<Result> runAll() {
return asList(runJayway(), runBoon(), runNebhale());
public Map<String, Result> runAll() {
Map<String, Result> res = new HashMap<String, Result>();
res.put("jayway", runJayway());
res.put("boon", runBoon());
res.put("nebhale", runNebhale());
return res;
}
private String getError(Exception e) {

2
json-path-web-test/src/main/java/com/jayway/jsonpath/web/bench/Result.java

@ -5,14 +5,12 @@ import com.jayway.jsonpath.internal.JsonFormatter;
public class Result {
public final String provider;
public final String active;
public final long time;
public final String result;
public final String error;
public Result(String provider, long time, String result, String error) {
this.provider = provider;
this.active = provider == "jayway" ? "active" : "";
this.time = time;
this.result = result != null ? JsonFormatter.prettyPrint(result) : result;
this.error = error;

35
json-path-web-test/src/main/java/com/jayway/jsonpath/web/resource/IndexResource.java

@ -13,9 +13,11 @@ import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.List;
@ -23,7 +25,7 @@ import java.util.Map;
import static java.util.Arrays.asList;
@Path("")
@Path("/")
@Produces(MediaType.TEXT_HTML)
public class IndexResource {
@ -32,22 +34,38 @@ public class IndexResource {
public final static Map<String, String> TEMPLATES = loadTemplates();
@GET
public Viewable get(@QueryParam("template") @DefaultValue("goessner") String template){
return createView(TEMPLATES.get(template), "$.store.book[0].title", true, template, null);
@Path("templates/{template}")
@Produces(MediaType.APPLICATION_JSON)
public Response getTemplate(@PathParam("template") @DefaultValue("goessner") String template){
return Response.ok(TEMPLATES.get(template)).build();
}
@POST
@Path("eval")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Viewable post(@FormParam("json") String json,
@FormParam("path") String path,
@FormParam("type") String type,
@FormParam("template") String template){
@Produces(MediaType.APPLICATION_JSON)
public Response getTemplate(@FormParam("json") String json,
@FormParam("path") String path,
@FormParam("type") String type,
@FormParam("flagWrap") boolean flagWrap,
@FormParam("flagMerge") boolean flagMerge,
@FormParam("flagSuppress") boolean flagSuppress ){
boolean value = "VALUE".equalsIgnoreCase(type);
return createView(json, path, value, template, new Bench(json, path, value, true, true).runAll());
Map<String, Result> resultMap = new Bench(json, path, value, flagWrap, flagMerge, flagSuppress).runAll();
return Response.ok(resultMap).build();
}
@GET
public Viewable get(@QueryParam("template") @DefaultValue("goessner") String template){
return createView(TEMPLATES.get(template), "$.store.book[0].title", true, template, null);
}
private Viewable createView(String json, String path, boolean value, String selectedTemplate, List<Result> results){
Map<String, Object> res = new HashMap<String, Object>();
res.put("results", results);
@ -70,6 +88,7 @@ public class IndexResource {
String twentyK = IOUtils.toString(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/20k.json"));
Map<String, String> templates = new HashMap<String, String>();
templates.put("blank", "null");
templates.put("goessner", goessner);
templates.put("twitter", twitter);
templates.put("webapp", webapp);

237
json-path-web-test/src/main/resources/templates/index.mustache

@ -6,79 +6,138 @@
<title>JsonPath</title>
<link rel="stylesheet" href="/static/css/bootstrap.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.min.css">
<link rel="stylesheet" href="//google-code-prettify.googlecode.com/svn/loader/prettify.css">
<script type="text/javascript" src="//google-code-prettify.googlecode.com/svn/loader/prettify.js?autoload=false"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript" src="/static/js/jsonpath-0.8.0.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.js"></script>
<script src="//google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
</head>
<body role="document">
<div class="container">
<div class="jumbotron">
<h3>JSONPath evaluator</h3>
</div>
<h3>JSONPath evaluator</h3>
<div class="row">
<div class="col-md-6">
<form method="post">
<form id="form">
<div class="form-group">
<select id="templates" name="template" class="form-control" onChange='window.location="?template=" + this.value;'>
{{#templates}}
<option value="{{value}}" {{selected}}>{{name}}</option>
{{/templates}}
<select id="selTemplates" name="template" class="form-control">
<option value="blank"></option>
<option value="goessner">goessner</option>
<option value="twitter">twitter</option>
<option value="webapp">webapp</option>
<option value="20k">20k</option>
</select>
</div>
<div class="form-group">
<textarea id="json" name="json" rows="20" class="form-control">{{json}}</textarea>
</div>
<div class="radio">
<label>
<input type="radio" name="type" id="optTypeValue" value="value" {{value-checked}} />
Matching values
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="type" id="optTypePath" value="path" {{path-checked}} />
Normalized path expressions
</label>
<textarea id="txtJson" name="json" rows="15" class="form-control" placeholder="Select a template above or enter JSON"></textarea>
</div>
<div class="input-group">
<input id="path" name="path" value="{{path}}" placeholder="Enter path" class="form-control"/>
<input id="txtPath" name="path" value="{{path}}" placeholder="Enter path" class="form-control"/>
<span class="input-group-btn">
<button class="btn btn-default" type="submit">Go!</button>
<button id="submit" class="btn btn-default" type="button">Go!</button>
</span>
</div>
<br/>
<div class="row">
<div class="col-md-6">
<fieldset>
<legend>Result options</legend>
<div class="radio">
<label>
<input type="radio" name="rbType" value="VALUE" checked/>
Matching values
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="rbType" value="PATH"/>
Normalized path expressions
</label>
</div>
</fieldset>
</div>
<div class="col-md-6">
<fieldset>
<legend>Jayway options</legend>
<div class="checkbox">
<label>
<input type="checkbox" name="flagWrap" id="cbFlagWrap" />
Always return result as list
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="flagMerge" id="cbFlagMerge" />
Merge multi props to new object
</label>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="flagSuppress" id="cbFlagSuppress" />
Suppress exceptions
</label>
</div>
</fieldset>
</div>
</div>
</form>
</div>
<div class="col-md-6">
<ul id="tabs" class="nav nav-tabs" data-tabs="tabs">
<li class="active"><a href="#jayway" data-toggle="tab">Jayway</a></li>
<li><a href="#boon" data-toggle="tab">Boon</a></li>
<li><a href="#nebhale" data-toggle="tab">Nebhale</a></li>
<li><a href="#goessner" data-toggle="tab">Gossner</a></li>
<li class="active"><a href="#jayway-tab" data-toggle="tab">Jayway</a></li>
<li><a href="#boon-tab" data-toggle="tab">Boon</a></li>
<li><a href="#nebhale-tab" data-toggle="tab">Nebhale</a></li>
<li><a href="#goessner-tab" data-toggle="tab">Gossner</a></li>
</ul>
<div id="my-tab-content" class="tab-content">
{{#results}}
<div class="tab-pane {{active}}" id="{{provider}}">
<br/>
<span id="{{provider}}-time">{{time}}</span>&nbsp;millis
<hr/>
{{^error}}
<div class="row">
<div class="col-md-12">
<pre class="prettyprint" style="background-color: transparent; border: none;">{{result}}</pre>
</div>
<div class="tab-pane active" id="jayway-tab">
<br/>
<span id="jayway-time"></span>&nbsp;millis
<hr/>
<div class="row">
<div class="col-md-12">
<pre id="jayway-res" class="prettyprint" style="background-color: transparent; border: none;"></pre>
</div>
</div>
<p id="jayway-error" class="bg-danger"></p>
</div>
<div class="tab-pane" id="boon-tab">
<br/>
<span id="boon-time"></span>&nbsp;millis
<hr/>
<div class="row">
<div class="col-md-12">
<pre id="boon-res" class="prettyprint" style="background-color: transparent; border: none;"></pre>
</div>
{{/error}}
{{#error}}
<p class="bg-danger">{{error}}</p>
{{/error}}
</div>
{{/results}}
<div class="tab-pane" id="goessner">
<p id="boon-error" class="bg-danger"></p>
</div>
<div class="tab-pane" id="nebhale-tab">
<br/>
<span id="nebhale-time"></span>&nbsp;millis
<hr/>
<div class="row">
<div class="col-md-12">
<pre id="nebhale-res" class="prettyprint" style="background-color: transparent; border: none;"></pre>
</div>
</div>
<p id="nebhale-error" class="bg-danger"></p>
</div>
<div class="tab-pane" id="goessner-tab">
<br/>
<span id="goessner-time"></span>&nbsp;millis
<hr/>
@ -88,31 +147,87 @@
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
$( document ).ready(function() {
if( $('#jayway').length )
{
//var value = $("#optTypeValue").prop("checked", true);
var value = $("#optTypeValue").is(':checked');
var start = new Date().getTime();
var json = JSON.parse($('#json').val());
var path = $('#path').val();
var res = '';
if(value){
res = jsonPath(json, path, {resultType:"VALUE"});
} else {
res = jsonPath(json, path, {resultType:"PATH"});
$('#selTemplates').on('change', function() {
var val = this.value;
$.ajax({
url: "/templates/" + val,
success: function(data){
if(data){
data = JSON.stringify(data, null, ' ');
}
$("#txtJson").val(data);
}
});
});
$('#submit').on('click', function() {
var json = $('#txtJson').val();
var path = $('#txtPath').val();
var data = {
json: json,
path: path,
type: $('input[name=rbType]:checked', '#form').val(),
flagWrap: $('#cbFlagWrap').prop('checked'),
flagMerge: $('#cbFlagMerge').prop('checked'),
flagSuppress: $('#cbFlagSuppress').prop('checked')
}
var elapsed = new Date().getTime() - start;
console.log(data);
$.ajax({
url: "/eval",
type: 'POST',
dataType: 'json',
data: data,
success: function(data) {
$('#jayway-time').text(data.jayway.time);
$('#jayway-res').text(data.jayway.result).effect( "highlight", {color: '#428bca'} );
if(data.jayway.error){
$('#jayway-error').text(data.jayway.error).show();
} else {
$('#jayway-error').css( "display", "none")
}
$('#boon-time').text(data.boon.time);
$('#boon-res').text(data.boon.result).effect( "highlight", {color: '#428bca'} );
if(data.boon.error){
$('#boon-error').text(data.boon.error).show();
} else {
$('#boon-error').css( "display", "none")
}
$('#nebhale-time').text(data.nebhale.time);
$('#nebhale-res').text(data.nebhale.result).effect( "highlight", {color: '#428bca'} );
if(data.nebhale.error){
$('#nebhale-error').text(data.nebhale.error).show();
} else {
$('#nebhale-error').css( "display", "none")
}
var start = new Date().getTime();
var res = jsonPath(JSON.parse(json), path, {resultType: $('input[name=rbType]:checked', '#form').val() });
var elapsed = new Date().getTime() - start;
$("#goessner-time").text(elapsed);
$("#goessner-res").text(JSON.stringify(res, null, ' '));
$('.prettyprinted').removeClass('prettyprinted');
prettyPrint();
}
});
});
$("#goessner-time").html(elapsed);
$("#goessner-res").text(JSON.stringify(res, null, ' '));
}
});
</script>
</html>

29
json-path/src/main/java/com/jayway/jsonpath/JsonPath.java

@ -165,9 +165,36 @@ public class JsonPath {
* @param <T> expected return type
* @return object(s) matched by the given path
*/
public <T> T read(Object jsonObject, Configuration configuration) {
return (T)path.evaluate(jsonObject, configuration).getWithOptions();
boolean optAsPathList = configuration.getOptions().contains(Option.AS_PATH_LIST);
boolean optAlwaysReturnList = configuration.getOptions().contains(Option.ALWAYS_RETURN_LIST);
boolean optSuppressExceptions = configuration.getOptions().contains(Option.SUPPRESS_EXCEPTIONS);
boolean optThrowOnMissingProperty = configuration.getOptions().contains(Option.THROW_ON_MISSING_PROPERTY);
Object result = null;
try {
result = path.evaluate(jsonObject, configuration).getWithOptions();
} catch (RuntimeException e){
if(optThrowOnMissingProperty || (!optThrowOnMissingProperty && !optSuppressExceptions)){
throw e;
} else {
if(optSuppressExceptions){
if(path.isDefinite() && !optAlwaysReturnList && !optAsPathList){
result = null;
} else {
result = configuration.getProvider().createArray();
}
}
}
}
return (T)result;
}
/*
public <T> T read(Object jsonObject, Configuration configuration) {
return (T)path.evaluate(jsonObject, configuration).getWithOptions();
}*/
/**
* Applies this JsonPath to the provided json string

11
json-path/src/main/java/com/jayway/jsonpath/Option.java

@ -34,7 +34,16 @@ public enum Option {
/**
* When multiple properties are queried eg @..['foo', 'bar'] these properties are extracted and put in a new Map.
*/
MERGE_MULTI_PROPS
MERGE_MULTI_PROPS,
/**
* Suppress all exceptions when evaluating path.
* <br/>
* If an exception is thrown and the option {@link Option#ALWAYS_RETURN_LIST} an empty list is returned.
* If an exception is thrown and the option {@link Option#ALWAYS_RETURN_LIST} is not present null is returned.
* The option {@link Option#THROW_ON_MISSING_PROPERTY} has precedence over this option.
*/
SUPPRESS_EXCEPTIONS
}

9
json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/EvaluationContextImpl.java

@ -59,8 +59,10 @@ class EvaluationContextImpl implements EvaluationContext {
@Override
public Object getWithOptions() {
if(configuration.getOptions().contains(Option.AS_PATH_LIST)) {
boolean optAsPathList = configuration.getOptions().contains(Option.AS_PATH_LIST);
boolean optAlwaysReturnList = configuration.getOptions().contains(Option.ALWAYS_RETURN_LIST);
if (optAsPathList) {
Object array = configuration.getProvider().createArray();
int i = 0;
for (String p : pathResult) {
@ -68,11 +70,8 @@ class EvaluationContextImpl implements EvaluationContext {
i++;
}
return array;
} else if(configuration.getOptions().contains(Option.ALWAYS_RETURN_LIST)){
} else if (optAlwaysReturnList) {
return objectResult;
} else {
return get();
}

Loading…
Cancel
Save