You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rm...@apache.org on 2014/06/13 15:45:16 UTC

[4/6] initial import

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/pom.xml
----------------------------------------------------------------------
diff --git a/fleece-core/pom.xml b/fleece-core/pom.xml
new file mode 100644
index 0000000..cb2a0d2
--- /dev/null
+++ b/fleece-core/pom.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <parent>
+    <artifactId>fleece</artifactId>
+    <groupId>org.apache.fleece</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>fleece-core</artifactId>
+  <name>Fleece :: Core</name>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/BufferCache.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/BufferCache.java b/fleece-core/src/main/java/org/apache/fleece/core/BufferCache.java
new file mode 100644
index 0000000..9510959
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/BufferCache.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+public abstract class BufferCache<T> {
+    // alloc are expensive so using a very trivial buffer, we remove from TL to say we use it and reset it when we are done (close)
+    private final ThreadLocal<T> buffers;
+    private final int defaultSize;
+
+    public BufferCache(final int defaultSize) {
+        this.buffers = new ThreadLocal<T>() {
+            @Override
+            protected T initialValue() {
+                return BufferCache.this.newValue(defaultSize);
+            }
+        };
+        this.defaultSize = defaultSize;
+    }
+
+    protected abstract T newValue(final int defaultSize);
+
+    public T getCache() {
+        final T cachedLoadedChars = buffers.get();
+        if (cachedLoadedChars == null) {
+            return newValue(defaultSize);
+        }
+        buffers.set(null); // remove just kills the buffers
+        return cachedLoadedChars;
+    }
+
+
+    public void release(final T buffer) {
+        buffers.set(buffer);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/EscapedStringAwareJsonParser.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/EscapedStringAwareJsonParser.java b/fleece-core/src/main/java/org/apache/fleece/core/EscapedStringAwareJsonParser.java
new file mode 100644
index 0000000..56cb7a5
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/EscapedStringAwareJsonParser.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.stream.JsonParser;
+
+public interface EscapedStringAwareJsonParser extends JsonParser {
+    String getEscapedString();
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayBuilderImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayBuilderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayBuilderImpl.java
new file mode 100644
index 0000000..d903134
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayBuilderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonArrayBuilderImpl implements JsonArrayBuilder {
+    private final JsonArrayImpl array = new JsonArrayImpl();
+
+    @Override
+    public JsonArrayBuilder add(final JsonValue value) {
+        array.addInternal(value);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final String value) {
+        array.addInternal(new JsonStringImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final BigDecimal value) {
+        array.addInternal(new JsonNumberImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final BigInteger value) {
+        array.addInternal(new JsonNumberImpl(new BigDecimal(value)));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final int value) {
+        array.addInternal(new JsonLongImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final long value) {
+        array.addInternal(new JsonLongImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final double value) {
+        array.addInternal(new JsonDoubleImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final boolean value) {
+        array.add(value ? JsonValue.TRUE : JsonValue.FALSE);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder addNull() {
+        array.add(JsonValue.NULL);
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final JsonObjectBuilder builder) {
+        array.add(builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArrayBuilder add(final JsonArrayBuilder builder) {
+        array.add(builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonArray build() {
+        return array;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayImpl.java
new file mode 100644
index 0000000..a2fb350
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonArrayImpl.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+public class JsonArrayImpl extends LinkedList<JsonValue> implements JsonArray {
+    private Integer hashCode = null;
+
+    private <T> T value(final int idx, final Class<T> type) {
+        if (idx > size()) {
+            throw new IndexOutOfBoundsException(idx + "/" + size());
+        }
+        return type.cast(get(idx));
+    }
+
+    @Override
+    public JsonObject getJsonObject(final int index) {
+        return value(index, JsonObject.class);
+    }
+
+    @Override
+    public JsonArray getJsonArray(final int index) {
+        return value(index, JsonArray.class);
+    }
+
+    @Override
+    public JsonNumber getJsonNumber(final int index) {
+        return value(index, JsonNumber.class);
+    }
+
+    @Override
+    public JsonString getJsonString(final int index) {
+        return value(index, JsonString.class);
+    }
+
+    @Override
+    public <T extends JsonValue> List<T> getValuesAs(final Class<T> clazz) {
+        return (List<T>) this;
+    }
+
+    @Override
+    public String getString(final int index) {
+        return value(index, JsonString.class).getString();
+    }
+
+    @Override
+    public String getString(final int index, final String defaultValue) {
+        try {
+            return getString(index);
+        } catch (final IndexOutOfBoundsException ioobe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public int getInt(final int index) {
+        return value(index, JsonNumber.class).intValue();
+    }
+
+    @Override
+    public int getInt(final int index, final int defaultValue) {
+        try {
+            return getInt(index);
+        } catch (final IndexOutOfBoundsException ioobe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public boolean getBoolean(final int index) {
+        return value(index, JsonValue.class) == JsonValue.TRUE;
+    }
+
+    @Override
+    public boolean getBoolean(final int index, final boolean defaultValue) {
+        try {
+            return getBoolean(index);
+        } catch (final IndexOutOfBoundsException ioobe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public boolean isNull(final int index) {
+        return value(index, JsonValue.class) == JsonValue.NULL;
+    }
+
+    @Override
+    public ValueType getValueType() {
+        return ValueType.ARRAY;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder("[");
+        final Iterator<JsonValue> it = iterator();
+        boolean hasNext = it.hasNext();
+        while (hasNext) {
+            final JsonValue jsonValue = it.next();
+            if (JsonString.class.isInstance(jsonValue)) {
+                builder.append(JsonChars.QUOTE).append(jsonValue.toString()).append(JsonChars.QUOTE);
+            } else {
+                builder.append(jsonValue != JsonValue.NULL ? jsonValue.toString() : JsonChars.NULL);
+            }
+            hasNext = it.hasNext();
+            if (hasNext) {
+                builder.append(",");
+            }
+        }
+        return builder.append(']').toString();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return JsonArray.class.isInstance(obj) && super.equals(obj);
+    }
+
+    public void addInternal(final JsonValue value) {
+        super.add(value);
+    }
+
+    @Override
+    public boolean add(final JsonValue element) {
+        throw immutable();
+    }
+
+    @Override
+    public boolean addAll(final int index, final Collection<? extends JsonValue> c) {
+        throw immutable();
+    }
+
+    @Override
+    public boolean remove(final Object o) {
+        throw immutable();
+    }
+
+    @Override
+    public JsonValue remove(final int index) {
+        throw immutable();
+    }
+
+    @Override
+    public void add(final int index, final JsonValue element) {
+        throw immutable();
+    }
+
+    @Override
+    public void clear() {
+        throw immutable();
+    }
+
+    @Override
+    public boolean retainAll(final Collection<?> c) {
+        throw immutable();
+    }
+
+    @Override
+    public boolean removeAll(final Collection<?> c) {
+        throw immutable();
+    }
+
+    @Override
+    public JsonValue set(final int index, final JsonValue element) {
+        throw immutable();
+    }
+
+    private static UnsupportedOperationException immutable() {
+        throw new UnsupportedOperationException("JsonArray is immutable. You can create another one thanks to JsonArrayBuilder");
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == null) {
+            hashCode = super.hashCode();
+        }
+        return hashCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java
new file mode 100644
index 0000000..710aa54
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonBuilderFactoryImpl.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObjectBuilder;
+import java.util.Map;
+
+public class JsonBuilderFactoryImpl implements JsonBuilderFactory {
+    private final Map<String, ?> config;
+
+    public JsonBuilderFactoryImpl(final Map<String, ?> config) {
+        this.config = config;
+    }
+
+    @Override
+    public JsonObjectBuilder createObjectBuilder() {
+        return new JsonObjectBuilderImpl();
+    }
+
+    @Override
+    public JsonArrayBuilder createArrayBuilder() {
+        return new JsonArrayBuilderImpl();
+    }
+
+    @Override
+    public Map<String, ?> getConfigInUse() {
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
new file mode 100644
index 0000000..3fbc5b4
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonChars.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+public interface JsonChars {
+    char EOF = Character.MIN_VALUE;
+
+    char START_OBJECT_CHAR = '{';
+    char END_OBJECT_CHAR = '}';
+    char START_ARRAY_CHAR = '[';
+    char END_ARRAY_CHAR = ']';
+    char EOL = '\n';
+    char COMMA = ',';
+    char SPACE = ' ';
+    char KEY_SEPARATOR = ':';
+    char TRUE_T = 't';
+    char TRUE_R = 'r';
+    char TRUE_U = 'u';
+    char TRUE_E = 'e';
+    char FALSE_F = 'f';
+    char FALSE_A = 'a';
+    char FALSE_L = 'l';
+    char FALSE_S = 's';
+    char FALSE_E = 'e';
+    char NULL_N = 'n';
+    char NULL_U = 'u';
+    char NULL_L = 'l';
+    char QUOTE = '"';
+    char ZERO = '0';
+    char NINE = '9';
+    char DOT = '.';
+    char MINUS = '-';
+    char PLUS = '+';
+    char EXP_LOWERCASE = 'e';
+    char EXP_UPPERCASE = 'E';
+    char ESCAPE_CHAR = '\\';
+
+    String NULL = "null";
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
new file mode 100644
index 0000000..6d9d370
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonDoubleImpl.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonNumber;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonDoubleImpl implements JsonNumber {
+    private final double value;
+
+    public JsonDoubleImpl(final double value) {
+        this.value = value;
+    }
+
+    @Override
+    public boolean isIntegral() {
+        return false;
+    }
+
+    @Override
+    public int intValue() {
+        return (int) value;
+    }
+
+    @Override
+    public int intValueExact() {
+        return intValue();
+    }
+
+    @Override
+    public long longValue() {
+        return (long) value;
+    }
+
+    @Override
+    public long longValueExact() {
+        return (long) value;
+    }
+
+    @Override
+    public BigInteger bigIntegerValue() {
+        return new BigInteger(toString());
+    }
+
+    @Override
+    public BigInteger bigIntegerValueExact() {
+        return bigIntegerValue();
+    }
+
+    @Override
+    public double doubleValue() {
+        return value;
+    }
+
+    @Override
+    public BigDecimal bigDecimalValue() {
+        return new BigDecimal(toString());
+    }
+
+    @Override
+    public ValueType getValueType() {
+        return ValueType.NUMBER;
+    }
+
+    @Override
+    public String toString() {
+        return Double.toString(value);
+    }
+
+    @Override
+    public int hashCode() {
+        return Double.valueOf(value).hashCode();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return JsonNumber.class.isInstance(obj) && JsonNumber.class.cast(obj).doubleValue() == value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java
new file mode 100644
index 0000000..b855943
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorFactoryImpl.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class JsonGeneratorFactoryImpl implements JsonGeneratorFactory {
+    private final Map<String, ?> config;
+    private final ConcurrentMap<String, String> cache = new ConcurrentHashMap<String, String>();
+    private final boolean pretty;
+
+    public JsonGeneratorFactoryImpl(final Map<String, ?> config) {
+        this.config = config;
+        this.pretty = Boolean.TRUE.equals(config.get(JsonGenerator.PRETTY_PRINTING)) || "true".equals(config.get(JsonGenerator.PRETTY_PRINTING));
+    }
+
+    @Override
+    public JsonGenerator createGenerator(final Writer writer) {
+        if (pretty) {
+            return new JsonPrettyGeneratorImpl(writer, cache);
+        }
+        return new JsonGeneratorImpl<JsonGeneratorImpl<?>>(writer, cache);
+    }
+
+    @Override
+    public JsonGenerator createGenerator(final OutputStream out) {
+        return createGenerator(new OutputStreamWriter(out));
+    }
+
+    @Override
+    public JsonGenerator createGenerator(final OutputStream out, final Charset charset) {
+        return createGenerator(new OutputStreamWriter(out, charset));
+    }
+
+    @Override
+    public Map<String, ?> getConfigInUse() {
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorImpl.java
new file mode 100644
index 0000000..e0dd287
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonGeneratorImpl.java
@@ -0,0 +1,317 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerationException;
+import javax.json.stream.JsonGenerator;
+import java.io.IOException;
+import java.io.Writer;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.concurrent.ConcurrentMap;
+
+public class JsonGeneratorImpl<P extends JsonGeneratorImpl<?>> implements JsonGenerator, JsonChars {
+    protected static final String START_ARRAY = "[";
+    protected static final String END_ARRAY = "]";
+    protected static final String END_OBJECT = "}";
+    protected static final String START_OBJECT = "{";
+    protected static final String NULL = "null";
+    protected static final String NULL_KEY = "null:";
+
+    protected final Writer writer;
+    protected final P parent;
+    protected final boolean array;
+    protected final ConcurrentMap<String, String> cache;
+
+    protected boolean needComma = false;
+
+    public JsonGeneratorImpl(final Writer writer, final ConcurrentMap<String, String> cache) {
+        this(writer, null, false, cache);
+    }
+
+    public JsonGeneratorImpl(final Writer writer, final P parent, final boolean array,
+                             final ConcurrentMap<String, String> cache) {
+        this.writer = writer;
+        this.parent = parent;
+        this.array = array;
+        this.cache = cache;
+    }
+
+    private void addCommaIfNeeded() {
+        if (needComma) {
+            try {
+                writer.write(',');
+            } catch (final IOException e) {
+                throw new JsonGenerationException(e.getMessage(), e);
+            }
+            needComma = false;
+        }
+    }
+
+    protected JsonGenerator newJsonGenerator(final Writer writer, final P parent, final boolean array) {
+        return new JsonGeneratorImpl<P>(writer, parent, array, cache);
+    }
+
+    // we cache key only since they are generally fixed
+    private String key(final String name) {
+        if (name == null) {
+            return NULL_KEY;
+        }
+        String k = cache.get(name);
+        if (k == null) {
+            k = '"' + Strings.escape(name) + "\":";
+            cache.putIfAbsent(name, k);
+        }
+        return k;
+    }
+
+    @Override
+    public JsonGenerator writeStartObject() {
+        noCheckWriteAndForceComma(START_OBJECT);
+        return newJsonGenerator(writer, (P) this, false);
+    }
+
+    @Override
+    public JsonGenerator writeStartObject(final String name) {
+        noCheckWriteAndForceComma(key(name) + START_OBJECT);
+        return newJsonGenerator(writer, (P) this, false);
+    }
+
+    @Override
+    public JsonGenerator writeStartArray() {
+        noCheckWriteAndForceComma(START_ARRAY);
+        return newJsonGenerator(writer, (P) this, true);
+    }
+
+    @Override
+    public JsonGenerator writeStartArray(final String name) {
+        noCheckWriteAndForceComma(key(name) + START_ARRAY);
+        return newJsonGenerator(writer, (P) this, true);
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final JsonValue value) {
+        if (JsonString.class.isInstance(value)) {
+            return write(name, value == null ? null : value.toString());
+        }
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(value == null ? NULL : value.toString());
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final String value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(value == null ? NULL : "\"" + Strings.escape(value) + "\"");
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final BigInteger value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(value == null ? NULL : value.toString());
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final BigDecimal value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(value == null ? NULL : value.toString());
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final int value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final long value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final double value) {
+        checkObject();
+        checkDoubleRange(value);
+        noCheckWriteAndForceComma(key(name));
+        justWrite(String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String name, final boolean value) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public JsonGenerator writeNull(final String name) {
+        checkObject();
+        noCheckWriteAndForceComma(key(name));
+        justWrite(NULL);
+        return this;
+    }
+
+    @Override
+    public JsonGenerator writeEnd() {
+        needComma = false;
+        noCheckWriteAndForceComma(array ? END_ARRAY : END_OBJECT);
+        return parent != null ? parent : this;
+    }
+
+    @Override
+    public JsonGenerator write(final JsonValue value) {
+        noCheckWriteAndForceComma(String.valueOf(value));
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final String value) {
+        checkArray();
+        noCheckWriteAndForceComma(value);
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final BigDecimal value) {
+        checkArray();
+        noCheckWrite(String.valueOf(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final BigInteger value) {
+        checkArray();
+        noCheckWrite(String.valueOf(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final int value) {
+        checkArray();
+        noCheckWrite(Integer.toString(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final long value) {
+        checkArray();
+        noCheckWrite(Long.toString(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final double value) {
+        checkArray();
+        checkDoubleRange(value);
+        noCheckWrite(Double.toString(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator write(final boolean value) {
+        checkArray();
+        noCheckWrite(Boolean.toString(value));
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public JsonGenerator writeNull() {
+        checkArray();
+        noCheckWriteAndForceComma(NULL);
+        needComma = true;
+        return this;
+    }
+
+    @Override
+    public void close() {
+        try {
+            writer.close();
+        } catch (final IOException e) {
+            throw new JsonGenerationException(e.getMessage(), e);
+        }
+    }
+
+    @Override
+    public void flush() {
+        try {
+            writer.flush();
+        } catch (final IOException e) {
+            throw new JsonGenerationException(e.getMessage(), e);
+        }
+    }
+
+    protected JsonGenerator noCheckWriteAndForceComma(final String value) {
+        noCheckWrite(value);
+        needComma = true;
+        return this;
+    }
+
+    private void noCheckWrite(String value) {
+        addCommaIfNeeded();
+        justWrite(value);
+    }
+
+    private void justWrite(final String value) {
+        try {
+            writer.write(value);
+        } catch (final IOException e) {
+            throw new JsonGenerationException(e.getMessage(), e);
+        }
+    }
+
+    private void checkObject() {
+        if (array) {
+            throw new JsonGenerationException("write(name, param) is only valid in objects");
+        }
+    }
+
+    private void checkArray() {
+        if (!array) {
+            throw new JsonGenerationException("write(param) is only valid in arrays");
+        }
+    }
+
+    private static void checkDoubleRange(final double value) {
+        if (Double.isInfinite(value) || Double.isNaN(value)) {
+            throw new NumberFormatException("double can't be infinite and NaN");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonInMemoryParser.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonInMemoryParser.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonInMemoryParser.java
new file mode 100644
index 0000000..3f26de9
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonInMemoryParser.java
@@ -0,0 +1,165 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.stream.JsonLocation;
+import javax.json.stream.JsonParser;
+import java.math.BigDecimal;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+// we don't use visitor pattern to ensure we work with other impl of JsonObject and JsonArray
+public class JsonInMemoryParser implements EscapedStringAwareJsonParser {
+    private final Iterator<Entry> iterator;
+
+    private Entry next = null;
+
+    public JsonInMemoryParser(final JsonObject object) {
+        final List<Entry> events = new LinkedList<Entry>();
+        generateObjectEvents(events, object);
+        iterator = events.iterator();
+    }
+
+    public JsonInMemoryParser(final JsonArray array) {
+        final List<Entry> events = new LinkedList<Entry>();
+        generateArrayEvents(events, array);
+        iterator = events.iterator();
+    }
+
+    private static void generateObjectEvents(final List<Entry> events, final JsonObject object) {
+        events.add(new Entry(Event.START_OBJECT, object));
+        for (final Map.Entry<String, JsonValue> entry : object.entrySet()) {
+            events.add(new Entry(Event.KEY_NAME, new JsonStringImpl(entry.getKey())));
+            final JsonValue value = entry.getValue();
+            addValueEvents(events, value);
+        }
+        events.add(new Entry(Event.END_OBJECT, object));
+    }
+
+    private static void generateArrayEvents(final List<Entry> events, final JsonArray array) {
+        events.add(new Entry(Event.START_ARRAY, array));
+        for (final JsonValue value : array) {
+            addValueEvents(events, value);
+        }
+        events.add(new Entry(Event.END_ARRAY, array));
+    }
+
+    private static void addValueEvents(final List<Entry> events, final JsonValue value) {
+        if (JsonArray.class.isInstance(value)) {
+            generateArrayEvents(events, JsonArray.class.cast(value));
+        } else if (JsonObject.class.isInstance(value)) {
+            generateObjectEvents(events, JsonObject.class.cast(value));
+        } else if (JsonString.class.isInstance(value)) {
+            events.add(new Entry(Event.VALUE_STRING, JsonValue.class.cast(value)));
+        } else if (JsonNumber.class.isInstance(value)) {
+            events.add(new Entry(Event.VALUE_NUMBER, JsonValue.class.cast(value)));
+        } else if (value == JsonValue.TRUE) {
+            events.add(new Entry(Event.VALUE_TRUE, value));
+        } else if (value == JsonValue.FALSE) {
+            events.add(new Entry(Event.VALUE_FALSE, value));
+        } else if (value == JsonValue.NULL) {
+            events.add(new Entry(Event.VALUE_NULL, value));
+        } else {
+            throw new IllegalArgumentException(value + " not supported");
+        }
+    }
+
+    @Override
+    public boolean hasNext() {
+        return iterator.hasNext();
+    }
+
+    @Override
+    public Event next() {
+        next = iterator.next();
+        return next.event;
+    }
+
+    @Override
+    public String getString() {
+        if (JsonObject.class.isInstance(next.value) || JsonArray.class.isInstance(next.value)) {
+            throw new IllegalStateException("String is for numbers and strings");
+        }
+        return getEscapedString();
+    }
+
+    @Override
+    public boolean isIntegralNumber() {
+        if (!JsonNumber.class.isInstance(next.value)) {
+            throw new IllegalStateException("isIntegralNumber is for numbers");
+        }
+        return JsonNumber.class.cast(next.value).isIntegral();
+    }
+
+    @Override
+    public int getInt() {
+        if (!JsonNumber.class.isInstance(next.value)) {
+            throw new IllegalStateException("getInt is for numbers");
+        }
+        return JsonNumber.class.cast(next.value).intValue();
+    }
+
+    @Override
+    public long getLong() {
+        if (!JsonNumber.class.isInstance(next.value)) {
+            throw new IllegalStateException("getLong is for numbers");
+        }
+        return JsonNumber.class.cast(next.value).longValue();
+    }
+
+    @Override
+    public BigDecimal getBigDecimal() {
+        if (!JsonNumber.class.isInstance(next.value)) {
+            throw new IllegalStateException("getBigDecimal is for numbers");
+        }
+        return JsonNumber.class.cast(next.value).bigDecimalValue();
+    }
+
+    @Override
+    public JsonLocation getLocation() { // no location for in memory parsers
+        return new JsonLocationImpl(-1, -1, -1);
+    }
+
+    @Override
+    public String getEscapedString() {
+        return JsonValue.class.cast(next.value).toString();
+    }
+
+    @Override
+    public void close() {
+        // no-op
+    }
+
+    private static class Entry {
+        private final Event event;
+        private final JsonValue value;
+
+        private Entry(final Event event, final JsonValue value) {
+            this.event = event;
+            this.value = value;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
new file mode 100644
index 0000000..7b20e5b
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonLocationImpl.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.stream.JsonLocation;
+import java.io.Serializable;
+
+public class JsonLocationImpl implements JsonLocation, Serializable {
+    private final long lineNumber;
+    private final long columnNumber;
+    private final long streamOffset;
+
+    public JsonLocationImpl(final long lineNumber, final long columnNumber, final long streamOffset) {
+        this.lineNumber = lineNumber;
+        this.columnNumber = columnNumber;
+        this.streamOffset = streamOffset;
+    }
+
+    @Override
+    public long getLineNumber() {
+        return lineNumber;
+    }
+
+    @Override
+    public long getColumnNumber() {
+        return columnNumber;
+    }
+
+    @Override
+    public long getStreamOffset() {
+        return streamOffset;
+    }
+
+    @Override
+    public boolean equals(final Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        final JsonLocationImpl that = JsonLocationImpl.class.cast(o);
+        return columnNumber == that.columnNumber && lineNumber == that.lineNumber && streamOffset == that.streamOffset;
+
+    }
+
+    @Override
+    public int hashCode() {
+        int result = (int) (lineNumber ^ (lineNumber >>> 32));
+        result = 31 * result + (int) (columnNumber ^ (columnNumber >>> 32));
+        result = 31 * result + (int) (streamOffset ^ (streamOffset >>> 32));
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonLongImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonLongImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonLongImpl.java
new file mode 100644
index 0000000..f54e4b7
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonLongImpl.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonNumber;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonLongImpl implements JsonNumber {
+    private final long value;
+
+    public JsonLongImpl(final long value) {
+        this.value = value;
+    }
+
+    @Override
+    public boolean isIntegral() {
+        return false;
+    }
+
+    @Override
+    public int intValue() {
+        return (int) value;
+    }
+
+    @Override
+    public int intValueExact() {
+        return intValue();
+    }
+
+    @Override
+    public long longValue() {
+        return value;
+    }
+
+    @Override
+    public long longValueExact() {
+        return value;
+    }
+
+    @Override
+    public BigInteger bigIntegerValue() {
+        return new BigInteger(toString());
+    }
+
+    @Override
+    public BigInteger bigIntegerValueExact() {
+        return bigIntegerValue();
+    }
+
+    @Override
+    public double doubleValue() {
+        return value;
+    }
+
+    @Override
+    public BigDecimal bigDecimalValue() {
+        return new BigDecimal(toString());
+    }
+
+    @Override
+    public ValueType getValueType() {
+        return ValueType.NUMBER;
+    }
+
+    @Override
+    public String toString() {
+        return Long.toString(value);
+    }
+
+    @Override
+    public int hashCode() {
+        return (int) value;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return JsonNumber.class.isInstance(obj) && JsonNumber.class.cast(obj).longValue() == value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonNumberImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonNumberImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonNumberImpl.java
new file mode 100644
index 0000000..c992a9f
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonNumberImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonNumber;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonNumberImpl implements JsonNumber {
+    private final BigDecimal value;
+    private Integer hashCode = null;
+
+    public JsonNumberImpl(final BigDecimal decimal) {
+        this.value = decimal;
+    }
+
+    @Override
+    public boolean isIntegral() {
+        return value.scale() == 0;
+    }
+
+    @Override
+    public int intValue() {
+        return value.intValue();
+    }
+
+    @Override
+    public int intValueExact() {
+        return value.intValueExact();
+    }
+
+    @Override
+    public long longValue() {
+        return value.longValue();
+    }
+
+    @Override
+    public long longValueExact() {
+        return value.longValueExact();
+    }
+
+    @Override
+    public BigInteger bigIntegerValue() {
+        return value.toBigInteger();
+    }
+
+    @Override
+    public BigInteger bigIntegerValueExact() {
+        return value.toBigIntegerExact();
+    }
+
+    @Override
+    public double doubleValue() {
+        return value.doubleValue();
+    }
+
+    @Override
+    public BigDecimal bigDecimalValue() {
+        return value;
+    }
+
+    @Override
+    public ValueType getValueType() {
+        return ValueType.NUMBER;
+    }
+
+    @Override
+    public String toString() {
+        return value.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == null) {
+            hashCode = value.hashCode();
+        }
+        return hashCode;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return JsonNumber.class.isInstance(obj) && JsonNumber.class.cast(obj).bigDecimalValue().equals(value);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectBuilderImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectBuilderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectBuilderImpl.java
new file mode 100644
index 0000000..8b545a2
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectBuilderImpl.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonValue;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+public class JsonObjectBuilderImpl implements JsonObjectBuilder {
+    private final JsonObjectImpl delegate = new JsonObjectImpl();
+
+    @Override
+    public JsonObjectBuilder add(final String name, final JsonValue value) {
+        delegate.putInternal(name, value);
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final String value) {
+        delegate.putInternal(name, new JsonStringImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final BigInteger value) {
+        delegate.putInternal(name, new JsonNumberImpl(new BigDecimal(value)));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final BigDecimal value) {
+        delegate.putInternal(name, new JsonNumberImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final int value) {
+        delegate.putInternal(name, new JsonLongImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final long value) {
+        delegate.putInternal(name, new JsonLongImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final double value) {
+        delegate.putInternal(name, new JsonDoubleImpl(value));
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final boolean value) {
+        delegate.putInternal(name, value ? JsonValue.TRUE : JsonValue.FALSE);
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder addNull(final String name) {
+        delegate.putInternal(name, JsonValue.NULL);
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final JsonObjectBuilder builder) {
+        delegate.putInternal(name, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonObjectBuilder add(final String name, final JsonArrayBuilder builder) {
+        delegate.putInternal(name, builder.build());
+        return this;
+    }
+
+    @Override
+    public JsonObject build() {
+        return delegate;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectImpl.java
new file mode 100644
index 0000000..01a2615
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonObjectImpl.java
@@ -0,0 +1,179 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class JsonObjectImpl extends LinkedHashMap<String, JsonValue> implements JsonObject {
+    private Integer hashCode = null;
+
+    private <T> T value(final String name, final Class<T> clazz) {
+        final Object v = get(name);
+        if (v != null) {
+            return clazz.cast(v);
+        }
+        throw new NullPointerException("no mapping for " + name);
+    }
+
+    @Override
+    public JsonArray getJsonArray(final String name) {
+        return value(name, JsonArray.class);
+    }
+
+    @Override
+    public JsonObject getJsonObject(final String name) {
+        return value(name, JsonObject.class);
+    }
+
+    @Override
+    public JsonNumber getJsonNumber(final String name) {
+        return value(name, JsonNumber.class);
+    }
+
+    @Override
+    public JsonString getJsonString(final String name) {
+        return value(name, JsonString.class);
+    }
+
+    @Override
+    public String getString(final String name) {
+        final JsonString str = getJsonString(name);
+        return str != null ? str.getString() : null;
+    }
+
+    @Override
+    public String getString(final String name, final String defaultValue) {
+        try {
+            return getJsonString(name).getString();
+        } catch (final NullPointerException npe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public int getInt(final String name) {
+        return getJsonNumber(name).intValue();
+    }
+
+    @Override
+    public int getInt(final String name, final int defaultValue) {
+        try {
+            return getJsonNumber(name).intValue();
+        } catch (final NullPointerException npe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public boolean getBoolean(final String name) {
+        return value(name, JsonValue.class) == JsonValue.TRUE;
+    }
+
+    @Override
+    public boolean getBoolean(final String name, final boolean defaultValue) {
+        try {
+            return getBoolean(name);
+        } catch (final NullPointerException npe) {
+            return defaultValue;
+        }
+    }
+
+    @Override
+    public boolean isNull(final String name) {
+        return value(name, JsonValue.class) == JsonValue.NULL;
+    }
+
+    @Override
+    public ValueType getValueType() {
+        return ValueType.OBJECT;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder builder = new StringBuilder("{");
+        final Iterator<Map.Entry<String, JsonValue>> it = entrySet().iterator();
+        boolean hasNext = it.hasNext();
+        while (hasNext) {
+            final Map.Entry<String, JsonValue> entry = it.next();
+
+            builder.append('"').append(entry.getKey()).append("\":");
+
+            final JsonValue value = entry.getValue();
+            if (JsonString.class.isInstance(value)) {
+                builder.append(JsonChars.QUOTE).append(value.toString()).append(JsonChars.QUOTE);
+            } else {
+                builder.append(value != JsonValue.NULL ? value.toString() : JsonChars.NULL);
+            }
+
+            hasNext = it.hasNext();
+            if (hasNext) {
+                builder.append(",");
+            }
+        }
+        return builder.append('}').toString();
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        return JsonObject.class.isInstance(obj) && super.equals(obj);
+    }
+
+    @Override
+    public void clear() {
+        throw immutable();
+    }
+
+    @Override
+    public JsonValue put(String key, JsonValue value) {
+        throw immutable();
+    }
+
+    @Override
+    public void putAll(Map<? extends String, ? extends JsonValue> jsonObject) {
+        throw immutable();
+    }
+
+    @Override
+    public JsonValue remove(Object key) {
+        throw immutable();
+    }
+
+    private static UnsupportedOperationException immutable() {
+        throw new UnsupportedOperationException("JsonObject is immutable. You can create another one thanks to JsonObjectBuilder");
+    }
+
+    public void putInternal(final String name, final JsonValue value) {
+        super.put(name, value);
+    }
+
+    @Override
+    public int hashCode() {
+        if (hashCode == null) {
+            hashCode = super.hashCode();
+        }
+        return hashCode;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
new file mode 100644
index 0000000..b138d84
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonParserFactoryImpl.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParserFactory;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+public class JsonParserFactoryImpl implements JsonParserFactory {
+    public static final String MAX_STRING_LENGTH = "org.apache.fleece.max-string-length";
+    public static final int DEFAULT_MAX_SIZE = Integer.getInteger(MAX_STRING_LENGTH, 8192);
+
+    private final Map<String, ?> config;
+    private final int maxSize;
+
+    public JsonParserFactoryImpl(final Map<String, ?> config) {
+        this.config = config;
+        final Object maxStringSize = config.get(MAX_STRING_LENGTH);
+        if (maxStringSize == null) {
+            maxSize = DEFAULT_MAX_SIZE;
+        } else if (Number.class.isInstance(maxStringSize)) {
+            maxSize = Number.class.cast(maxStringSize).intValue();
+        } else {
+            maxSize = Integer.parseInt(maxStringSize.toString());
+        }
+    }
+
+    @Override
+    public JsonParser createParser(final Reader reader) {
+        return new JsonStreamParser(reader, maxSize);
+    }
+
+    @Override
+    public JsonParser createParser(final InputStream in) {
+        return new JsonStreamParser(in, maxSize);
+    }
+
+    @Override
+    public JsonParser createParser(final InputStream in, final Charset charset) {
+        return new JsonStreamParser(in, charset, maxSize);
+    }
+
+    @Override
+    public JsonParser createParser(final JsonObject obj) {
+        return new JsonInMemoryParser(obj);
+    }
+
+    @Override
+    public JsonParser createParser(final JsonArray array) {
+        return new JsonInMemoryParser(array);
+    }
+
+    @Override
+    public Map<String, ?> getConfigInUse() {
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonPrettyGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonPrettyGeneratorImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonPrettyGeneratorImpl.java
new file mode 100644
index 0000000..ff965bd
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonPrettyGeneratorImpl.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.stream.JsonGenerationException;
+import javax.json.stream.JsonGenerator;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.concurrent.ConcurrentMap;
+
+public class JsonPrettyGeneratorImpl extends JsonGeneratorImpl<JsonPrettyGeneratorImpl> {
+    private static final String DEFAULT_INDENTATION = "  ";
+
+    private String indent; // should be final but writeEnd needs it not final, we could change write() to support indent
+
+    public JsonPrettyGeneratorImpl(final Writer writer, final ConcurrentMap<String, String> cache) {
+        this(writer, null, false, "", cache);
+    }
+
+    public JsonPrettyGeneratorImpl(final Writer writer, final JsonPrettyGeneratorImpl parent,
+                                   final boolean array, final String prefix,
+                                   final ConcurrentMap<String, String> cache) {
+        super(writer, parent, array, cache);
+        this.indent = prefix;
+    }
+
+    private void addCommaIfNeeded() {
+        if (needComma) {
+            try {
+                writer.write(',');
+                ln();
+            } catch (final IOException e) {
+                throw new JsonGenerationException(e.getMessage(), e);
+            }
+            needComma = false;
+        }
+    }
+
+    private void ln() {
+        try {
+            writer.write('\n');
+        } catch (final IOException e) {
+            throw new JsonGenerationException(e.getMessage(), e);
+        }
+    }
+
+    private String nextIndent() {
+        return indent != null ? indent + DEFAULT_INDENTATION : null;
+    }
+
+    @Override
+    protected JsonGenerator newJsonGenerator(final Writer writer, final JsonPrettyGeneratorImpl parent, final boolean array) {
+        return new JsonPrettyGeneratorImpl(writer, parent, array, nextIndent(), cache);
+    }
+
+    @Override
+    public JsonGenerator writeStartObject() {
+        final JsonGenerator generator = super.writeStartObject();
+        ln();
+        return generator;
+    }
+
+    @Override
+    public JsonGenerator writeStartObject(final String name) {
+        final JsonGenerator generator = super.writeStartObject(name);
+        ln();
+        return generator;
+    }
+
+    @Override
+    public JsonGenerator writeStartArray() {
+        final JsonGenerator generator = super.writeStartArray();
+        ln();
+        return generator;
+    }
+
+    @Override
+    public JsonGenerator writeStartArray(final String name) {
+        final JsonGenerator generator = super.writeStartArray(name);
+        ln();
+        return generator;
+    }
+
+    @Override
+    public JsonGenerator writeEnd() {
+        ln();
+        needComma = false;
+        final String thisIndent = indent;
+        indent = parent != null ? parent.indent : indent;
+        noCheckWriteAndForceComma(array ? "]" : "}");
+        indent = thisIndent;
+        return parent != null ? parent : this;
+    }
+
+    @Override
+    protected JsonGenerator noCheckWriteAndForceComma(final String value) {
+        addCommaIfNeeded();
+        try {
+            if (indent != null) {
+                writer.write(indent);
+            }
+            writer.write(value);
+        } catch (final IOException e) {
+            throw new JsonGenerationException(e.getMessage(), e);
+        }
+        needComma = true;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonProviderImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonProviderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonProviderImpl.java
new file mode 100644
index 0000000..efd33ce
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonProviderImpl.java
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+import javax.json.spi.JsonProvider;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParserFactory;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class JsonProviderImpl extends JsonProvider {
+    @Override
+    public JsonParser createParser(final InputStream in) {
+        return createParserFactory(Collections.<String, Object>emptyMap()).createParser(in);
+    }
+
+    @Override
+    public JsonParser createParser(final Reader reader) {
+        return createParserFactory(Collections.<String, Object>emptyMap()).createParser(reader);
+    }
+
+    @Override
+    public JsonReader createReader(final InputStream in) {
+        return new JsonReaderImpl(in);
+    }
+
+    @Override
+    public JsonReader createReader(final Reader reader) {
+        return new JsonReaderImpl(reader);
+    }
+
+    @Override
+    public JsonParserFactory createParserFactory(final Map<String, ?> config) {
+        return new JsonParserFactoryImpl(config);
+    }
+
+    @Override
+    public JsonReaderFactory createReaderFactory(final Map<String, ?> config) {
+        return new JsonReaderFactoryImpl(config);
+    }
+
+    @Override
+    public JsonGenerator createGenerator(final Writer writer) {
+        return new JsonGeneratorImpl(writer, new ConcurrentHashMap<String, String>());
+    }
+
+    @Override
+    public JsonGenerator createGenerator(final OutputStream out) {
+        return createGenerator(new OutputStreamWriter(out));
+    }
+
+    @Override
+    public JsonGeneratorFactory createGeneratorFactory(final Map<String, ?> config) {
+        return new JsonGeneratorFactoryImpl(config);
+    }
+
+    @Override
+    public JsonWriter createWriter(final Writer writer) {
+        return new JsonWriterImpl(createGenerator(writer));
+    }
+
+    @Override
+    public JsonWriter createWriter(final OutputStream out) {
+        return createWriter(new OutputStreamWriter(out));
+    }
+
+    @Override
+    public JsonWriterFactory createWriterFactory(final Map<String, ?> config) {
+        return new JsonWriterFactoryImpl(config);
+    }
+
+    @Override
+    public JsonObjectBuilder createObjectBuilder() {
+        return new JsonObjectBuilderImpl();
+    }
+
+    @Override
+    public JsonArrayBuilder createArrayBuilder() {
+        return new JsonArrayBuilderImpl();
+    }
+
+    @Override
+    public JsonBuilderFactory createBuilderFactory(final Map<String, ?> config) {
+        return new JsonBuilderFactoryImpl(config);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java
new file mode 100644
index 0000000..934a299
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderFactoryImpl.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.Map;
+
+public class JsonReaderFactoryImpl implements JsonReaderFactory {
+    private final Map<String, ?> config;
+
+    public JsonReaderFactoryImpl(final Map<String, ?> config) {
+        this.config = config;
+    }
+
+    @Override
+    public JsonReader createReader(final Reader reader) {
+        return new JsonReaderImpl(reader);
+    }
+
+    @Override
+    public JsonReader createReader(final InputStream in) {
+        return new JsonReaderImpl(in);
+    }
+
+    @Override
+    public JsonReader createReader(final InputStream in, final Charset charset) {
+        return new JsonReaderImpl(new InputStreamReader(in, charset));
+    }
+
+    @Override
+    public Map<String, ?> getConfigInUse() {
+        return config;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
new file mode 100644
index 0000000..03d52f2
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderImpl.java
@@ -0,0 +1,331 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import javax.json.JsonArray;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonStructure;
+import javax.json.JsonValue;
+import javax.json.stream.JsonParser;
+import javax.json.stream.JsonParsingException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+
+public class JsonReaderImpl implements JsonReader {
+    private final EscapedStringAwareJsonParser parser;
+    private final JsonReaderListenerFactory listenerFactory;
+
+    public JsonReaderImpl(final InputStream in) {
+        this(new JsonStreamParser(in, JsonParserFactoryImpl.DEFAULT_MAX_SIZE), new JsonListenerFactory());
+    }
+
+    public JsonReaderImpl(final Reader in) {
+        this(new JsonStreamParser(in, JsonParserFactoryImpl.DEFAULT_MAX_SIZE), new JsonListenerFactory());
+    }
+
+    public JsonReaderImpl(final EscapedStringAwareJsonParser parser, final JsonReaderListenerFactory listenerFactory) {
+        this.parser = parser;
+        this.listenerFactory = listenerFactory;
+    }
+
+    @Override
+    public JsonStructure read() {
+        if (!parser.hasNext()) {
+            throw new JsonParsingException("Nothing to read", new JsonLocationImpl(1, 1, 0));
+        }
+        switch (parser.next()) {
+            case START_OBJECT:
+                final JsonReaderListener subObject = listenerFactory.subObject();
+                parseObject(subObject);
+                return JsonObject.class.cast(subObject.getObject());
+            case START_ARRAY:
+                final JsonReaderListener subArray = listenerFactory.subArray();
+                parseArray(subArray);
+                return JsonArray.class.cast(subArray.getObject());
+            default:
+                throw new JsonParsingException("Unknown structure: " + parser.next(), parser.getLocation());
+        }
+    }
+
+    @Override
+    public JsonObject readObject() {
+        return JsonObject.class.cast(read());
+    }
+
+    @Override
+    public JsonArray readArray() {
+        return JsonArray.class.cast(read());
+    }
+
+    @Override
+    public void close() {
+        parser.close();
+    }
+
+    private static class JsonListenerFactory implements JsonReaderListenerFactory {
+        @Override
+        public JsonReaderListener subObject() {
+            return new JsonObjectListener();
+        }
+
+        @Override
+        public JsonReaderListener subArray() {
+            return new JsonArrayListener();
+        }
+    }
+
+    private static class JsonObjectListener implements JsonReaderListener {
+        private JsonObjectImpl object = new JsonObjectImpl();
+        private String key = null;
+
+        @Override
+        public Object getObject() {
+            return object;
+        }
+
+        @Override
+        public void onKey(final String string) {
+            key = string;
+        }
+
+        @Override
+        public void onValue(final String string, final String escaped) {
+            final JsonStringImpl value = new JsonStringImpl(string, escaped);
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onLong(final long aLong) {
+            final JsonLongImpl value = new JsonLongImpl(aLong);
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onBigDecimal(final BigDecimal bigDecimal) {
+            final JsonNumberImpl value = new JsonNumberImpl(bigDecimal);
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onNull() {
+            final JsonValue value = JsonValue.NULL;
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onTrue() {
+            final JsonValue value = JsonValue.TRUE;
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onFalse() {
+            final JsonValue value = JsonValue.FALSE;
+            object.putInternal(key, value);
+        }
+
+        @Override
+        public void onObject(final Object obj) {
+            final JsonObject jsonObject = JsonObject.class.cast(obj);
+            object.putInternal(key, jsonObject);
+        }
+
+        @Override
+        public void onArray(final Object arr) {
+            final JsonArray jsonArry = JsonArray.class.cast(arr);
+            object.putInternal(key, jsonArry);
+        }
+    }
+
+    private static class JsonArrayListener implements JsonReaderListener {
+        private JsonArrayImpl array = new JsonArrayImpl();
+        private String key = null;
+
+        @Override
+        public Object getObject() {
+            return array;
+        }
+
+        @Override
+        public void onKey(final String string) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public void onValue(final String string, final String escaped) {
+            final JsonStringImpl value = new JsonStringImpl(string, escaped);
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onLong(final long aLong) {
+            final JsonLongImpl value = new JsonLongImpl(aLong);
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onBigDecimal(final BigDecimal bigDecimal) {
+            final JsonNumberImpl value = new JsonNumberImpl(bigDecimal);
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onNull() {
+            final JsonValue value = JsonValue.NULL;
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onTrue() {
+            final JsonValue value = JsonValue.TRUE;
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onFalse() {
+            final JsonValue value = JsonValue.FALSE;
+            array.addInternal(value);
+        }
+
+        @Override
+        public void onObject(final Object obj) {
+            final JsonObject jsonObject = JsonObject.class.cast(obj);
+            array.addInternal(jsonObject);
+        }
+
+        @Override
+        public void onArray(final Object arr) {
+            final JsonArray jsonArry = JsonArray.class.cast(arr);
+            array.addInternal(jsonArry);
+        }
+    }
+
+    private void parseObject(final JsonReaderListener listener) {
+        while (parser.hasNext()) {
+            final JsonParser.Event next = parser.next();
+            switch (next) {
+                case KEY_NAME:
+                    listener.onKey(parser.getString());
+                    break;
+
+                case VALUE_STRING:
+                    listener.onValue(parser.getString(), parser.getEscapedString());
+                    break;
+
+                case START_OBJECT:
+                    final JsonReaderListener subListenerObject = listenerFactory.subObject();
+                    parseObject(subListenerObject);
+                    listener.onObject(subListenerObject.getObject());
+                    break;
+
+                case START_ARRAY:
+                    final JsonReaderListener subListenerArray = listenerFactory.subArray();
+                    parseArray(subListenerArray);
+                    listener.onArray(subListenerArray.getObject());
+                    break;
+
+                case VALUE_NUMBER:
+                    if (parser.isIntegralNumber()) {
+                        listener.onLong(parser.getLong());
+                    } else {
+                        listener.onBigDecimal(parser.getBigDecimal());
+                    }
+                    break;
+
+                case VALUE_NULL:
+                    listener.onNull();
+                    break;
+
+                case VALUE_TRUE:
+                    listener.onTrue();
+                    break;
+
+                case VALUE_FALSE:
+                    listener.onFalse();
+                    break;
+
+                case END_OBJECT:
+                    return;
+
+                case END_ARRAY:
+                    throw new JsonParsingException("']', shouldn't occur", JsonStreamParser.location(parser));
+
+                default:
+                    throw new JsonParsingException(next.name() + ", shouldn't occur", JsonStreamParser.location(parser));
+            }
+        }
+    }
+
+    private void parseArray(final JsonReaderListener listener) {
+        while (parser.hasNext()) {
+            final JsonParser.Event next = parser.next();
+            switch (next) {
+                case VALUE_STRING:
+                    listener.onValue(parser.getString(), parser.getEscapedString());
+                    break;
+
+                case VALUE_NUMBER:
+                    if (parser.isIntegralNumber()) {
+                        listener.onLong(parser.getLong());
+                    } else {
+                        listener.onBigDecimal(parser.getBigDecimal());
+                    }
+                    break;
+
+                case START_OBJECT:
+                    final JsonReaderListener subListenerObject = listenerFactory.subObject();
+                    parseObject(subListenerObject);
+                    listener.onObject(subListenerObject.getObject());
+                    break;
+
+                case START_ARRAY:
+                    final JsonReaderListener subListenerArray = listenerFactory.subArray();
+                    parseArray(subListenerArray);
+                    listener.onArray(subListenerArray.getObject());
+                    break;
+
+                case END_ARRAY:
+                    return;
+
+                case VALUE_NULL:
+                    listener.onNull();
+                    break;
+
+                case VALUE_TRUE:
+                    listener.onTrue();
+                    break;
+
+                case VALUE_FALSE:
+                    listener.onFalse();
+                    break;
+
+                case KEY_NAME:
+                    throw new JsonParsingException("array doesn't have keys", JsonStreamParser.location(parser));
+
+                case END_OBJECT:
+                    throw new JsonParsingException("'}', shouldn't occur", JsonStreamParser.location(parser));
+
+                default:
+                    throw new JsonParsingException(next.name() + ", shouldn't occur", JsonStreamParser.location(parser));
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderListener.java
----------------------------------------------------------------------
diff --git a/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderListener.java b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderListener.java
new file mode 100644
index 0000000..b3ba294
--- /dev/null
+++ b/fleece-core/src/main/java/org/apache/fleece/core/JsonReaderListener.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.fleece.core;
+
+import java.math.BigDecimal;
+
+public interface JsonReaderListener {
+    Object getObject();
+
+    void onKey(String string);
+
+    void onValue(String string, String escaped);
+
+    void onLong(long aLong);
+
+    void onBigDecimal(BigDecimal bigDecimal);
+
+    void onNull();
+
+    void onTrue();
+
+    void onFalse();
+
+    void onObject(Object object);
+
+    void onArray(Object array);
+}