Browse Source

Option handling improved.

pull/41/head
Kalle Stenflo 10 years ago
parent
commit
8da4d1a1d6
  1. 4
      json-path-web-test/src/main/resources/css/font-awesome.min.css
  2. 34
      json-path-web-test/src/main/resources/html/index.html
  3. 2
      json-path-web-test/src/main/resources/js/prettify.js
  4. 4
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  5. 37
      json-path/src/main/java/com/jayway/jsonpath/JsonPath.java
  6. 53
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/EvaluationContextImpl.java
  7. 5
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/PathCompiler.java
  8. 50
      json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/PathToken.java
  9. 14
      json-path/src/main/java/com/jayway/jsonpath/spi/compiler/EvaluationContext.java
  10. 4
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java
  11. 4
      json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java
  12. 4
      json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java
  13. 6
      json-path/src/test/java/com/jayway/jsonpath/internal/TestInternal3.java
  14. 2
      json-path/src/test/java/com/jayway/jsonpath/reader/ReadConfigurationTest.java

4
json-path-web-test/src/main/resources/css/font-awesome.min.css vendored

File diff suppressed because one or more lines are too long

34
json-path-web-test/src/main/resources/html/index.html

@ -4,9 +4,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>JSONPath evaluator</title> <title>JSONPath evaluator</title>
<link href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" rel="stylesheet">
<link rel="stylesheet" href="/css/bootstrap.min.css"> <link rel="stylesheet" href="/css/bootstrap.min.css">
<link rel="stylesheet" href="/css/prettify.css"> <link rel="stylesheet" href="/css/prettify.css">
<link rel="stylesheet" href="/css/font-awesome.min.css">
<script type="text/javascript" src="/js/prettify.js"></script> <script type="text/javascript" src="/js/prettify.js"></script>
<script type="text/javascript" src="/js/jquery.min.js"></script> <script type="text/javascript" src="/js/jquery.min.js"></script>
@ -21,9 +21,9 @@
<div class="form-group"> <div class="form-group">
<select id="selTemplates" name="template" class="form-control"> <select id="selTemplates" name="template" class="form-control">
<option value="blank"></option> <option value="blank"></option>
<option value="goessner.json">goessner</option> <option value="goessner.json">Goessner examle</option>
<option value="twitter.json">twitter</option> <option value="twitter.json">Twitter API</option>
<option value="webxml.json">webapp</option> <option value="webxml.json">Webapp</option>
<option value="20k.json">20k</option> <option value="20k.json">20k</option>
</select> </select>
</div> </div>
@ -33,7 +33,7 @@
</div> </div>
<div class="input-group"> <div class="input-group">
<span id="path-status-tool" class="input-group-addon" data-toggle="tooltip" data-placement="top" title="Invalid path"><span id="path-status" class="glyphicon glyphicon-ban-circle"></span></span> <span id="path-status-tool" class="input-group-addon" data-toggle="tooltip" data-placement="top" title="Invalid path"><span id="path-status" class="fa fa-ban"></span></span>
<input id="txtPath" name="path" placeholder="Enter path" autocomplete="off" class="form-control"/> <input id="txtPath" name="path" placeholder="Enter path" autocomplete="off" class="form-control"/>
<span class="input-group-btn"> <span class="input-group-btn">
<button id="submit" class="btn btn-primary" type="button">Go!</button> <button id="submit" class="btn btn-primary" type="button">Go!</button>
@ -45,7 +45,7 @@
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<fieldset> <fieldset>
<legend>Result options</legend> <legend>JSONPath options</legend>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" name="rbType" value="VALUE" checked/> <input type="radio" name="rbType" value="VALUE" checked/>
@ -66,20 +66,20 @@
<legend>Jayway options</legend> <legend>Jayway options</legend>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="flagWrap" id="cbFlagWrap" /> <input type="checkbox" name="flagSuppress" id="cbFlagSuppress" />
Always return result as list Suppress exceptions
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="flagMerge" id="cbFlagMerge" /> <input type="checkbox" name="flagWrap" id="cbFlagWrap" />
Merge multi props to new object Always return result list
</label> </label>
</div> </div>
<div class="checkbox"> <div class="checkbox">
<label> <label>
<input type="checkbox" name="flagSuppress" id="cbFlagSuppress" /> <input type="checkbox" name="flagMerge" id="cbFlagMerge" />
Suppress exceptions Merge multi props to new object
</label> </label>
</div> </div>
</fieldset> </fieldset>
@ -185,25 +185,25 @@
var pathString = $("#txtPath").val(); var pathString = $("#txtPath").val();
var updateDisplay = function(icon, tooltip){ var updateDisplay = function(icon, tooltip){
$('#path-status').removeClass().addClass('glyphicon ' + icon); $('#path-status').removeClass().addClass('fa ' + icon);
$('#path-status-tool').attr('data-original-title', tooltip).tooltip('fixTitle'); $('#path-status-tool').attr('data-original-title', tooltip).tooltip('fixTitle');
}; };
if(pathString.length ==0){ if(pathString.length ==0){
updateDisplay('glyphicon-ban-circle', 'Invalid path'); updateDisplay('fa-ban', 'Invalid path');
return; return;
} }
$.get('/api/validate/?path=' + pathString, function(data) { $.get('/api/validate/?path=' + pathString, function(data) {
if(data){ if(data){
if(data.result === -1){ if(data.result === -1){
updateDisplay('glyphicon-ban-circle', 'Invalid path'); updateDisplay('fa-ban', 'Invalid path');
} }
else if(data.result === 0){ else if(data.result === 0){
updateDisplay('glyphicon-record', 'Path is definite'); updateDisplay('fa-bullseye', 'Path is definite');
} }
else if(data.result === 1){ else if(data.result === 1){
updateDisplay('glyphicon-align-justify', 'Path is indefinite'); updateDisplay('fa-navicon', 'Path is indefinite');
} }
} }
}); });

2
json-path-web-test/src/main/resources/js/prettify.js

@ -16,7 +16,7 @@
a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g, a.a=b;a.d=g.d;a.e=0;I(d,b)(a);var s=/\bMSIE\s(\d+)/.exec(navigator.userAgent),s=s&&+s[1]<=8,d=/\n/g,x=a.a,m=x.length,g=0,j=a.d,k=j.length,b=0,c=a.g,i=c.length,r=0;c[i]=m;var n,e;for(e=n=0;e<i;)c[e]!==c[e+2]?(c[n++]=c[e++],c[n++]=c[e++]):e+=2;i=n;for(e=n=0;e<i;){for(var p=c[e],w=c[e+1],t=e+2;t+2<=i&&c[t+1]===w;)t+=2;c[n++]=p;c[n++]=w;e=t}c.length=n;var f=a.c,h;if(f)h=f.style.display,f.style.display="none";try{for(;b<k;){var l=j[b+2]||m,B=c[r+2]||m,t=Math.min(l,B),A=j[b+1],G;if(A.nodeType!==1&&(G=x.substring(g,
t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], t))){s&&(G=G.replace(d,"\r"));A.nodeValue=G;var L=A.ownerDocument,o=L.createElement("span");o.className=c[r+1];var v=A.parentNode;v.replaceChild(o,A);o.appendChild(A);g<l&&(j[b+1]=A=L.createTextNode(x.substring(t,l)),v.insertBefore(A,o.nextSibling))}g=t;g>=l&&(b+=2);g>=B&&(r+=2)}}finally{if(f)f.style.display=h}}catch(u){D.console&&console.log(u&&u.stack||u)}}var D=window,y=["break,continue,do,else,for,if,return,while"],E=[[y,"auto,case,char,const,default,double,enum,extern,float,goto,inline,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"], "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],M=[E,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,delegate,dynamic_cast,explicit,export,friend,generic,late_check,mutable,namespace,nullptr,property,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],N=[E,"abstract,assert,boolean,byte,extends,final,finally,implements,import,instanceof,interface,null,native,package,strictfp,super,synchronized,throws,transient"],
O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], O=[N,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,internal,into,is,let,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var,virtual,where"],E=[E,"debugger,eval,export,function,getValue,null,set,undefined,var,with,Infinity,NaN"],P=[y,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/, Q=[y,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],W=[y,"as,assert,const,copy,drop,enum,extern,fail,false,fn,impl,let,log,loop,match,mod,move,mut,priv,pub,pure,ref,self,static,struct,true,trait,type,unsafe,use"],y=[y,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],R=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)\b/,
V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-", V=/\S/,X=v({keywords:[M,O,E,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",P,Q,y],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),F={};p(X,["default-code"]);p(C([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",
/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/], /^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);p(C([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],

4
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -272,7 +272,7 @@ public class Criteria implements Predicate {
if (CriteriaType.EXISTS == criteriaType) { if (CriteriaType.EXISTS == criteriaType) {
boolean exists = ((Boolean) expected); boolean exists = ((Boolean) expected);
try { try {
path.evaluate(model, configuration.options(Option.THROW_ON_MISSING_PROPERTY)).get(); path.evaluate(model, configuration.options(Option.THROW_ON_MISSING_PROPERTY)).getValue();
return exists == true; return exists == true;
} catch (PathNotFoundException e) { } catch (PathNotFoundException e) {
return exists == false; return exists == false;
@ -280,7 +280,7 @@ public class Criteria implements Predicate {
} else { } else {
try { try {
final Object actual = path.evaluate(model, configuration).get(); final Object actual = path.evaluate(model, configuration).getValue();
return criteriaType.eval(expected, actual, configuration); return criteriaType.eval(expected, actual, configuration);
} catch (CompareException e) { } catch (CompareException e) {
return false; return false;

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

@ -172,29 +172,36 @@ public class JsonPath {
boolean optSuppressExceptions = configuration.getOptions().contains(Option.SUPPRESS_EXCEPTIONS); boolean optSuppressExceptions = configuration.getOptions().contains(Option.SUPPRESS_EXCEPTIONS);
boolean optThrowOnMissingProperty = configuration.getOptions().contains(Option.THROW_ON_MISSING_PROPERTY); boolean optThrowOnMissingProperty = configuration.getOptions().contains(Option.THROW_ON_MISSING_PROPERTY);
Object result = null;
try { try {
result = path.evaluate(jsonObject, configuration).getWithOptions(); if(optAsPathList){
return (T)path.evaluate(jsonObject, configuration).getPath();
} else {
Object res = path.evaluate(jsonObject, configuration).getValue();
if(optAlwaysReturnList && path.isDefinite()){
Object array = configuration.getProvider().createArray();
configuration.getProvider().setProperty(array, 0, res);
return (T)array;
} else {
return (T)res;
}
}
} catch (RuntimeException e){ } catch (RuntimeException e){
if(optThrowOnMissingProperty || (!optThrowOnMissingProperty && !optSuppressExceptions)){ if(optThrowOnMissingProperty || !optSuppressExceptions){
throw e; throw e;
}
}
if(optAsPathList){
return (T)configuration.getProvider().createArray();
} else {
if(optAlwaysReturnList){
return (T)configuration.getProvider().createArray();
} else { } else {
if(optSuppressExceptions){ return (T)(path.isDefinite() ? null : configuration.getProvider().createArray());
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

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

@ -2,11 +2,13 @@ package com.jayway.jsonpath.internal.spi.compiler;
import com.jayway.jsonpath.Configuration; import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.Option; import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.spi.compiler.EvaluationContext; import com.jayway.jsonpath.spi.compiler.EvaluationContext;
import com.jayway.jsonpath.spi.compiler.Path; import com.jayway.jsonpath.spi.compiler.Path;
import com.jayway.jsonpath.spi.json.JsonProvider; import com.jayway.jsonpath.spi.json.JsonProvider;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -16,22 +18,21 @@ import java.util.Set;
class EvaluationContextImpl implements EvaluationContext { class EvaluationContextImpl implements EvaluationContext {
private final Configuration configuration; private final Configuration configuration;
private final Object objectResult; private final Object valueResult;
private final List<String> pathResult; private final Object pathResult;
private final Path path; private final Path path;
private int resultIndex = 0; private int resultIndex = 0;
EvaluationContextImpl(Path path, Configuration configuration) { EvaluationContextImpl(Path path, Configuration configuration) {
this.path = path; this.path = path;
this.configuration = configuration; this.configuration = configuration;
this.objectResult = configuration.getProvider().createArray(); this.valueResult = configuration.getProvider().createArray();
this.pathResult = new ArrayList<String>(); this.pathResult = configuration.getProvider().createArray();
} }
void addResult(String path, Object model) { void addResult(String path, Object model) {
pathResult.add(path); configuration.getProvider().setProperty(valueResult, resultIndex, model);
configuration.getProvider().setProperty(objectResult, resultIndex, model); configuration.getProvider().setProperty(pathResult, resultIndex, path);
resultIndex++; resultIndex++;
} }
@ -50,36 +51,34 @@ class EvaluationContextImpl implements EvaluationContext {
@Override @Override
public <T> T get() { public <T> T getValue() {
if (path.isDefinite()) { if (path.isDefinite()) {
return (T) jsonProvider().getArrayIndex(objectResult, 0); if(resultIndex == 0){
throw new PathNotFoundException("No results for path: " + path.toString());
}
return (T) jsonProvider().getArrayIndex(valueResult, 0);
} }
return (T) objectResult; return (T) valueResult;
} }
@Override @Override
public Object getWithOptions() { public <T> T getPath() {
boolean optAsPathList = configuration.getOptions().contains(Option.AS_PATH_LIST); if(resultIndex == 0){
boolean optAlwaysReturnList = configuration.getOptions().contains(Option.ALWAYS_RETURN_LIST); throw new PathNotFoundException("No results for path: " + path.toString());
if (optAsPathList) {
Object array = configuration.getProvider().createArray();
int i = 0;
for (String p : pathResult) {
configuration.getProvider().setProperty(array, i, p);
i++;
}
return array;
} else if (optAlwaysReturnList) {
return objectResult;
} else {
return get();
} }
return (T)pathResult;
} }
@Override @Override
public List<String> getPathList() { public List<String> getPathList() {
return pathResult; List<String> res = new ArrayList<String>();
if(resultIndex > 0){
Iterable<Object> objects = configuration.getProvider().toIterable(pathResult);
for (Object o : objects) {
res.add((String)o);
}
}
return res;
} }
} }

5
json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/PathCompiler.java

@ -28,6 +28,7 @@ public class PathCompiler {
private static final char PERIOD = '.'; private static final char PERIOD = '.';
private static final char BRACKET_OPEN = '['; private static final char BRACKET_OPEN = '[';
private static final char BRACKET_CLOSE = ']'; private static final char BRACKET_CLOSE = ']';
private static final char SPACE = ' ';
private static final Cache cache = new Cache(200); private static final Cache cache = new Cache(200);
@ -60,6 +61,8 @@ public class PathCompiler {
char current = chars[i]; char current = chars[i];
switch (current) { switch (current) {
case SPACE:
throw new InvalidPathException("Space not allowed in path");
case DOCUMENT: case DOCUMENT:
fragment = "$"; fragment = "$";
i++; i++;
@ -132,7 +135,7 @@ public class PathCompiler {
int skipCount = 0; int skipCount = 0;
while (index < chars.length) { while (index < chars.length) {
char current = chars[index]; char current = chars[index];
if (current == PERIOD || current == BRACKET_OPEN) { if (current == PERIOD || current == BRACKET_OPEN || current == SPACE) {
break; break;
} }
index++; index++;

50
json-path/src/main/java/com/jayway/jsonpath/internal/spi/compiler/PathToken.java

@ -24,39 +24,41 @@ abstract class PathToken {
String property = properties.get(0); String property = properties.get(0);
String evalPath = currentPath + "['" + property + "']"; String evalPath = currentPath + "['" + property + "']";
Object propertyVal = readObjectProperty(property, model, ctx); Object propertyVal = readObjectProperty(property, model, ctx);
if(propertyVal == JsonProvider.UNDEFINED){
return;
}
if (isLeaf()) { if (isLeaf()) {
ctx.addResult(evalPath, propertyVal); ctx.addResult(evalPath, propertyVal);
} else { } else {
next().evaluate(evalPath, propertyVal, ctx); next().evaluate(evalPath, propertyVal, ctx);
} }
} else { } else {
if(ctx.configuration().getOptions().contains(Option.MERGE_MULTI_PROPS)) { String evalPath = currentPath + "[" + Utils.join(", ", "'", properties) + "]";
String evalPath = currentPath + "[" + Utils.join(", ", "'", properties) + "]"; if (!isLeaf()) {
if (!isLeaf()) { throw new InvalidPathException("Multi properties can only be used as path leafs: " + evalPath);
throw new InvalidPathException("Multi properties can only be used as path leafs: " + evalPath); }
} else {
Object map = ctx.jsonProvider().createMap(); if(ctx.configuration().getOptions().contains(Option.MERGE_MULTI_PROPS)) {
for (String property : properties) { Object map = ctx.jsonProvider().createMap();
if(hasProperty(property, model, ctx)) { for (String property : properties) {
Object propertyVal = readObjectProperty(property, model, ctx); Object propertyVal = readObjectProperty(property, model, ctx);
ctx.jsonProvider().setProperty(map, property, propertyVal); if(propertyVal == JsonProvider.UNDEFINED){
} continue;
} }
ctx.addResult(evalPath, map); ctx.jsonProvider().setProperty(map, property, propertyVal);
} }
ctx.addResult(evalPath, map);
} else { } else {
if (!isLeaf()) { for (String property : properties) {
String evalPath = currentPath + "[" + Utils.join(", ", "'", properties) + "]"; evalPath = currentPath + "['" + property + "']";
throw new InvalidPathException("Multi properties can only be used as path leafs: " + evalPath); if(hasProperty(property, model, ctx)) {
} else { Object propertyVal = readObjectProperty(property, model, ctx);
for (String property : properties) { if(propertyVal == JsonProvider.UNDEFINED){
String evalPath = currentPath + "['" + property + "']"; continue;
if(hasProperty(property, model, ctx)) {
Object propertyVal = readObjectProperty(property, model, ctx);
ctx.addResult(evalPath, propertyVal);
} }
ctx.addResult(evalPath, propertyVal);
} }
} }
} }
@ -68,9 +70,11 @@ abstract class PathToken {
} }
private Object readObjectProperty(String property, Object model, EvaluationContextImpl ctx) { private Object readObjectProperty(String property, Object model, EvaluationContextImpl ctx) {
Object val = ctx.jsonProvider().getMapValue(model, property, ctx.options().contains(Option.THROW_ON_MISSING_PROPERTY)); Object val = ctx.jsonProvider().getMapValue(model, property, true);
if(val == JsonProvider.UNDEFINED){ if(val == JsonProvider.UNDEFINED){
throw new PathNotFoundException("Property ['" + property + "'] not found in the current context" ); if(ctx.options().contains(Option.THROW_ON_MISSING_PROPERTY)) {
throw new PathNotFoundException("Property ['" + property + "'] not found in the current context");
}
} }
return val; return val;
} }

14
json-path/src/main/java/com/jayway/jsonpath/spi/compiler/EvaluationContext.java

@ -19,17 +19,11 @@ public interface EvaluationContext {
* @param <T> expected return type * @param <T> expected return type
* @return evaluation result * @return evaluation result
*/ */
<T> T get(); <T> T getValue();
<T> T getPath();
/**
* This method does adhere to configuration settings like
*
* {@link com.jayway.jsonpath.Option#ALWAYS_RETURN_LIST}
* {@link com.jayway.jsonpath.Option#AS_PATH_LIST}
*
* @return evaluation result
*/
Object getWithOptions();
/** /**
* Convenience method to get list of hits as String path representations * Convenience method to get list of hits as String path representations

4
json-path/src/test/java/com/jayway/jsonpath/FilterTest.java

@ -392,7 +392,7 @@ public class FilterTest {
Filter customFilter = new Filter.FilterAdapter<Map<String, Object>>() { Filter customFilter = new Filter.FilterAdapter<Map<String, Object>>() {
@Override @Override
public boolean apply(check, confMap<String, Object> map) { public boolean apply(check, confMap<String, Object> map) {
if (map.get("name").equals("rootGrandChild_A")) { if (map.getValue("name").equals("rootGrandChild_A")) {
return true; return true;
} }
return false; return false;
@ -427,7 +427,7 @@ public class FilterTest {
List<Integer> res = JsonPath.read(doc, "$.items[?]", customFilter); List<Integer> res = JsonPath.read(doc, "$.items[?]", customFilter);
assertEquals(1, res.get(0).intValue()); assertEquals(1, res.getValue(0).intValue());
*/ */
} }

4
json-path/src/test/java/com/jayway/jsonpath/IssuesTest.java

@ -141,8 +141,8 @@ public class IssuesTest {
System.out.println(result); System.out.println(result);
//assertThat(result.get(0), is(new Double(10.1))); //assertThat(result.getValue(0), is(new Double(10.1)));
//assertThat(result.get(1), is(new Double(21.0))); //assertThat(result.getValue(1), is(new Double(21.0)));
} }

4
json-path/src/test/java/com/jayway/jsonpath/JsonPathFilterTest.java

@ -73,7 +73,7 @@ public class JsonPathFilterTest {
Filter customFilter = new Filter.FilterAdapter<Map<String, Object>>() { Filter customFilter = new Filter.FilterAdapter<Map<String, Object>>() {
@Override @Override
public boolean accept(Map<String, Object> map) { public boolean accept(Map<String, Object> map) {
if(map.get("name").equals("rootGrandChild_A")){ if(map.getValue("name").equals("rootGrandChild_A")){
return true; return true;
} }
return false; return false;
@ -109,7 +109,7 @@ public class JsonPathFilterTest {
List<Integer> res = JsonPath.read(doc, "$.items[?]", customFilter); List<Integer> res = JsonPath.read(doc, "$.items[?]", customFilter);
assertEquals(1, res.get(0).intValue()); assertEquals(1, res.getValue(0).intValue());
} }
*/ */

6
json-path/src/test/java/com/jayway/jsonpath/internal/TestInternal3.java

@ -29,7 +29,7 @@ public class TestInternal3 extends TestBase {
@Test @Test
public void a_root_object_can_be_evaluated() { public void a_root_object_can_be_evaluated() {
Map<String, Object> result = tokenize("$").evaluate(DOC, CONF).get(); Map<String, Object> result = tokenize("$").evaluate(DOC, CONF).getValue();
assertThat(result) assertThat(result)
.containsKey("store") .containsKey("store")
@ -39,7 +39,7 @@ public class TestInternal3 extends TestBase {
@Test @Test
public void a_definite_array_item_property_can_be_evaluated() { public void a_definite_array_item_property_can_be_evaluated() {
String result = tokenize("$.store.book[0].author").evaluate(DOC, CONF).get(); String result = tokenize("$.store.book[0].author").evaluate(DOC, CONF).getValue();
assertThat(result).isEqualTo("Nigel Rees"); assertThat(result).isEqualTo("Nigel Rees");
} }
@ -47,7 +47,7 @@ public class TestInternal3 extends TestBase {
@Test @Test
public void a_wildcard_array_item_property_can_be_evaluated() { public void a_wildcard_array_item_property_can_be_evaluated() {
List result = tokenize("$.store.book[*].author").evaluate(DOC, CONF).get(); List result = tokenize("$.store.book[*].author").evaluate(DOC, CONF).getValue();
assertThat(result).containsOnly( assertThat(result).containsOnly(
"Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien"); "Nigel Rees", "Evelyn Waugh", "Herman Melville", "J. R. R. Tolkien");

2
json-path/src/test/java/com/jayway/jsonpath/reader/ReadConfigurationTest.java

@ -34,7 +34,7 @@ public class ReadConfigurationTest {
Object updatedJsonModel = JsonPath.parse("{...}") Object updatedJsonModel = JsonPath.parse("{...}")
.write("$['store'][1]['name']", "new name") .write("$['store'][1]['name']", "new name")
.write("$.store[1].age", 43) .write("$.store[1].age", 43)
.get(); .getValue();
*/ */
} }

Loading…
Cancel
Save