diff --git a/CREDITS.txt b/CREDITS.txt index e036d93..1f6e6d6 100644 --- a/CREDITS.txt +++ b/CREDITS.txt @@ -46,3 +46,12 @@ https://github.com/marc4j/marc4j/tree/master/test/resources and were donated by libraries for testing purpose. +----------------- + +The JSON reader/writer classes are derived work from + +https://github.com/ralfstx/minimal-json + +The original work is based on the MIT License + +----------------- diff --git a/build.gradle b/build.gradle index 50160ab..1c775a0 100644 --- a/build.gradle +++ b/build.gradle @@ -24,6 +24,9 @@ dependencies { testImplementation("com.github.stefanbirkner:system-rules:${project.property('system-rules.version')}") { exclude module: 'junit' } + testImplementation("org.mockito:mockito-core:${project.property('mockito.version')}") { + exclude group: 'org.hamcrest' + } } compileJava { diff --git a/gradle.properties b/gradle.properties index dced48b..5914d1c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,3 +14,4 @@ junit4.version = 4.12 xalan.version = 2.7.2 xmlunit-matchers.version = 2.6.3 system-rules.version = 1.19.0 +mockito.version = 3.1.0 diff --git a/src/main/java/org/xbib/marc/json/Json.java b/src/main/java/org/xbib/marc/json/Json.java new file mode 100755 index 0000000..3058ef1 --- /dev/null +++ b/src/main/java/org/xbib/marc/json/Json.java @@ -0,0 +1,280 @@ +/* + Copyright 2016 Jörg Prante + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ +package org.xbib.marc.json; + +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.util.Objects; + +/** + * This class serves as the entry point to the JSON API. + *
+ * To parse a given JSON input, use the parse()
methods like in this
+ * example:
+ *
+ * JsonObject object = Json.parse(string).asObject(); + *+ *
+ * To create a JSON data structure to be serialized, use the methods
+ * value()
, array()
, and object()
. For example, the following
+ * snippet will produce the JSON string {"foo": 23, "bar": true}:
+ *
+ * String string = Json.object().add("foo", 23).add("bar", true).toString(); + *+ *
+ * To create a JSON array from a given Java array, you can use one of the array()
+ * methods with varargs parameters:
+ *
+ * String[] names = ... + * JsonArray array = Json.array(names); + *+ */ +public final class Json { + + private Json() { + // not meant to be instantiated + } + + /** + * Returns a JsonValue instance that represents the given
int
value.
+ *
+ * @param value the value to get a JSON representation for
+ * @return a JSON value that represents the given value
+ */
+ public static JsonValue of(int value) {
+ return new JsonNumber(Integer.toString(value, 10));
+ }
+
+ /**
+ * Returns a JsonValue instance that represents the given long
value.
+ *
+ * @param value the value to get a JSON representation for
+ * @return a JSON value that represents the given value
+ */
+ public static JsonValue of(long value) {
+ return new JsonNumber(Long.toString(value, 10));
+ }
+
+ /**
+ * Returns a JsonValue instance that represents the given float
value.
+ *
+ * @param value the value to get a JSON representation for
+ * @return a JSON value that represents the given value
+ */
+ public static JsonValue of(float value) {
+ if (Float.isInfinite(value) || Float.isNaN(value)) {
+ throw new IllegalArgumentException("Infinite and NaN values not permitted in JSON");
+ }
+ return new JsonNumber(cutOffPointZero(Float.toString(value)));
+ }
+
+ /**
+ * Returns a JsonValue instance that represents the given double
value.
+ *
+ * @param value the value to get a JSON representation for
+ * @return a JSON value that represents the given value
+ */
+ public static JsonValue of(double value) {
+ if (Double.isInfinite(value) || Double.isNaN(value)) {
+ throw new IllegalArgumentException("Infinite and NaN values not permitted in JSON");
+ }
+ return new JsonNumber(cutOffPointZero(Double.toString(value)));
+ }
+
+ /**
+ * Returns a JsonValue instance that represents the given string.
+ *
+ * @param string the string to get a JSON representation for
+ * @return a JSON value that represents the given string
+ */
+ public static JsonValue of(String string) {
+ return string == null ? JsonLiteral.NULL : new JsonString(string);
+ }
+
+ /**
+ * Returns a JsonValue instance that represents the given boolean
value.
+ *
+ * @param value the value to get a JSON representation for
+ * @return a JSON value that represents the given value
+ */
+ public static JsonValue of(boolean value) {
+ return value ? JsonLiteral.TRUE : JsonLiteral.FALSE;
+ }
+
+ /**
+ * Creates a new empty JsonArray. This is equivalent to creating a new JsonArray using the
+ * constructor.
+ *
+ * @return a new empty JSON array
+ */
+ public static JsonArray array() {
+ return new JsonArray();
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given int
+ * values.
+ *
+ * @param values the values to be included in the new JSON array
+ * @return a new JSON array that contains the given values
+ */
+ public static JsonArray array(int... values) {
+ Objects.requireNonNull(values);
+ JsonArray array = new JsonArray();
+ for (int value : values) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given long
+ * values.
+ *
+ * @param values the values to be included in the new JSON array
+ * @return a new JSON array that contains the given values
+ */
+ public static JsonArray array(long... values) {
+ Objects.requireNonNull(values);
+ JsonArray array = new JsonArray();
+ for (long value : values) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given float
+ * values.
+ *
+ * @param values the values to be included in the new JSON array
+ * @return a new JSON array that contains the given values
+ */
+ public static JsonArray array(float... values) {
+ Objects.requireNonNull(values);
+ JsonArray array = new JsonArray();
+ for (float value : values) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given double
+ * values.
+ *
+ * @param values the values to be included in the new JSON array
+ * @return a new JSON array that contains the given values
+ */
+ public static JsonArray array(double... values) {
+ Objects.requireNonNull(values);
+ JsonArray array = new JsonArray();
+ for (double value : values) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given
+ * boolean
values.
+ *
+ * @param values the values to be included in the new JSON array
+ * @return a new JSON array that contains the given values
+ */
+ public static JsonArray array(boolean... values) {
+ Objects.requireNonNull(values);
+ JsonArray array = new JsonArray();
+ for (boolean value : values) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new JsonArray that contains the JSON representations of the given strings.
+ *
+ * @param strings the strings to be included in the new JSON array
+ * @return a new JSON array that contains the given strings
+ */
+ public static JsonArray array(String... strings) {
+ Objects.requireNonNull(strings);
+ JsonArray array = new JsonArray();
+ for (String value : strings) {
+ array.add(value);
+ }
+ return array;
+ }
+
+ /**
+ * Creates a new empty JsonObject. This is equivalent to creating a new JsonObject using the
+ * constructor.
+ *
+ * @return a new empty JSON object
+ */
+ public static JsonObject object() {
+ return new JsonObject();
+ }
+
+ /**
+ * Parses the given input string as JSON. The input must contain a valid JSON value, optionally
+ * padded with whitespace.
+ *
+ * @param string the input string, must be valid JSON
+ * @return a value that represents the parsed JSON
+ * @throws IOException if the input is not valid JSON
+ */
+ public static JsonValue parse(String string) throws IOException {
+ Objects.requireNonNull(string);
+ JsonDefaultHandler handler = new JsonDefaultHandler();
+ new JsonReader<>(new StringReader(string), handler).parse();
+ return handler.getValue();
+ }
+
+ /**
+ * Reads the entire input from the given reader and parses it as JSON. The input must contain a
+ * valid JSON value, optionally padded with whitespace.
+ *
+ * Characters are read in chunks into an input buffer. Hence, wrapping a reader in an additional
+ * BufferedReader
likely won't improve reading performance.
+ *
+ * Elements can be added using the add(...)
methods which accept instances of
+ * {@link JsonValue}, strings, primitive numbers, and boolean values. To replace an element of an
+ * array, use the set(int, ...)
methods.
+ *
+ * Elements can be accessed by their index using {@link #get(int)}. This class also supports + * iterating over the elements in document order using an {@link #iterator()} or an enhanced for + * loop: + *
+ *+ * for (JsonValue value : jsonArray) { + * ... + * } + *+ *
+ * An equivalent {@link List} can be obtained from the method {@link #values()}. + *
+ *
+ * Note that this class is not thread-safe. If multiple threads access a
+ * JsonArray
instance concurrently, while at least one of these threads modifies the
+ * contents of this array, access to the instance must be synchronized externally. Failure to do so
+ * may lead to an inconsistent state.
+ *
null
+ */
+ public JsonArray(JsonArray array) {
+ Objects.requireNonNull(array);
+ values = new ArrayList<>(array.values);
+ }
+
+ /**
+ * Appends the JSON representation of the specified int
value to the end of this
+ * array.
+ *
+ * @param value the value to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(int value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the JSON representation of the specified long
value to the end of this
+ * array.
+ *
+ * @param value the value to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(long value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the JSON representation of the specified float
value to the end of this
+ * array.
+ *
+ * @param value the value to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(float value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the JSON representation of the specified double
value to the end of this
+ * array.
+ *
+ * @param value the value to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(double value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the JSON representation of the specified boolean
value to the end of this
+ * array.
+ *
+ * @param value the value to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(boolean value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the JSON representation of the specified string to the end of this array.
+ *
+ * @param value the string to add to the array
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(String value) {
+ values.add(Json.of(value));
+ return this;
+ }
+
+ /**
+ * Appends the specified JSON value to the end of this array.
+ *
+ * @param value the JsonValue to add to the array, must not be null
+ * @return the array itself, to enable method chaining
+ */
+ public JsonArray add(JsonValue value) {
+ Objects.requireNonNull(value);
+ values.add(value);
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified int
value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, int value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified long
value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, long value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified float
value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, float value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified double
value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, double value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified boolean
value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, boolean value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the JSON representation of
+ * the specified string.
+ *
+ * @param index the index of the array element to replace
+ * @param value the string to be stored at the specified array position
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, String value) {
+ values.set(index, Json.of(value));
+ return this;
+ }
+
+ /**
+ * Replaces the element at the specified position in this array with the specified JSON value.
+ *
+ * @param index the index of the array element to replace
+ * @param value the value to be stored at the specified array position, must not be null
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray set(int index, JsonValue value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ values.set(index, value);
+ return this;
+ }
+
+ /**
+ * Removes the element at the specified index from this array.
+ *
+ * @param index the index of the element to remove
+ * @return the array itself, to enable method chaining
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonArray remove(int index) {
+ values.remove(index);
+ return this;
+ }
+
+ /**
+ * Returns the number of elements in this array.
+ *
+ * @return the number of elements in this array
+ */
+ public int size() {
+ return values.size();
+ }
+
+ /**
+ * Returns true
if this array contains no elements.
+ *
+ * @return true
if this array contains no elements
+ */
+ public boolean isEmpty() {
+ return values.isEmpty();
+ }
+
+ /**
+ * Returns the value of the element at the specified position in this array.
+ *
+ * @param index the index of the array element to return
+ * @return the value of the element at the specified position
+ * @throws IndexOutOfBoundsException if the index is out of range, i.e. index < 0
or
+ * index >= size
+ */
+ public JsonValue get(int index) {
+ return values.get(index);
+ }
+
+ /**
+ * Returns a list of the values in this array in document order.
+ *
+ * @return a list of the values in this array
+ */
+ public ListJsonArray
and both arrays contain the same list of values.
+ * + * If two JsonArrays are equal, they will also produce the same JSON output. + *
+ * + * @param object the object to be compared with this JsonArray + * @return true if the specified object is equal to this JsonArray,false
+ * otherwise
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+ }
+ if (object == null) {
+ return false;
+ }
+ if (getClass() != object.getClass()) {
+ return false;
+ }
+ JsonArray other = (JsonArray) object;
+ return values.equals(other.values);
+ }
+
+}
diff --git a/src/main/java/org/xbib/marc/json/JsonDefaultHandler.java b/src/main/java/org/xbib/marc/json/JsonDefaultHandler.java
new file mode 100644
index 0000000..42e99d8
--- /dev/null
+++ b/src/main/java/org/xbib/marc/json/JsonDefaultHandler.java
@@ -0,0 +1,111 @@
+/*
+ Copyright 2016 Jörg Prante
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.xbib.marc.json;
+
+/**
+ *
+ */
+public class JsonDefaultHandler implements JsonHandler+ * Implementations that build an object representation of the parsed JSON can return arbitrary handler + * objects for JSON arrays and JSON objects in {@link #startArray()} and {@link #startObject()}. + * These handler objects will then be provided in all subsequent parser events for this particular + * array or object. They can be used to keep track the elements of a JSON array or object. + *
+ * + * @param The type of handlers used for JSON arrays + * @paramnull
literal in the JSON input. This method will be
+ * called when reading the first character of the literal.
+ */
+ void startNull();
+
+ /**
+ * Indicates the end of a null
literal in the JSON input. This method will be called
+ * after reading the last character of the literal.
+ */
+ void endNull();
+
+ /**
+ * Indicates the beginning of a boolean literal (true
or false
) in the
+ * JSON input. This method will be called when reading the first character of the literal.
+ */
+ void startBoolean();
+
+ /**
+ * Indicates the end of a boolean literal (true
or false
) in the JSON
+ * input. This method will be called after reading the last character of the literal.
+ *
+ * @param value the parsed boolean value
+ */
+ void endBoolean(boolean value);
+
+ /**
+ * Indicates the beginning of a string in the JSON input. This method will be called when reading
+ * the opening double quote character ('"'
).
+ */
+ void startString();
+
+ /**
+ * Indicates the end of a string in the JSON input. This method will be called after reading the
+ * closing double quote character ('"'
).
+ *
+ * @param string the parsed string
+ */
+ void endString(String string);
+
+ /**
+ * Indicates the beginning of a number in the JSON input. This method will be called when reading
+ * the first character of the number.
+ */
+ void startNumber();
+
+ /**
+ * Indicates the end of a number in the JSON input. This method will be called after reading the
+ * last character of the number.
+ *
+ * @param string the parsed number string
+ */
+ void endNumber(String string);
+
+ /**
+ * Indicates the beginning of an array in the JSON input. This method will be called when reading
+ * the opening square bracket character ('['
).
+ * + * This method may return an object to handle subsequent parser events for this array. This array + * handler will then be provided in all calls to {@link #startArrayValue(Object) + * startArrayValue()}, {@link #endArrayValue(Object) endArrayValue()}, and + * {@link #endArray(Object) endArray()} for this array. + *
+ * + * @return a handler for this array, ornull
if not needed
+ */
+ A startArray();
+
+ /**
+ * Indicates the end of an array in the JSON input. This method will be called after reading the
+ * closing square bracket character (']'
).
+ *
+ * @param array the array handler returned from {@link #startArray()}, or null
if not
+ * provided
+ */
+ void endArray(A array);
+
+ /**
+ * Indicates the beginning of an array element in the JSON input. This method will be called when
+ * reading the first character of the element, just before the call to the start
+ * method for the specific element type ({@link #startString()}, {@link #startNumber()}, etc.).
+ *
+ * @param array the array handler returned from {@link #startArray()}, or null
if not
+ * provided
+ */
+ void startArrayValue(A array);
+
+ /**
+ * Indicates the end of an array element in the JSON input. This method will be called after
+ * reading the last character of the element value, just after the end
method for the
+ * specific element type (like {@link #endString(String) endString()}, {@link #endNumber(String)
+ * endNumber()}, etc.).
+ *
+ * @param array the array handler returned from {@link #startArray()}, or null
if not
+ * provided
+ */
+ void endArrayValue(A array);
+
+ /**
+ * Indicates the beginning of an object in the JSON input. This method will be called when reading
+ * the opening curly bracket character ('{'
).
+ * + * This method may return an object to handle subsequent parser events for this object. This + * object handler will be provided in all calls to {@link #startObjectName(Object) + * startObjectName()}, {@link #endObjectName(Object, String) endObjectName()}, + * {@link #startObjectValue(Object, String) startObjectValue()}, + * {@link #endObjectValue(Object, String) endObjectValue()}, and {@link #endObject(Object) + * endObject()} for this object. + *
+ * + * @return a handler for this object, ornull
if not needed
+ */
+ O startObject();
+
+ /**
+ * Indicates the end of an object in the JSON input. This method will be called after reading the
+ * closing curly bracket character ('}'
).
+ *
+ * @param object the object handler returned from {@link #startObject()}, or null if not provided
+ */
+ void endObject(O object);
+
+ /**
+ * Indicates the beginning of the name of an object member in the JSON input. This method will be
+ * called when reading the opening quote character ('"') of the member name.
+ *
+ * @param object the object handler returned from {@link #startObject()}, or null
if not
+ * provided
+ */
+ void startObjectName(O object);
+
+ /**
+ * Indicates the end of an object member name in the JSON input. This method will be called after
+ * reading the closing quote character ('"'
) of the member name.
+ *
+ * @param object the object handler returned from {@link #startObject()}, or null if not provided
+ * @param name the parsed member name
+ */
+ void endObjectName(O object, String name);
+
+ /**
+ * Indicates the beginning of the name of an object member in the JSON input. This method will be
+ * called when reading the opening quote character ('"') of the member name.
+ *
+ * @param object the object handler returned from {@link #startObject()}, or null
if not
+ * provided
+ * @param name the member name
+ */
+ void startObjectValue(O object, String name);
+
+ /**
+ * Indicates the end of an object member value in the JSON input. This method will be called after
+ * reading the last character of the member value, just after the end
method for the
+ * specific member type (like {@link #endString(String) endString()}, {@link #endNumber(String)
+ * endNumber()}, etc.).
+ *
+ * @param object the object handler returned from {@link #startObject()}, or null if not provided
+ * @param name the parsed member name
+ */
+ void endObjectValue(O object, String name);
+
+}
diff --git a/src/main/java/org/xbib/marc/json/JsonLiteral.java b/src/main/java/org/xbib/marc/json/JsonLiteral.java
new file mode 100755
index 0000000..73c35fb
--- /dev/null
+++ b/src/main/java/org/xbib/marc/json/JsonLiteral.java
@@ -0,0 +1,92 @@
+/*
+ Copyright 2016 Jörg Prante
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.xbib.marc.json;
+
+import java.io.IOException;
+
+/**
+ * A JSON literal.
+ */
+class JsonLiteral extends JsonValue {
+
+ public static final JsonLiteral NULL = new JsonLiteral("null");
+
+ public static final JsonLiteral TRUE = new JsonLiteral("true");
+
+ public static final JsonLiteral FALSE = new JsonLiteral("false");
+
+ private final String value;
+
+ private final boolean isNull;
+
+ private final boolean isTrue;
+
+ private final boolean isFalse;
+
+ JsonLiteral(String value) {
+ this.value = value;
+ isNull = "null".equals(value);
+ isTrue = "true".equals(value);
+ isFalse = "false".equals(value);
+ }
+
+ @Override
+ void write(JsonWriter writer) throws IOException {
+ writer.writeLiteral(value);
+ }
+
+ @Override
+ public String toString() {
+ return value;
+ }
+
+ @Override
+ public int hashCode() {
+ return value.hashCode();
+ }
+
+ @Override
+ public boolean isNull() {
+ return isNull;
+ }
+
+ @Override
+ public boolean isTrue() {
+ return isTrue;
+ }
+
+ @Override
+ public boolean isFalse() {
+ return isFalse;
+ }
+
+ @Override
+ public boolean isBoolean() {
+ return isTrue || isFalse;
+ }
+
+ @Override
+ public boolean asBoolean() {
+ return isNull ? super.asBoolean() : isTrue;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ return this == object || object != null && getClass() == object.getClass() && value.equals(((JsonLiteral) object).value);
+ }
+
+}
diff --git a/src/main/java/org/xbib/marc/json/JsonMapper.java b/src/main/java/org/xbib/marc/json/JsonMapper.java
new file mode 100644
index 0000000..b9aaee4
--- /dev/null
+++ b/src/main/java/org/xbib/marc/json/JsonMapper.java
@@ -0,0 +1,111 @@
+/*
+ Copyright 2016 Jörg Prante
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ */
+package org.xbib.marc.json;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ */
+public class JsonMapper {
+
+ private JsonMapper() {
+ // do not instantiate this class
+ }
+
+ public static Object asObject(JsonValue value) {
+ if (value.isBoolean()) {
+ return value.asBoolean();
+ } else if (value.isInt()) {
+ return value.asInt();
+ } else if (value.isLong()) {
+ return value.asLong();
+ } else if (value.isFloat()) {
+ return value.asFloat();
+ } else if (value.isDouble()) {
+ return value.asDouble();
+ } else if (value.isString()) {
+ return value.asString();
+ } else if (value.isArray()) {
+ return asList(value.asArray());
+ } else if (value.isObject()) {
+ return asMap(value.asObject());
+ } else {
+ return null;
+ }
+ }
+
+ public static List