Browse Source

expose JSON providers ability to parse UTF-8 byte arrays (#770)

heroku
Richard Startin 3 years ago committed by GitHub
parent
commit
921d3bc984
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      json-path/src/main/java/com/jayway/jsonpath/ParseContext.java
  2. 7
      json-path/src/main/java/com/jayway/jsonpath/internal/ParseContextImpl.java
  3. 20
      json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java
  4. 13
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java
  5. 13
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonProvider.java
  6. 68
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JakartaJsonProvider.java
  7. 12
      json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java
  8. 8
      json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java
  9. 17
      json-path/src/test/java/com/jayway/jsonpath/JacksonTest.java
  10. 15
      json-path/src/test/java/com/jayway/jsonpath/JakartaJsonProviderTest.java

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

@ -19,6 +19,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* Parses JSON as specified by the used {@link com.jayway.jsonpath.spi.json.JsonProvider}.
*/
@ -34,6 +35,8 @@ public interface ParseContext {
DocumentContext parse(File json) throws IOException;
DocumentContext parseUtf8(byte[] json);
@Deprecated
DocumentContext parse(URL json) throws IOException;
}

7
json-path/src/main/java/com/jayway/jsonpath/internal/ParseContextImpl.java

@ -38,6 +38,13 @@ public class ParseContextImpl implements ParseContext {
return new JsonContext(obj, configuration);
}
@Override
public DocumentContext parseUtf8(byte[] json) {
notEmpty(json, "json bytes can not be null or empty");
Object obj = configuration.jsonProvider().parse(json);
return new JsonContext(obj, configuration);
}
@Override
public DocumentContext parse(InputStream json) {
return parse(json, "UTF-8");

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

@ -403,6 +403,26 @@ public final class Utils {
return chars;
}
/**
* <p>Validate that the specified argument character sequence is
* neither {@code null} nor a length of zero (no characters);
* otherwise throwing an exception with the specified message.
* <p/>
* <pre>Validate.notEmpty(myString, "The string must not be empty");</pre>
*
* @param bytes the bytes to check, validated not null by this method
* @param message the {@link String#format(String, Object...)} exception message if invalid, not null
* @return the validated character sequence (never {@code null} method for chaining)
* @throws NullPointerException if the character sequence is {@code null}
* @throws IllegalArgumentException if the character sequence is empty
*/
public static byte[] notEmpty(byte[] bytes, String message) {
if (bytes == null || bytes.length == 0) {
throw new IllegalArgumentException(message);
}
return bytes;
}
/**
* <p>Validate that the specified argument character sequence is
* neither {@code null} nor a length of zero (no characters);

13
json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java

@ -8,17 +8,18 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.databind.node.TextNode;
import com.jayway.jsonpath.InvalidJsonException;
import com.jayway.jsonpath.JsonPathException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
public class JacksonJsonNodeJsonProvider extends AbstractJsonProvider {
private static final ObjectMapper defaultObjectMapper = new ObjectMapper();
@ -54,6 +55,16 @@ public class JacksonJsonNodeJsonProvider extends AbstractJsonProvider {
}
}
@Override
public Object parse(byte[] json)
throws InvalidJsonException {
try {
return objectMapper.readTree(json);
} catch (IOException e) {
throw new InvalidJsonException(e, new String(json, StandardCharsets.UTF_8));
}
}
@Override
public Object parse(InputStream jsonStream, String charset) throws InvalidJsonException {
try {

13
json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonProvider.java

@ -18,15 +18,16 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.jayway.jsonpath.InvalidJsonException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
public class JacksonJsonProvider extends AbstractJsonProvider {
private static final ObjectMapper defaultObjectMapper = new ObjectMapper();
@ -73,6 +74,16 @@ public class JacksonJsonProvider extends AbstractJsonProvider {
}
}
@Override
public Object parse(byte[] json)
throws InvalidJsonException {
try {
return objectReader.readValue(json);
} catch (IOException e) {
throw new InvalidJsonException(e, new String(json, StandardCharsets.UTF_8));
}
}
@Override
public Object parse(InputStream jsonStream, String charset) throws InvalidJsonException {
try {

68
json-path/src/main/java/com/jayway/jsonpath/spi/json/JakartaJsonProvider.java

@ -1,5 +1,20 @@
package com.jayway.jsonpath.spi.json;
import com.jayway.jsonpath.InvalidJsonException;
import com.jayway.jsonpath.JsonPathException;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonBuilderFactory;
import jakarta.json.JsonNumber;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonReader;
import jakarta.json.JsonString;
import jakarta.json.JsonStructure;
import jakarta.json.JsonValue;
import jakarta.json.spi.JsonProvider;
import jakarta.json.stream.JsonParsingException;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
@ -7,6 +22,7 @@ import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collection;
@ -19,22 +35,6 @@ import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import com.jayway.jsonpath.InvalidJsonException;
import com.jayway.jsonpath.JsonPathException;
import jakarta.json.JsonArray;
import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonBuilderFactory;
import jakarta.json.JsonException;
import jakarta.json.JsonNumber;
import jakarta.json.JsonObject;
import jakarta.json.JsonObjectBuilder;
import jakarta.json.JsonReader;
import jakarta.json.JsonString;
import jakarta.json.JsonStructure;
import jakarta.json.JsonValue;
import jakarta.json.spi.JsonProvider;
import jakarta.json.stream.JsonParsingException;
public class JakartaJsonProvider extends AbstractJsonProvider {
@ -69,34 +69,34 @@ public class JakartaJsonProvider extends AbstractJsonProvider {
@Override
public Object parse(String json) throws InvalidJsonException {
Reader jsonInput = new StringReader(json);
try (JsonReader jsonReader = defaultJsonProvider.createReader(jsonInput)) {
JsonStructure jsonStruct = jsonReader.read();
return mutableJson ? proxyAll(jsonStruct) : jsonStruct;
} catch (JsonParsingException e) {
throw new InvalidJsonException(e);
}
// not catching a JsonException as it never happens here
return parse(new StringReader(json));
}
@Override
public Object parse(byte[] json)
throws InvalidJsonException {
return parse(new InputStreamReader(new ByteArrayInputStream(json), StandardCharsets.UTF_8));
}
@Override
public Object parse(InputStream jsonStream, String charset) throws InvalidJsonException {
Reader jsonInput;
try {
jsonInput = new InputStreamReader(jsonStream, charset);
return parse(new InputStreamReader(jsonStream, charset));
} catch (UnsupportedEncodingException e) {
throw new JsonPathException(e);
}
try (JsonReader jsonReader = defaultJsonProvider.createReader(jsonInput)) {
JsonStructure jsonStruct = jsonReader.read();
return mutableJson ? proxyAll(jsonStruct) : jsonStruct;
} catch (JsonParsingException e) {
throw new InvalidJsonException(e);
} catch (JsonException e) {
throw new JsonPathException(e);
}
}
private Object parse(Reader jsonInput) {
try (JsonReader jsonReader = defaultJsonProvider.createReader(jsonInput)) {
JsonStructure jsonStruct = jsonReader.read();
return mutableJson ? proxyAll(jsonStruct) : jsonStruct;
} catch (JsonParsingException e) {
throw new InvalidJsonException(e);
}
// not catching a JsonException as it never happens here
}
@Override
public String toJson(Object obj) {
if (obj instanceof JsonObjectBuilder) {

12
json-path/src/main/java/com/jayway/jsonpath/spi/json/JsonProvider.java

@ -15,10 +15,11 @@
package com.jayway.jsonpath.spi.json;
import com.jayway.jsonpath.InvalidJsonException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Collection;
public interface JsonProvider {
static final Object UNDEFINED = new Object();
@ -31,6 +32,15 @@ public interface JsonProvider {
*/
Object parse(String json) throws InvalidJsonException;
/**
* Parse the given json bytes in UTF-8 encoding
* @param json json bytes to parse
* @return Object representation of json
* @throws InvalidJsonException
*/
default Object parse(byte[] json) throws InvalidJsonException {
return parse(new String(json, StandardCharsets.UTF_8));
}
/**
* Parse the given json string
* @param jsonStream input stream to parse

8
json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java

@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingException;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
import java.io.IOException;
@ -53,6 +54,13 @@ public class JacksonJsonNodeJsonProviderTest extends BaseTest {
assertThat(node.get("string-property").asText()).isEqualTo("string-value");
}
@Test
public void bytes_json_can_be_parsed() {
ObjectNode node = using(JACKSON_JSON_NODE_CONFIGURATION).parseUtf8(JSON_DOCUMENT.getBytes(StandardCharsets.UTF_8))
.read("$");
assertThat(node.get("string-property").asText()).isEqualTo("string-value");
}
@Test
public void always_return_same_object() { // Test because of Bug #211
DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION).parse(JSON_DOCUMENT);

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

@ -1,12 +1,13 @@
package com.jayway.jsonpath;
import org.junit.Test;
import java.util.Date;
import org.junit.Test;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.singletonMap;
import static org.assertj.core.api.Assertions.assertThat;
public class JacksonTest extends BaseTest {
@Test
@ -25,6 +26,12 @@ public class JacksonTest extends BaseTest {
assertThat(fooBarBaz.bar).isEqualTo(10L);
assertThat(fooBarBaz.baz).isEqualTo(true);
fooBarBaz = JsonPath.using(JACKSON_CONFIGURATION).parseUtf8(json.getBytes(UTF_8))
.read("$", FooBarBaz.class);
assertThat(fooBarBaz.foo).isEqualTo("foo");
assertThat(fooBarBaz.bar).isEqualTo(10L);
assertThat(fooBarBaz.baz).isEqualTo(true);
}
public static class FooBarBaz {
@ -52,7 +59,11 @@ public class JacksonTest extends BaseTest {
final Object readFromSingleQuote = JsonPath.using(JACKSON_CONFIGURATION).parse(jsonArray).read("$.[?(@.foo in ['bar'])].foo");
final Object readFromDoubleQuote = JsonPath.using(JACKSON_CONFIGURATION).parse(jsonArray).read("$.[?(@.foo in [\"bar\"])].foo");
assertThat(readFromSingleQuote).isEqualTo(readFromDoubleQuote);
final Object readFromSingleQuoteBytes = JsonPath.using(JACKSON_CONFIGURATION).parseUtf8(jsonArray.getBytes(UTF_8))
.read("$.[?(@.foo in ['bar'])].foo");
final Object readFromDoubleQuoteBytes = JsonPath.using(JACKSON_CONFIGURATION).parseUtf8(jsonArray.getBytes(UTF_8))
.read("$.[?(@.foo in [\"bar\"])].foo");
assertThat(readFromSingleQuoteBytes).isEqualTo(readFromDoubleQuoteBytes);
}
}

15
json-path/src/test/java/com/jayway/jsonpath/JakartaJsonProviderTest.java

@ -1,20 +1,20 @@
package com.jayway.jsonpath;
import org.junit.Test;
import jakarta.json.JsonObject;
import jakarta.json.JsonString;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test;
import static com.jayway.jsonpath.JsonPath.parse;
import static com.jayway.jsonpath.JsonPath.using;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Collections.emptyMap;
import static org.assertj.core.api.Assertions.assertThat;
public class JakartaJsonProviderTest extends BaseTest {
private static final Map<String, Object> EMPTY_MAP = emptyMap();
@ -28,6 +28,15 @@ public class JakartaJsonProviderTest extends BaseTest {
assertThat(((JsonString) book.get("author")).getChars()).isEqualTo("Nigel Rees");
}
@Test
public void an_object_can_be_read_from_bytes() {
JsonObject book = using(JAKARTA_JSON_CONFIGURATION)
.parseUtf8(JSON_DOCUMENT.getBytes(UTF_8))
.read("$.store.book[0]");
assertThat(((JsonString) book.get("author")).getChars()).isEqualTo("Nigel Rees");
}
@Test
public void a_property_can_be_read() {
JsonString category = using(JAKARTA_JSON_CONFIGURATION)

Loading…
Cancel
Save