Browse Source

Added option to Suppress exceptions.

pull/41/head
Kalle Stenflo 11 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 scala.collection.Iterator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import static java.util.Arrays.asList;
public class Bench { public class Bench {
protected final String json; protected final String json;
protected final String path; protected final String path;
private final boolean optionAsValues; private final boolean optionAsValues;
private final boolean optionAllwaysReturnList; private final boolean flagWrap;
private final boolean optionMergeMultiProps; 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.json = json;
this.path = path; this.path = path;
this.optionAsValues = optionAsValues; this.optionAsValues = optionAsValues;
this.optionAllwaysReturnList = optionAllwaysReturnList; this.flagWrap = flagWrap;
this.optionMergeMultiProps = optionMergeMultiProps; this.flagMerge = flagMerge;
this.flagSuppress = flagSuppress;
} }
public Result runJayway() { public Result runJayway() {
@ -41,12 +43,15 @@ public class Bench {
Configuration configuration = Configuration.defaultConfiguration(); Configuration configuration = Configuration.defaultConfiguration();
if(optionAllwaysReturnList){ if(flagWrap){
configuration = configuration.addOptions(Option.ALWAYS_RETURN_LIST); configuration = configuration.addOptions(Option.ALWAYS_RETURN_LIST);
} }
if(optionMergeMultiProps){ if(flagMerge){
configuration = configuration.addOptions(Option.MERGE_MULTI_PROPS); configuration = configuration.addOptions(Option.MERGE_MULTI_PROPS);
} }
if(flagSuppress){
configuration = configuration.addOptions(Option.SUPPRESS_EXCEPTIONS);
}
if (!optionAsValues) { if (!optionAsValues) {
configuration = configuration.addOptions(Option.AS_PATH_LIST); configuration = configuration.addOptions(Option.AS_PATH_LIST);
} }
@ -129,8 +134,12 @@ public class Bench {
} }
} }
public List<Result> runAll() { public Map<String, Result> runAll() {
return asList(runJayway(), runBoon(), runNebhale()); 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) { 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 class Result {
public final String provider; public final String provider;
public final String active;
public final long time; public final long time;
public final String result; public final String result;
public final String error; public final String error;
public Result(String provider, long time, String result, String error) { public Result(String provider, long time, String result, String error) {
this.provider = provider; this.provider = provider;
this.active = provider == "jayway" ? "active" : "";
this.time = time; this.time = time;
this.result = result != null ? JsonFormatter.prettyPrint(result) : result; this.result = result != null ? JsonFormatter.prettyPrint(result) : result;
this.error = error; 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.GET;
import javax.ws.rs.POST; import javax.ws.rs.POST;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam; import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -23,7 +25,7 @@ import java.util.Map;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
@Path("") @Path("/")
@Produces(MediaType.TEXT_HTML) @Produces(MediaType.TEXT_HTML)
public class IndexResource { public class IndexResource {
@ -32,22 +34,38 @@ public class IndexResource {
public final static Map<String, String> TEMPLATES = loadTemplates(); public final static Map<String, String> TEMPLATES = loadTemplates();
@GET @GET
public Viewable get(@QueryParam("template") @DefaultValue("goessner") String template){ @Path("templates/{template}")
return createView(TEMPLATES.get(template), "$.store.book[0].title", true, template, null); @Produces(MediaType.APPLICATION_JSON)
public Response getTemplate(@PathParam("template") @DefaultValue("goessner") String template){
return Response.ok(TEMPLATES.get(template)).build();
} }
@POST @POST
@Path("eval")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Viewable post(@FormParam("json") String json, @Produces(MediaType.APPLICATION_JSON)
@FormParam("path") String path, public Response getTemplate(@FormParam("json") String json,
@FormParam("type") String type, @FormParam("path") String path,
@FormParam("template") String template){ @FormParam("type") String type,
@FormParam("flagWrap") boolean flagWrap,
@FormParam("flagMerge") boolean flagMerge,
@FormParam("flagSuppress") boolean flagSuppress ){
boolean value = "VALUE".equalsIgnoreCase(type); 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){ private Viewable createView(String json, String path, boolean value, String selectedTemplate, List<Result> results){
Map<String, Object> res = new HashMap<String, Object>(); Map<String, Object> res = new HashMap<String, Object>();
res.put("results", results); res.put("results", results);
@ -70,6 +88,7 @@ public class IndexResource {
String twentyK = IOUtils.toString(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/20k.json")); String twentyK = IOUtils.toString(Thread.currentThread().getContextClassLoader().getResourceAsStream("json/20k.json"));
Map<String, String> templates = new HashMap<String, String>(); Map<String, String> templates = new HashMap<String, String>();
templates.put("blank", "null");
templates.put("goessner", goessner); templates.put("goessner", goessner);
templates.put("twitter", twitter); templates.put("twitter", twitter);
templates.put("webapp", webapp); templates.put("webapp", webapp);

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

@ -6,79 +6,138 @@
<title>JsonPath</title> <title>JsonPath</title>
<link rel="stylesheet" href="/static/css/bootstrap.css"> <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="//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/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/jsonpath-0.8.0.js"></script>
<script type="text/javascript" src="/static/js/bootstrap.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> </head>
<body role="document"> <body role="document">
<div class="container"> <div class="container">
<div class="jumbotron"> <h3>JSONPath evaluator</h3>
<h3>JSONPath evaluator</h3>
</div>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<form method="post"> <form id="form">
<div class="form-group"> <div class="form-group">
<select id="templates" name="template" class="form-control" onChange='window.location="?template=" + this.value;'> <select id="selTemplates" name="template" class="form-control">
{{#templates}} <option value="blank"></option>
<option value="{{value}}" {{selected}}>{{name}}</option> <option value="goessner">goessner</option>
{{/templates}} <option value="twitter">twitter</option>
<option value="webapp">webapp</option>
<option value="20k">20k</option>
</select> </select>
</div> </div>
<div class="form-group"> <div class="form-group">
<textarea id="json" name="json" rows="20" class="form-control">{{json}}</textarea> <textarea id="txtJson" name="json" rows="15" class="form-control" placeholder="Select a template above or enter 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>
</div> </div>
<div class="input-group"> <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"> <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> </span>
</div> </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> </form>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<ul id="tabs" class="nav nav-tabs" data-tabs="tabs"> <ul id="tabs" class="nav nav-tabs" data-tabs="tabs">
<li class="active"><a href="#jayway" data-toggle="tab">Jayway</a></li> <li class="active"><a href="#jayway-tab" data-toggle="tab">Jayway</a></li>
<li><a href="#boon" data-toggle="tab">Boon</a></li> <li><a href="#boon-tab" data-toggle="tab">Boon</a></li>
<li><a href="#nebhale" data-toggle="tab">Nebhale</a></li> <li><a href="#nebhale-tab" data-toggle="tab">Nebhale</a></li>
<li><a href="#goessner" data-toggle="tab">Gossner</a></li> <li><a href="#goessner-tab" data-toggle="tab">Gossner</a></li>
</ul> </ul>
<div id="my-tab-content" class="tab-content"> <div id="my-tab-content" class="tab-content">
{{#results}}
<div class="tab-pane {{active}}" id="{{provider}}"> <div class="tab-pane active" id="jayway-tab">
<br/> <br/>
<span id="{{provider}}-time">{{time}}</span>&nbsp;millis <span id="jayway-time"></span>&nbsp;millis
<hr/> <hr/>
{{^error}} <div class="row">
<div class="row"> <div class="col-md-12">
<div class="col-md-12"> <pre id="jayway-res" class="prettyprint" style="background-color: transparent; border: none;"></pre>
<pre class="prettyprint" style="background-color: transparent; border: none;">{{result}}</pre> </div>
</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> </div>
{{/error}}
{{#error}}
<p class="bg-danger">{{error}}</p>
{{/error}}
</div> </div>
{{/results}} <p id="boon-error" class="bg-danger"></p>
<div class="tab-pane" id="goessner"> </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/> <br/>
<span id="goessner-time"></span>&nbsp;millis <span id="goessner-time"></span>&nbsp;millis
<hr/> <hr/>
@ -88,31 +147,87 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</body> </body>
<script> <script>
$( document ).ready(function() { $( document ).ready(function() {
if( $('#jayway').length ) $('#selTemplates').on('change', function() {
{ var val = this.value;
//var value = $("#optTypeValue").prop("checked", true); $.ajax({
var value = $("#optTypeValue").is(':checked'); url: "/templates/" + val,
var start = new Date().getTime(); success: function(data){
var json = JSON.parse($('#json').val()); if(data){
var path = $('#path').val(); data = JSON.stringify(data, null, ' ');
var res = ''; }
if(value){ $("#txtJson").val(data);
res = jsonPath(json, path, {resultType:"VALUE"}); }
} else { });
res = jsonPath(json, path, {resultType:"PATH"}); });
$('#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> </script>
</html> </html>

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

@ -165,9 +165,36 @@ public class JsonPath {
* @param <T> expected return type * @param <T> expected return type
* @return object(s) matched by the given path * @return object(s) matched by the given path
*/ */
public <T> T read(Object jsonObject, Configuration configuration) { 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 * 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. * 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 @Override
public Object getWithOptions() { 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(); Object array = configuration.getProvider().createArray();
int i = 0; int i = 0;
for (String p : pathResult) { for (String p : pathResult) {
@ -68,11 +70,8 @@ class EvaluationContextImpl implements EvaluationContext {
i++; i++;
} }
return array; return array;
} else if (optAlwaysReturnList) {
} else if(configuration.getOptions().contains(Option.ALWAYS_RETURN_LIST)){
return objectResult; return objectResult;
} else { } else {
return get(); return get();
} }

Loading…
Cancel
Save