Browse Source

Fixed issues in Filter serialization.

pull/183/merge
Kalle Stenflo 9 years ago
parent
commit
0feb2bcb88
  1. 3
      json-path/src/main/java/com/jayway/jsonpath/Filter.java
  2. 453
      json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java
  3. 12
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ExpressionNode.java
  4. 37
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
  5. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java
  6. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java
  7. 75
      json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java
  8. 17
      json-path/src/test/java/com/jayway/jsonpath/internal/UtilsTest.java

3
json-path/src/main/java/com/jayway/jsonpath/Filter.java

@ -178,8 +178,7 @@ public abstract class Filter implements Predicate {
public static Filter parse(String filter){ public static Filter parse(String filter){
Predicate f = FilterCompiler.compile(filter); return FilterCompiler.compile(filter);
return new SingleFilter(f);
} }

453
json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java

@ -15,54 +15,14 @@
package com.jayway.jsonpath.internal; package com.jayway.jsonpath.internal;
import com.jayway.jsonpath.JsonPathException; import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.ValueCompareException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.StringWriter;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public final class Utils { public final class Utils {
public static final String CR = System.getProperty("line.separator");
private static final char BACKSLASH = '\\';
/**
* Creates a range of integers from start (inclusive) to end (exclusive)
*
* @param start
* @param end
* @return
*/
public static List<Integer> createRange(int start, int end) {
if (end <= start) {
throw new IllegalArgumentException("Cannot create range from " + start + " to " + end + ", end must be greater than start.");
}
if (start == end - 1) {
return Collections.emptyList();
}
List<Integer> range = new ArrayList<Integer>(end - start - 1);
for (int i = start; i < end; i++) {
range.add(i);
}
return range;
}
public static <T> Iterable<T> reverse(final List<T> list) {
return new ListReverser<T>(list);
}
// accept a collection of objects, since all objects have toString() // accept a collection of objects, since all objects have toString()
public static String join(String delimiter, String wrap, Iterable<? extends Object> objs) { public static String join(String delimiter, String wrap, Iterable<? extends Object> objs) {
Iterator<? extends Object> iter = objs.iterator(); Iterator<? extends Object> iter = objs.iterator();
@ -133,81 +93,166 @@ public final class Utils {
} }
} }
//--------------------------------------------------------- public static String escape(String str, boolean escapeSingleQuote) {
//
// Strings
//
//---------------------------------------------------------
public static boolean isInt(String str) {
if (str == null) { if (str == null) {
return false; return null;
} }
int sz = str.length(); int len = str.length();
for (int i = 0; i < sz; i++) { StringWriter writer = new StringWriter(len * 2);
if (Character.isDigit(str.charAt(i)) == false) {
return false; for (int i = 0; i < len; i++) {
char ch = str.charAt(i);
// handle unicode
if (ch > 0xfff) {
writer.write("\\u" + hex(ch));
} else if (ch > 0xff) {
writer.write("\\u0" + hex(ch));
} else if (ch > 0x7f) {
writer.write("\\u00" + hex(ch));
} else if (ch < 32) {
switch (ch) {
case '\b':
writer.write('\\');
writer.write('b');
break;
case '\n':
writer.write('\\');
writer.write('n');
break;
case '\t':
writer.write('\\');
writer.write('t');
break;
case '\f':
writer.write('\\');
writer.write('f');
break;
case '\r':
writer.write('\\');
writer.write('r');
break;
default :
if (ch > 0xf) {
writer.write("\\u00" + hex(ch));
} else {
writer.write("\\u000" + hex(ch));
} }
break;
} }
return true; } else {
switch (ch) {
case '\'':
if (escapeSingleQuote) {
writer.write('\\');
} }
writer.write('\'');
public static boolean isNumeric(String str) { break;
if (str == null || str.trim().isEmpty()) { case '"':
return false; writer.write('\\');
writer.write('"');
break;
case '\\':
writer.write('\\');
writer.write('\\');
break;
case '/':
writer.write('\\');
writer.write('/');
break;
default :
writer.write(ch);
break;
} }
int sz = str.length();
for (int i = 0; i < sz; i++) {
if (Character.isDigit(str.charAt(i)) == false && !(str.charAt(i) == '.')) {
return false;
} }
} }
return true; return writer.toString();
} }
public static String unescape(String s) { public static String unescape(String str) {
if (s.indexOf(BACKSLASH) == -1) { if (str == null) {
return s; return null;
} }
StringBuilder sb = new StringBuilder(s.length()); int len = str.length();
for (int i = 0; i < s.length(); i++) { StringWriter writer = new StringWriter(len);
char c = s.charAt(i); StringBuffer unicode = new StringBuffer(4);
if (c == BACKSLASH) { boolean hadSlash = false;
char c2 = s.charAt(++i); boolean inUnicode = false;
switch (c2) { for (int i = 0; i < len; i++) {
char ch = str.charAt(i);
if (inUnicode) {
unicode.append(ch);
if (unicode.length() == 4) {
try {
int value = Integer.parseInt(unicode.toString(), 16);
writer.write((char) value);
unicode.setLength(0);
inUnicode = false;
hadSlash = false;
} catch (NumberFormatException nfe) {
throw new JsonPathException("Unable to parse unicode value: " + unicode, nfe);
}
}
continue;
}
if (hadSlash) {
hadSlash = false;
switch (ch) {
case '\\': case '\\':
c2 = '\\'; writer.write('\\');
break; break;
case 'b': case '\'':
c2 = '\b'; writer.write('\'');
break; break;
case 'f': case '\"':
c2 = '\f'; writer.write('"');
break;
case 'n':
c2 = '\n';
break; break;
case 'r': case 'r':
c2 = '\r'; writer.write('\r');
break;
case 'f':
writer.write('\f');
break; break;
case 't': case 't':
c2 = '\t'; writer.write('\t');
break;
case 'n':
writer.write('\n');
break;
case 'b':
writer.write('\b');
break; break;
case 'u': case 'u':
try { {
String hex = s.substring(i + 1, i + 5); inUnicode = true;
c2 = (char) Integer.parseInt(hex, 16); break;
i += 4;
} catch (Exception e) {
throw new ValueCompareException("\\u parse failed", e);
} }
default :
writer.write(ch);
break; break;
} }
sb.append(c2); continue;
} else { } else if (ch == '\\') {
sb.append(c); hadSlash = true;
continue;
} }
writer.write(ch);
} }
return sb.toString(); if (hadSlash) {
writer.write('\\');
}
return writer.toString();
}
/**
* Returns an upper case hexadecimal <code>String</code> for the given
* character.
*
* @param ch The character to convert.
* @return An upper case hexadecimal <code>String</code>
*/
public static String hex(char ch) {
return Integer.toHexString(ch).toUpperCase();
} }
/** /**
@ -245,38 +290,7 @@ public final class Utils {
return cs.toString().indexOf(searchChar.toString(), start); return cs.toString().indexOf(searchChar.toString(), start);
} }
/**
* <p>Counts how many times the substring appears in the larger string.</p>
* <p/>
* <p>A {@code null} or empty ("") String input returns {@code 0}.</p>
* <p/>
* <pre>
* StringUtils.countMatches(null, *) = 0
* StringUtils.countMatches("", *) = 0
* StringUtils.countMatches("abba", null) = 0
* StringUtils.countMatches("abba", "") = 0
* StringUtils.countMatches("abba", "a") = 2
* StringUtils.countMatches("abba", "ab") = 1
* StringUtils.countMatches("abba", "xxx") = 0
* </pre>
*
* @param str the CharSequence to check, may be null
* @param sub the substring to count, may be null
* @return the number of occurrences, 0 if either CharSequence is {@code null}
* @since 3.0 Changed signature from countMatches(String, String) to countMatches(CharSequence, CharSequence)
*/
public static int countMatches(CharSequence str, CharSequence sub) {
if (isEmpty(str) || isEmpty(sub)) {
return 0;
}
int count = 0;
int idx = 0;
while ((idx = indexOf(str, sub, idx)) != -1) {
count++;
idx += sub.length();
}
return count;
}
//--------------------------------------------------------- //---------------------------------------------------------
// //
@ -384,200 +398,9 @@ public final class Utils {
if (null == o) { if (null == o) {
return null; return null;
} }
return o.toString(); return o.toString();
} }
//---------------------------------------------------------
//
// Serialization
//
//---------------------------------------------------------
/**
* <p>Serializes an {@code Object} to the specified stream.</p>
* <p/>
* <p>The stream will be closed once the object is written.
* This avoids the need for a finally clause, and maybe also exception
* handling, in the application code.</p>
* <p/>
* <p>The stream passed in is not buffered internally within this method.
* This is the responsibility of your application if desired.</p>
*
* @param obj the object to serialize to bytes, may be null
* @param outputStream the stream to write to, must not be null
* @throws IllegalArgumentException if {@code outputStream} is {@code null}
* @throws RuntimeException (runtime) if the serialization fails
*/
public static void serialize(Serializable obj, OutputStream outputStream) {
if (outputStream == null) {
throw new IllegalArgumentException("The OutputStream must not be null");
}
ObjectOutputStream out = null;
try {
// stream closed in the finally
out = new ObjectOutputStream(outputStream);
out.writeObject(obj);
} catch (IOException ex) {
throw new JsonPathException(ex);
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException ex) { // NOPMD
// ignore close exception
}
}
}
/**
* <p>Serializes an {@code Object} to a byte array for
* storage/serialization.</p>
*
* @param obj the object to serialize to bytes
* @return a byte[] with the converted Serializable
* @throws RuntimeException (runtime) if the serialization fails
*/
public static byte[] serialize(Serializable obj) {
ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
serialize(obj, baos);
return baos.toByteArray();
}
// Deserialize
//-----------------------------------------------------------------------
/**
* <p>Deserializes an {@code Object} from the specified stream.</p>
* <p/>
* <p>The stream will be closed once the object is written. This
* avoids the need for a finally clause, and maybe also exception
* handling, in the application code.</p>
* <p/>
* <p>The stream passed in is not buffered internally within this method.
* This is the responsibility of your application if desired.</p>
*
* @param inputStream the serialized object input stream, must not be null
* @return the deserialized object
* @throws IllegalArgumentException if {@code inputStream} is {@code null}
* @throws RuntimeException (runtime) if the serialization fails
*/
public static Object deserialize(InputStream inputStream) {
if (inputStream == null) {
throw new IllegalArgumentException("The InputStream must not be null");
}
ObjectInputStream in = null;
try {
// stream closed in the finally
in = new ObjectInputStream(inputStream);
return in.readObject();
} catch (ClassNotFoundException ex) {
throw new JsonPathException(ex);
} catch (IOException ex) {
throw new JsonPathException(ex);
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException ex) { // NOPMD
// ignore close exception
}
}
}
/**
* <p>Deserializes a single {@code Object} from an array of bytes.</p>
*
* @param objectData the serialized object, must not be null
* @return the deserialized object
* @throws IllegalArgumentException if {@code objectData} is {@code null}
* @throws RuntimeException (runtime) if the serialization fails
*/
public static Object deserialize(byte[] objectData) {
if (objectData == null) {
throw new IllegalArgumentException("The byte[] must not be null");
}
ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
return deserialize(bais);
}
/**
* <p>Custom specialization of the standard JDK {@link java.io.ObjectInputStream}
* that uses a custom <code>ClassLoader</code> to resolve a class.
* If the specified <code>ClassLoader</code> is not able to resolve the class,
* the context classloader of the current thread will be used.
* This way, the standard deserialization work also in web-application
* containers and application servers, no matter in which of the
* <code>ClassLoader</code> the particular class that encapsulates
* serialization/deserialization lives. </p>
* <p/>
* <p>For more in-depth information about the problem for which this
* class here is a workaround, see the JIRA issue LANG-626. </p>
*/
static class ClassLoaderAwareObjectInputStream extends ObjectInputStream {
private ClassLoader classLoader;
/**
* Constructor.
*
* @param in The <code>InputStream</code>.
* @param classLoader classloader to use
* @throws IOException if an I/O error occurs while reading stream header.
* @see java.io.ObjectInputStream
*/
public ClassLoaderAwareObjectInputStream(InputStream in, ClassLoader classLoader) throws IOException {
super(in);
this.classLoader = classLoader;
}
/**
* Overriden version that uses the parametrized <code>ClassLoader</code> or the <code>ClassLoader</code>
* of the current <code>Thread</code> to resolve the class.
*
* @param desc An instance of class <code>ObjectStreamClass</code>.
* @return A <code>Class</code> object corresponding to <code>desc</code>.
* @throws IOException Any of the usual Input/Output exceptions.
* @throws ClassNotFoundException If class of a serialized object cannot be found.
*/
@Override
protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String name = desc.getName();
try {
return Class.forName(name, false, classLoader);
} catch (ClassNotFoundException ex) {
return Class.forName(name, false, Thread.currentThread().getContextClassLoader());
}
}
}
private static class ListReverser<T> implements Iterable<T> {
private ListIterator<T> listIterator;
public ListReverser(List<T> wrappedList) {
this.listIterator = wrappedList.listIterator(wrappedList.size());
}
public Iterator<T> iterator() {
return new Iterator<T>() {
public boolean hasNext() {
return listIterator.hasPrevious();
}
public T next() {
return listIterator.previous();
}
public void remove() {
listIterator.remove();
}
};
}
}
private Utils() { private Utils() {
} }
} }

12
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ExpressionNode.java

@ -6,16 +6,16 @@ public abstract class ExpressionNode implements Predicate {
public static ExpressionNode createExpressionNode(ExpressionNode right, LogicalOperator operator, ExpressionNode left){ public static ExpressionNode createExpressionNode(ExpressionNode right, LogicalOperator operator, ExpressionNode left){
if(operator == LogicalOperator.AND){ if(operator == LogicalOperator.AND){
if((left instanceof LogicalExpressionNode) && ((LogicalExpressionNode)left).getOperator() == LogicalOperator.AND ){ if((right instanceof LogicalExpressionNode) && ((LogicalExpressionNode)right).getOperator() == LogicalOperator.AND ){
LogicalExpressionNode len = (LogicalExpressionNode) left; LogicalExpressionNode len = (LogicalExpressionNode) right;
return len.append(right); return len.append(left);
} else { } else {
return LogicalExpressionNode.createLogicalAnd(left, right); return LogicalExpressionNode.createLogicalAnd(left, right);
} }
} else { } else {
if((left instanceof LogicalExpressionNode) && ((LogicalExpressionNode)left).getOperator() == LogicalOperator.OR ){ if((right instanceof LogicalExpressionNode) && ((LogicalExpressionNode)right).getOperator() == LogicalOperator.OR ){
LogicalExpressionNode len = (LogicalExpressionNode) left; LogicalExpressionNode len = (LogicalExpressionNode) right;
return len.append(right); return len.append(left);
} else { } else {
return LogicalExpressionNode.createLogicalOr(left, right); return LogicalExpressionNode.createLogicalOr(left, right);
} }

37
json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java

@ -1,5 +1,6 @@
package com.jayway.jsonpath.internal.filter; package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.InvalidPathException; import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.Predicate; import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.CharacterIndex; import com.jayway.jsonpath.internal.CharacterIndex;
@ -38,9 +39,9 @@ public class FilterCompiler {
private CharacterIndex filter; private CharacterIndex filter;
public static Predicate compile(String filterString) { public static Filter compile(String filterString) {
FilterCompiler compiler = new FilterCompiler(filterString); FilterCompiler compiler = new FilterCompiler(filterString);
return compiler.compile(); return new CompiledFilter(compiler.compile());
} }
private FilterCompiler(String filterString) { private FilterCompiler(String filterString) {
@ -78,9 +79,15 @@ public class FilterCompiler {
case CLOSE_BRACKET: case CLOSE_BRACKET:
unbalancedBrackets--; unbalancedBrackets--;
filter.incrementPosition(1); filter.incrementPosition(1);
ExpressionNode expressionNode = expStack.pop();
if(!opsStack.isEmpty()){
ExpressionNode right = expStack.pop();
expressionNode = ExpressionNode.createExpressionNode(expressionNode, opsStack.pop(), right);
while(!opsStack.isEmpty()){ while(!opsStack.isEmpty()){
expStack.push(ExpressionNode.createExpressionNode(expStack.pop(), opsStack.pop(), expStack.pop())); expressionNode = ExpressionNode.createExpressionNode(expressionNode, opsStack.pop(), expStack.pop());
} }
}
expStack.push(expressionNode);
break; break;
case BANG: case BANG:
filter.incrementPosition(1); filter.incrementPosition(1);
@ -336,4 +343,28 @@ public class FilterCompiler {
private boolean isRelationalOperatorChar(char c) { private boolean isRelationalOperatorChar(char c) {
return c == LT || c == GT || c == EQ || c == TILDE || c == BANG; return c == LT || c == GT || c == EQ || c == TILDE || c == BANG;
} }
private static final class CompiledFilter extends Filter {
private final Predicate predicate;
private CompiledFilter(Predicate predicate) {
this.predicate = predicate;
}
@Override
public boolean apply(Predicate.PredicateContext ctx) {
return predicate.apply(ctx);
}
@Override
public String toString() {
String predicateString = predicate.toString();
if(predicateString.startsWith("(")){
return "[?" + predicateString + "]";
} else {
return "[?(" + predicateString + ")]";
}
}
}
} }

2
json-path/src/main/java/com/jayway/jsonpath/internal/filter/LogicalExpressionNode.java

@ -36,7 +36,7 @@ public class LogicalExpressionNode extends ExpressionNode {
} }
public LogicalExpressionNode append(ExpressionNode expressionNode) { public LogicalExpressionNode append(ExpressionNode expressionNode) {
chain.add(expressionNode); chain.add(0, expressionNode);
return this; return this;
} }

2
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java

@ -415,7 +415,7 @@ public abstract class ValueNode {
@Override @Override
public String toString() { public String toString() {
return "'" + string + "'"; return "'" + Utils.escape(string, true) + "'";
} }
@Override @Override

75
json-path/src/test/java/com/jayway/jsonpath/FilterCompilerTest.java

@ -1,54 +1,41 @@
package com.jayway.jsonpath; package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.filter.FilterCompiler;
import org.junit.Test; import org.junit.Test;
import static com.jayway.jsonpath.internal.filter.FilterCompiler.compile;
import static org.assertj.core.api.Assertions.assertThat;
public class FilterCompilerTest { public class FilterCompilerTest {
@Test @Test
public void filter_compiler_test() { public void filter_compiler_test() {
assertThat(compile("[?(@)]").toString()).isEqualTo("[?(@)]");
FilterCompiler.compile("[?(@)]"); assertThat(compile("[?(@)]").toString()).isEqualTo("[?(@)]");
assertThat(compile("[?(@.firstname)]").toString()).isEqualTo("[?(@['firstname'])]");
FilterCompiler.compile("[?($)]"); assertThat(compile("[?($.firstname)]").toString()).isEqualTo("[?($['firstname'])]");
assertThat(compile("[?(@['firstname'])]").toString()).isEqualTo("[?(@['firstname'])]");
FilterCompiler.compile("[?(@.firstname)]"); assertThat(compile("[?($['firstname'].lastname)]").toString()).isEqualTo("[?($['firstname']['lastname'])]");
FilterCompiler.compile("[?(@.firstname)]"); assertThat(compile("[?($['firstname']['lastname'])]").toString()).isEqualTo("[?($['firstname']['lastname'])]");
FilterCompiler.compile("[?($.firstname)]"); assertThat(compile("[?($['firstname']['lastname'].*)]").toString()).isEqualTo("[?($['firstname']['lastname'][*])]");
FilterCompiler.compile("[?(@['firstname'])]"); assertThat(compile("[?($['firstname']['num_eq'] == 1)]").toString()).isEqualTo("[?($['firstname']['num_eq'] == 1)]");
assertThat(compile("[?($['firstname']['num_gt'] > 1.1)]").toString()).isEqualTo("[?($['firstname']['num_gt'] > 1.1)]");
assertThat(compile("[?($['firstname']['num_lt'] < 11.11)]").toString()).isEqualTo("[?($['firstname']['num_lt'] < 11.11)]");
FilterCompiler.compile("[?($['firstname'].lastname)]"); assertThat(compile("[?($['firstname']['str_eq'] == 'hej')]").toString()).isEqualTo("[?($['firstname']['str_eq'] == 'hej')]");
FilterCompiler.compile("[?($['firstname']['lastname'])]"); assertThat(compile("[?($['firstname']['str_eq'] == '')]").toString()).isEqualTo("[?($['firstname']['str_eq'] == '')]");
assertThat(compile("[?($['firstname']['str_eq'] == null)]").toString()).isEqualTo("[?($['firstname']['str_eq'] == null)]");
FilterCompiler.compile("[?($['firstname']['lastname'].*)]"); assertThat(compile("[?($['firstname']['str_eq'] == true)]").toString()).isEqualTo("[?($['firstname']['str_eq'] == true)]");
assertThat(compile("[?($['firstname']['str_eq'] == false)]").toString()).isEqualTo("[?($['firstname']['str_eq'] == false)]");
FilterCompiler.compile("[?($['firstname']['num_eq'] == 1)]"); assertThat(compile("[?(@.firstname && @.lastname)]").toString()).isEqualTo("[?(@['firstname'] && @['lastname'])]");
FilterCompiler.compile("[?($['firstname']['num_gt'] > 1.1)]"); assertThat(compile("[?((@.firstname || @.lastname) && @.and)]").toString()).isEqualTo("[?((@['firstname'] || @['lastname']) && @['and'])]");
assertThat(compile("[?((@.a || @.b || @.c) && @.x)]").toString()).isEqualTo("[?((@['a'] || @['b'] || @['c']) && @['x'])]");
FilterCompiler.compile("[?($['firstname']['num_lt'] < 11.11)]"); assertThat(compile("[?((@.a && @.b && @.c) || @.x)]").toString()).isEqualTo("[?((@['a'] && @['b'] && @['c']) || @['x'])]");
assertThat(compile("[?((@.a && @.b || @.c) || @.x)]").toString()).isEqualTo("[?((@['a'] && (@['b'] || @['c'])) || @['x'])]");
FilterCompiler.compile("[?($['firstname']['str_eq'] == 'hej')]"); assertThat(compile("[?((@.a && @.b) || (@.c && @.d))]").toString()).isEqualTo("[?((@['a'] && @['b']) || (@['c'] && @['d']))]");
FilterCompiler.compile("[?($['firstname']['str_eq'] == '')]"); assertThat(compile("[?(@.a IN [1,2,3])]").toString()).isEqualTo("[?(@['a'] IN [1,2,3])]");
assertThat(compile("[?(@.a IN {'foo':'bar'})]").toString()).isEqualTo("[?(@['a'] IN {'foo':'bar'})]");
FilterCompiler.compile("[?($['firstname']['str_eq'] == null)]"); assertThat(compile("[?(@.value<'7')]").toString()).isEqualTo("[?(@['value'] < '7')]");
FilterCompiler.compile("[?($['firstname']['str_eq'] == true)]"); assertThat(compile("[?(@.message == 'it\\\\')]").toString()).isEqualTo("[?(@['message'] == 'it\\\\')]");
FilterCompiler.compile("[?($['firstname']['str_eq'] == false)]");
FilterCompiler.compile("[?(@.firstname && @.lastname)]");
FilterCompiler.compile("[?((@.firstname || @.lastname) && @.and)]");
FilterCompiler.compile("[?((@.a || @.b || @.c) && @.x)]");
FilterCompiler.compile("[?((@.a && @.b && @.c) || @.x)]");
FilterCompiler.compile("[?((@.a && @.b || @.c) || @.x)]");
FilterCompiler.compile("[?((@.a && @.b) || (@.c && @.d))]");
FilterCompiler.compile("[?(@.a IN [1,2,3])]");
FilterCompiler.compile("[?(@.a IN {'foo':'bar'})]");
FilterCompiler.compile("[?(@.value<'7')]");
FilterCompiler.compile("[?(@.message == 'it\\\\')]");
} }
} }

17
json-path/src/test/java/com/jayway/jsonpath/internal/UtilsTest.java

@ -0,0 +1,17 @@
package com.jayway.jsonpath.internal;
import org.junit.Test;
public class UtilsTest {
@Test
public void strings_can_be_escaped() {
String str = "it\\\\";
System.out.println(Utils.unescape(str));
System.out.println(Utils.escape(str, true));
}
}
Loading…
Cancel
Save