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:14 UTC

[2/6] initial import

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrMessageBodyWriter.java
----------------------------------------------------------------------
diff --git a/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrMessageBodyWriter.java b/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrMessageBodyWriter.java
new file mode 100644
index 0000000..dc77a30
--- /dev/null
+++ b/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrMessageBodyWriter.java
@@ -0,0 +1,88 @@
+/*
+ * 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.jaxrs;
+
+import javax.json.Json;
+import javax.json.JsonStructure;
+import javax.json.JsonWriter;
+import javax.json.JsonWriterFactory;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+
+import static javax.ws.rs.core.MediaType.WILDCARD;
+
+@Provider
+@Produces(WILDCARD)
+public class JsrMessageBodyWriter implements MessageBodyWriter<JsonStructure> {
+    private final JsonWriterFactory factory;
+    private final boolean close;
+
+    public JsrMessageBodyWriter() {
+        this(Json.createWriterFactory(Collections.<String, Object>emptyMap()), false);
+    }
+
+    public JsrMessageBodyWriter(final JsonWriterFactory factory, final boolean closeStreams) {
+        this.factory = factory;
+        this.close = closeStreams;
+    }
+
+    @Override
+    public boolean isWriteable(final Class<?> aClass, final Type type,
+                               final Annotation[] annotations, final MediaType mediaType) {
+        return JsonStructure.class.isAssignableFrom(aClass);
+    }
+
+    @Override
+    public long getSize(final JsonStructure jsonStructure, final Class<?> aClass,
+                        final Type type, final Annotation[] annotations,
+                        final MediaType mediaType) {
+        return -1;
+    }
+
+    @Override
+    public void writeTo(final JsonStructure jsonStructure,
+                        final Class<?> aClass, final Type type,
+                        final Annotation[] annotations, final MediaType mediaType,
+                        final MultivaluedMap<String, Object> stringObjectMultivaluedMap,
+                        final OutputStream outputStream) throws IOException, WebApplicationException {
+        JsonWriter writer = null;
+        try {
+            writer = factory.createWriter(outputStream);
+            writer.write(jsonStructure);
+        } finally {
+            if (writer != null) {
+                if (close) {
+                    writer.close();
+                } else if (Flushable.class.isInstance(writer)) {
+                    Flushable.class.cast(writer).flush();
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrProvider.java
----------------------------------------------------------------------
diff --git a/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrProvider.java b/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrProvider.java
new file mode 100644
index 0000000..22a2996
--- /dev/null
+++ b/fleece-jaxrs/src/main/java/org/apache/fleece/jaxrs/JsrProvider.java
@@ -0,0 +1,35 @@
+/*
+ * 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.jaxrs;
+
+import javax.json.JsonStructure;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Produces;
+import javax.ws.rs.ext.Provider;
+
+import static javax.ws.rs.core.MediaType.WILDCARD;
+
+@Provider
+@Produces(WILDCARD)
+@Consumes(WILDCARD)
+public class JsrProvider extends DelegateProvider<JsonStructure> {
+    public JsrProvider() {
+        super(new JsrMessageBodyReader(), new JsrMessageBodyWriter());
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/FleeceProviderTest.java
----------------------------------------------------------------------
diff --git a/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/FleeceProviderTest.java b/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/FleeceProviderTest.java
new file mode 100644
index 0000000..4493b91
--- /dev/null
+++ b/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/FleeceProviderTest.java
@@ -0,0 +1,161 @@
+/*
+ * 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.jaxrs;
+
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.local.LocalConduit;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.GenericType;
+import javax.ws.rs.core.MediaType;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class FleeceProviderTest {
+    private final static String ENDPOINT_ADDRESS = "local://fleece";
+    private static Server server;
+
+    @BeforeClass
+    public static void bindEndpoint() throws Exception {
+        final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(FleeceResource.class);
+        sf.setProviders(asList(new FleeceProvider<Object>()));
+        sf.setResourceProvider(FleeceResource.class, new SingletonResourceProvider(new FleeceResource(), false));
+        sf.setAddress(ENDPOINT_ADDRESS);
+        server = sf.create();
+    }
+
+    @AfterClass
+    public static void unbind() throws Exception {
+        server.stop();
+        server.destroy();
+    }
+
+    @Test
+    public void asParam() {
+        final String result = client().path("fleece").type(MediaType.APPLICATION_JSON_TYPE).post(new Fleece("client")).readEntity(String.class);
+        assertTrue(Boolean.parseBoolean(result));
+    }
+
+    @Test
+    public void object() {
+        final Fleece fleece = client().path("fleece").get(Fleece.class);
+        assertEquals("fleece", fleece.getName());
+    }
+
+    @Test
+    public void array() {
+        final Fleece[] fleece = client().path("fleece/all1").get(Fleece[].class);
+        assertEquals(2, fleece.length);
+        for (int i = 0; i < fleece.length; i++) {
+            assertEquals("fleece" + (i + 1), fleece[i].getName());
+        }
+    }
+
+    @Test
+    public void list() {
+        final ParameterizedType list = new ParameterizedType() {
+            @Override
+            public Type[] getActualTypeArguments() {
+                return new Type[]{Fleece.class};
+            }
+
+            @Override
+            public Type getRawType() {
+                return List.class;
+            }
+
+            @Override
+            public Type getOwnerType() {
+                return null;
+            }
+        };
+        final List<Fleece> fleeces = client().path("fleece/all2").get(new GenericType<List<Fleece>>(list));
+        assertEquals(2, fleeces.size());
+        int i = 1;
+        for (final Fleece f : fleeces) {
+            assertEquals("fleece" + i, f.getName());
+            i++;
+        }
+    }
+
+    private static WebClient client() {
+        final WebClient client = WebClient.create(ENDPOINT_ADDRESS, asList(new FleeceProvider<Object>())).accept(MediaType.APPLICATION_JSON_TYPE);
+        WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);
+        return client;
+    }
+
+    public static class Fleece {
+        private String name;
+
+        public Fleece(final String name) {
+            this.name = name;
+        }
+
+        public Fleece() {
+            // no-op
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(final String name) {
+            this.name = name;
+        }
+    }
+
+    @Path("fleece")
+    public static class FleeceResource {
+        @GET
+        public Fleece fleece() {
+            return new Fleece("fleece");
+        }
+
+        @GET
+        @Path("all1")
+        public Fleece[] fleeces1() {
+            return new Fleece[] { new Fleece("fleece1"), new Fleece("fleece2") };
+        }
+
+        @GET
+        @Path("all2")
+        public List<Fleece> fleeces2() {
+            return asList(fleeces1());
+        }
+
+        @POST
+        public String asParam(final Fleece f) {
+            return Boolean.toString("client".equals(f.getName()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/JsrProviderTest.java
----------------------------------------------------------------------
diff --git a/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/JsrProviderTest.java b/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/JsrProviderTest.java
new file mode 100644
index 0000000..04419a4
--- /dev/null
+++ b/fleece-jaxrs/src/test/java/org/apache/fleece/jaxrs/JsrProviderTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.jaxrs;
+
+import org.apache.cxf.endpoint.Server;
+import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
+import org.apache.cxf.transport.local.LocalConduit;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonValue;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import java.util.Iterator;
+
+import static java.util.Arrays.asList;
+import static org.junit.Assert.assertEquals;
+
+public class JsrProviderTest {
+    private final static String ENDPOINT_ADDRESS = "local://fleece";
+    private static Server server;
+
+    @BeforeClass
+    public static void bindEndpoint() throws Exception {
+        final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(FleeceResource.class);
+        sf.setProviders(asList(new JsrProvider()));
+        sf.setResourceProvider(FleeceResource.class, new SingletonResourceProvider(new FleeceResource(), false));
+        sf.setAddress(ENDPOINT_ADDRESS);
+        server = sf.create();
+    }
+
+    @AfterClass
+    public static void unbind() throws Exception {
+        server.stop();
+        server.destroy();
+    }
+
+    @Test
+    public void object() {
+        final JsonObject object = client().path("fleece/object").get(JsonObject.class);
+        assertEquals(2, object.size());
+        for (int i = 1; i <= 2; i++) {
+            assertEquals(i, object.getInt(Character.toString((char) ('a' + i - 1))));
+        }
+    }
+
+    @Test
+    public void array() {
+        final JsonArray array = client().path("fleece/array").get(JsonArray.class);
+        assertEquals(2, array.size());
+        final Iterator<JsonValue> ints = array.iterator();
+        for (int i = 1; i <= 2; i++) {
+            final JsonValue next = ints.next();
+            assertEquals(JsonValue.ValueType.NUMBER, next.getValueType());
+            assertEquals(i, JsonNumber.class.cast(next).intValue());
+        }
+    }
+
+    private static WebClient client() {
+        final WebClient client = WebClient.create(ENDPOINT_ADDRESS, asList(new JsrProvider())).accept(MediaType.APPLICATION_JSON_TYPE);
+        WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);
+        return client;
+    }
+
+    @Path("fleece")
+    public static class FleeceResource {
+        @GET
+        @Path("array")
+        public JsonArray array() {
+            return Json.createArrayBuilder().add(1).add(2).build();
+        }
+
+        @GET
+        @Path("object")
+        public JsonObject object() {
+            return Json.createObjectBuilder().add("a", 1).add("b", 2).build();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/pom.xml
----------------------------------------------------------------------
diff --git a/fleece-mapper/pom.xml b/fleece-mapper/pom.xml
new file mode 100644
index 0000000..3806cad
--- /dev/null
+++ b/fleece-mapper/pom.xml
@@ -0,0 +1,40 @@
+<?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-mapper</artifactId>
+  <name>Fleece :: Mapper</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.fleece</groupId>
+      <artifactId>fleece-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/Converter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/Converter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/Converter.java
new file mode 100644
index 0000000..fbed98c
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/Converter.java
@@ -0,0 +1,24 @@
+/*
+ * 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.mapper;
+
+public interface Converter<T> {
+    String toString(T instance);
+    T fromString(String text);
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceConverter.java
new file mode 100644
index 0000000..726afa1
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceConverter.java
@@ -0,0 +1,31 @@
+/*
+ * 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.mapper;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface FleeceConverter {
+    Class<? extends Converter<?>> value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceIgnore.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceIgnore.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceIgnore.java
new file mode 100644
index 0000000..6f8e545
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/FleeceIgnore.java
@@ -0,0 +1,36 @@
+/*
+ * 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.mapper;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface FleeceIgnore {
+    /**
+     * Example: @FleeceIgnore(minVersion = 2) will ignore the value until version is set to 2, 3, ...
+     *
+     * @return the first version the decorated field is not ignored.
+     */
+    int minVersion() default -1;
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/Mapper.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/Mapper.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/Mapper.java
new file mode 100644
index 0000000..8e9ea82
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/Mapper.java
@@ -0,0 +1,554 @@
+/*
+ * 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.mapper;
+
+import org.apache.fleece.core.JsonObjectImpl;
+import org.apache.fleece.mapper.converter.EnumConverter;
+import org.apache.fleece.mapper.reflection.Mappings;
+
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonValue;
+import javax.json.stream.JsonGenerator;
+import javax.json.stream.JsonGeneratorFactory;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static java.util.Arrays.asList;
+
+public class Mapper {
+    protected static final JsonObjectImpl EMPTY_OBJECT = new JsonObjectImpl();
+
+    protected final Mappings mappings = new Mappings();
+    protected final JsonReaderFactory readerFactory;
+    protected final JsonGeneratorFactory generatorFactory;
+    protected final boolean close;
+    protected final ConcurrentMap<Class<?>, Converter<?>> converters;
+    protected final int version;
+
+    public Mapper(final JsonReaderFactory readerFactory, final JsonGeneratorFactory generatorFactory,
+                  final boolean doClose, final Map<Class<?>, Converter<?>> converters,
+                  final int version) {
+        this.readerFactory = readerFactory;
+        this.generatorFactory = generatorFactory;
+        this.close = doClose;
+        this.converters = new ConcurrentHashMap<Class<?>, Converter<?>>(converters);
+        this.version = version;
+    }
+
+    private static JsonGenerator writePrimitives(final JsonGenerator generator, final Object value) {
+        if (value == null) {
+            return null; // fake a write
+        }
+
+        final Class<?> type = value.getClass();
+        if (type == String.class) {
+            return generator.write(value.toString());
+        } else if (type == long.class || type == Long.class) {
+            return generator.write(Long.class.cast(value).longValue());
+        } else if (type == int.class || type == Integer.class) {
+            return generator.write(Integer.class.cast(value).intValue());
+        } else if (type == double.class || type == Double.class
+                || type == float.class || type == Float.class) {
+            return generator.write(Number.class.cast(value).doubleValue());
+        } else if (type == boolean.class || type == Boolean.class) {
+            return generator.write(Boolean.class.cast(value).booleanValue());
+        } else if (type == BigDecimal.class) {
+            return generator.write(BigDecimal.class.cast(value));
+        } else if (type == BigInteger.class) {
+            return generator.write(BigInteger.class.cast(value));
+        }
+        return null;
+    }
+
+    private static JsonGenerator writePrimitives(final JsonGenerator generator, final String key, final Class<?> type, final Object value) {
+        if (type == String.class) {
+            return generator.write(key, value.toString());
+        } else if (type == long.class || type == Long.class) {
+            return generator.write(key, Long.class.cast(value).longValue());
+        } else if (type == int.class || type == Integer.class) {
+            return generator.write(key, Integer.class.cast(value).intValue());
+        } else if (type == double.class || type == Double.class
+                || type == float.class || type == Float.class) {
+            return generator.write(key, Number.class.cast(value).doubleValue());
+        } else if (type == boolean.class || type == Boolean.class) {
+            return generator.write(key, Boolean.class.cast(value).booleanValue());
+        } else if (type == BigDecimal.class) {
+            return generator.write(key, BigDecimal.class.cast(value));
+        } else if (type == BigInteger.class) {
+            return generator.write(key, BigInteger.class.cast(value));
+        }
+        return generator;
+    }
+
+    private <T> String convertFrom(final Class<T> aClass, final T value) {
+        final Converter<T> converter = (Converter<T>) findConverter(aClass);
+        return doConverFrom(value, converter);
+    }
+
+    private <T> String doConverFrom(final T value, final Converter<T> converter) {
+        if (converter == null) {
+            throw new MapperException("can't convert " + value + " to String");
+        }
+        return converter.toString(value);
+    }
+
+    private <T> Converter<T> findConverter(final Class<T> aClass) {
+        final Converter<T> converter = (Converter<T>) converters.get(aClass);
+        if (converter != null) {
+            return converter;
+        }
+        if (aClass.isEnum()) {
+            final Converter<T> enumConverter = new EnumConverter(aClass);
+            converters.putIfAbsent(aClass, enumConverter);
+            return enumConverter;
+        }
+        return null;
+    }
+
+    private Object convertTo(final Class<?> aClass, final String text) {
+        final Converter<?> converter = findConverter(aClass);
+        if (converter == null) {
+            throw new MapperException("can't convert String to " + aClass.getName());
+        }
+        return converter.fromString(text);
+    }
+
+    public <T> void writeArray(final Object object, final OutputStream stream) {
+        writeArray(asList((T[]) object), stream);
+    }
+
+    public <T> void writeArray(final T[] object, final OutputStream stream) {
+        writeArray(asList(object), stream);
+    }
+
+    public <T> void writeArray(final T[] object, final Writer stream) {
+        writeArray(asList(object), stream);
+    }
+
+    public <T> void writeArray(final Collection<T> object, final OutputStream stream) {
+        writeArray(object, new OutputStreamWriter(stream));
+    }
+
+    public <T> void writeArray(final Collection<T> object, final Writer stream) {
+        JsonGenerator generator = generatorFactory.createGenerator(stream);
+        try {
+            if (object == null) {
+                generator = generator.writeStartArray().writeEnd();
+            } else {
+                generator = generator.writeStartArray();
+                for (final T t : object) {
+                    generator = writeItem(generator, t);
+                }
+                generator = generator.writeEnd();
+            }
+        } finally {
+            doCloseOrFlush(generator);
+        }
+    }
+
+    private void doCloseOrFlush(JsonGenerator generator) {
+        if (close) {
+            generator.close();
+        } else {
+            generator.flush();
+        }
+    }
+
+    public <T> void writeIterable(final Iterable<T> object, final OutputStream stream) {
+        writeIterable(object, new OutputStreamWriter(stream));
+    }
+
+    public <T> void writeIterable(final Iterable<T> object, final Writer stream) {
+        JsonGenerator generator = generatorFactory.createGenerator(stream);
+        try {
+            if (object == null) {
+                generator = generator.writeStartArray().writeEnd();
+            } else {
+                generator.writeStartArray();
+                for (final T t : object) {
+                    generator = writeItem(generator, t);
+                }
+                generator.writeEnd();
+            }
+        } finally {
+            doCloseOrFlush(generator);
+        }
+    }
+
+    public void writeObject(final Object object, final Writer stream) {
+        final JsonGenerator generator = generatorFactory.createGenerator(stream);
+        doWriteHandlingNullObject(object, generator);
+    }
+
+    public void writeObject(final Object object, final OutputStream stream) {
+        final JsonGenerator generator = generatorFactory.createGenerator(stream);
+        doWriteHandlingNullObject(object, generator);
+    }
+
+    private void doWriteHandlingNullObject(final Object object, final JsonGenerator generator) {
+        if (object == null) {
+            generator.writeStartObject().writeEnd().close();
+            return;
+        }
+
+        JsonGenerator gen = null;
+        try {
+            gen = doWriteObject(generator, object);
+        } finally {
+            doCloseOrFlush(generator);
+        }
+    }
+
+    private JsonGenerator doWriteObject(final JsonGenerator generator, final Object object) {
+        try {
+            JsonGenerator gen = generator;
+            if (object == null) {
+                return generator;
+            }
+
+            if (Map.class.isInstance(object)) {
+                gen = gen.writeStartObject();
+                gen = writeMapBody((Map<?, ?>) object, gen);
+                gen = gen.writeEnd();
+                return gen;
+            }
+
+            gen = gen.writeStartObject();
+            gen = doWriteObjectBody(gen, object);
+            return gen.writeEnd();
+        } catch (final InvocationTargetException e) {
+            throw new MapperException(e);
+        } catch (final IllegalAccessException e) {
+            throw new MapperException(e);
+        }
+    }
+
+    private JsonGenerator doWriteObjectBody(final JsonGenerator gen, final Object object) throws IllegalAccessException, InvocationTargetException {
+        final Class<?> objectClass = object.getClass();
+        final Mappings.ClassMapping classMapping = mappings.findClassMapping(objectClass);
+        if (classMapping == null) {
+            throw new MapperException("No mapping for " + objectClass.getName());
+        }
+
+        JsonGenerator generator = gen;
+        for (final Map.Entry<String, Mappings.Getter> getterEntry : classMapping.getters.entrySet()) {
+            final Mappings.Getter getter = getterEntry.getValue();
+            final Object value = getter.setter.invoke(object);
+            if (value == null || (getter.version >= 0 && version >= getter.version)) {
+                continue;
+            }
+
+            generator = writeValue(generator, value.getClass(), getter.primitive, getterEntry.getKey(), getter.converter == null ? value : getter.converter.toString(value));
+        }
+        return generator;
+    }
+
+    private JsonGenerator writeMapBody(final Map<?, ?> object, final JsonGenerator gen) throws InvocationTargetException, IllegalAccessException {
+        JsonGenerator generator = gen;
+        for (final Map.Entry<?, ?> entry : ((Map<?, ?>) object).entrySet()) {
+            final Object value = entry.getValue();
+            if (value == null) {
+                continue;
+            }
+
+            final Object key = entry.getKey();
+            final Class<?> valueClass = value.getClass();
+            final boolean primitive = Mappings.isPrimitive(valueClass);
+            generator = writeValue(generator, valueClass, primitive, key == null ? "null" : key.toString(), value);
+        }
+        return generator;
+    }
+
+    private JsonGenerator writeValue(final JsonGenerator generator, final Class<?> type, final boolean primitive, final String key, final Object value) throws InvocationTargetException, IllegalAccessException {
+        if (type.isArray()) {
+            JsonGenerator gen = generator.writeStartArray(key);
+            final int length = Array.getLength(value);
+            for (int i = 0; i < length; i++) {
+                gen = writeItem(gen, Array.get(value, i));
+            }
+            return gen.writeEnd();
+        } else if (Collection.class.isInstance(value)) {
+            JsonGenerator gen = generator.writeStartArray(key);
+            for (final Object o : Collection.class.cast(value)) {
+                gen = writeItem(gen, o);
+            }
+            return gen.writeEnd();
+        } else if (Map.class.isInstance(value)) {
+            JsonGenerator gen = generator.writeStartObject(key);
+            gen = writeMapBody((Map<?, ?>) value, gen);
+            return gen.writeEnd();
+        } else if (primitive) {
+            return writePrimitives(generator, key, type, value);
+        } else {
+            final Converter<?> converter = findConverter(type);
+            if (converter != null) {
+                return writeValue(generator, type, true, key, doConverFrom(value, (Converter<Object>) converter));
+            }
+            return doWriteObjectBody(generator.writeStartObject(key), value).writeEnd();
+        }
+    }
+
+    private JsonGenerator writeItem(final JsonGenerator generator, final Object o) {
+        final JsonGenerator newGen = writePrimitives(generator, o);
+        if (newGen == null) {
+            return doWriteObject(generator, o);
+        }
+        return newGen;
+    }
+
+    public <T> T readObject(final Reader stream, final Type clazz) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return mapObject(clazz, reader);
+    }
+
+    public <T> T readObject(final InputStream stream, final Type clazz) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return mapObject(clazz, reader);
+    }
+
+    private <T> T mapObject(final Type clazz, final JsonReader reader) {
+        try {
+            return (T) buildObject(clazz, reader.readObject());
+        } catch (final InstantiationException e) {
+            throw new MapperException(e);
+        } catch (final IllegalAccessException e) {
+            throw new MapperException(e);
+        } finally {
+            if (close) {
+                reader.close();
+            }
+        }
+    }
+
+    public <C extends Collection<T>, T> C readCollection(final InputStream stream, final ParameterizedType genericType, final Class<T> raw) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(genericType, raw);
+        if (mapping == null) {
+            throw new UnsupportedOperationException("type " + genericType + " not supported");
+        }
+        try {
+            return (C) mapCollection(mapping, reader.readArray());
+        } catch (final InstantiationException e) {
+            throw new MapperException(e);
+        } catch (final IllegalAccessException e) {
+            throw new MapperException(e);
+        } finally {
+            if (close) {
+                reader.close();
+            }
+        }
+    }
+
+    public <C extends Collection<T>, T> C readCollection(final Reader stream, final ParameterizedType genericType, final Class<T> raw) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(genericType, raw);
+        if (mapping == null) {
+            throw new UnsupportedOperationException("type " + genericType + " not supported");
+        }
+        try {
+            return (C) mapCollection(mapping, reader.readArray());
+        } catch (final InstantiationException e) {
+            throw new MapperException(e);
+        } catch (final IllegalAccessException e) {
+            throw new MapperException(e);
+        } finally {
+            if (close) {
+                reader.close();
+            }
+        }
+    }
+
+    public <T> T[] readArray(final Reader stream, final Class<T> clazz) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return mapArray(clazz, reader);
+    }
+
+    public <T> T[] readArray(final InputStream stream, final Class<T> clazz) {
+        final JsonReader reader = readerFactory.createReader(stream);
+        return mapArray(clazz, reader);
+    }
+
+    private <T> T[] mapArray(final Class<T> clazz, final JsonReader reader) {
+        try {
+            return (T[]) buildArrayWithComponentType(reader.readArray(), clazz);
+        } catch (final InstantiationException e) {
+            throw new MapperException(e);
+        } catch (final IllegalAccessException e) {
+            throw new MapperException(e);
+        } finally {
+            if (close) {
+                reader.close();
+            }
+        }
+    }
+
+    private Object buildObject(final Type type, final JsonObject object) throws InstantiationException, IllegalAccessException {
+        final Mappings.ClassMapping classMapping = mappings.findClassMapping(type);
+
+        if (classMapping == null) {
+            if (ParameterizedType.class.isInstance(type)) {
+                final ParameterizedType aType = ParameterizedType.class.cast(type);
+                final Type[] fieldArgTypes = aType.getActualTypeArguments();
+                if (fieldArgTypes.length >= 2) {
+                    final Class<?> raw = Class.class.cast(aType.getRawType());
+
+                    final Map map;
+                    if (ConcurrentMap.class.isAssignableFrom(raw)) {
+                        map = new ConcurrentHashMap(object.size());
+                    } else if (Map.class.isAssignableFrom(raw)) {
+                        map = new HashMap(object.size());
+                    } else {
+                        map = null;
+                    }
+
+                    if (map != null) {
+                        final Class<?> keyType = Class.class.cast(fieldArgTypes[0]);
+                        for (final Map.Entry<String, JsonValue> value : object.entrySet()) {
+                            map.put(convertTo(keyType, value.getKey()), toObject(value.getValue(), fieldArgTypes[1]));
+                        }
+                        return map;
+                    }
+                } else {
+                    throw new MapperException("Can't map " + type + ", not a map and no Mapping found");
+                }
+            } else {
+                throw new MapperException("Can't map " + type);
+            }
+        }
+
+        final Object t = classMapping.clazz.newInstance();
+        for (final Map.Entry<String, Mappings.Setter> setter : classMapping.setters.entrySet()) {
+            final JsonValue jsonValue = object.get(setter.getKey());
+            final Mappings.Setter value = setter.getValue();
+            final Method setterMethod = value.setter;
+            final Object convertedValue = value.converter == null? toObject(jsonValue, value.paramType) : value.converter.fromString(jsonValue.toString());
+            if (convertedValue != null) {
+                try {
+                    setterMethod.invoke(t, convertedValue);
+                } catch (final InvocationTargetException e) {
+                    throw new MapperException(e.getCause());
+                }
+            }
+        }
+
+        return t;
+    }
+
+    private Object toObject(final JsonValue jsonValue, final Type type) throws InstantiationException, IllegalAccessException {
+        Object convertedValue = null;
+        if (JsonObject.class.isInstance(jsonValue)) {
+            convertedValue = buildObject(type, JsonObject.class.cast(jsonValue));
+        } else if (JsonArray.class.isInstance(jsonValue)) {
+            convertedValue = buildArray(type, JsonArray.class.cast(jsonValue));
+        } else if (jsonValue != null && JsonValue.NULL != jsonValue) {
+            if (JsonNumber.class.isInstance(jsonValue)) {
+                final JsonNumber number = JsonNumber.class.cast(jsonValue);
+                if (type == Integer.class || type == int.class) {
+                    return number.intValue();
+                }
+                if (type == Long.class || type == long.class) {
+                    return number.longValue();
+                }
+                if (type == Double.class || type == double.class) {
+                    return number.doubleValue();
+                }
+                if (type == BigInteger.class) {
+                    return number.bigIntegerValue();
+                }
+                if (type == BigDecimal.class) {
+                    return number.bigDecimalValue();
+                }
+            }
+
+            final String text = jsonValue.toString();
+            if (text != null) {
+                convertedValue = convertTo(Class.class.cast(type), text);
+            }
+        }
+        return convertedValue;
+    }
+
+    private Object buildArray(final Type type, final JsonArray jsonArray) throws IllegalAccessException, InstantiationException {
+        if (Class.class.isInstance(type)) {
+            final Class clazz = Class.class.cast(type);
+            if (clazz.isArray()) {
+                final Class<?> componentType = clazz.getComponentType();
+                return buildArrayWithComponentType(jsonArray, componentType);
+            }
+        }
+
+        if (ParameterizedType.class.isInstance(type)) {
+            final Mappings.CollectionMapping mapping = mappings.findCollectionMapping(ParameterizedType.class.cast(type), (Class<Object>) ParameterizedType.class.cast(type).getRawType());
+            if (mapping != null) {
+                return mapCollection(mapping, jsonArray);
+            }
+        }
+
+        throw new UnsupportedOperationException("type " + type + " not supported");
+    }
+
+    private <T> Collection<T> mapCollection(final Mappings.CollectionMapping mapping, final JsonArray jsonArray) throws InstantiationException, IllegalAccessException {
+        final Collection collection;
+        if (List.class == mapping.raw || Collection.class == mapping.raw) {
+            collection = new ArrayList<T>(jsonArray.size());
+        } else if (Set.class == mapping.raw) {
+            collection = new HashSet<T>(jsonArray.size());
+        } else {
+            throw new IllegalStateException("not supported collection type: " + mapping.raw.getName());
+        }
+
+        for (final JsonValue value : jsonArray) {
+            final Object element = toObject(value, mapping.arg);
+            collection.add(element);
+        }
+        return collection;
+    }
+
+    private Object buildArrayWithComponentType(final JsonArray jsonArray, final Class<?> componentType) throws InstantiationException, IllegalAccessException {
+        final Object array = Array.newInstance(componentType, jsonArray.size());
+        int i = 0;
+        for (final JsonValue value : jsonArray) {
+            Array.set(array, i++, toObject(value, componentType));
+        }
+        return array;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperBuilder.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperBuilder.java
new file mode 100644
index 0000000..a7f2150
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperBuilder.java
@@ -0,0 +1,116 @@
+/*
+ * 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.mapper;
+
+import org.apache.fleece.mapper.converter.BigDecimalConverter;
+import org.apache.fleece.mapper.converter.BigIntegerConverter;
+import org.apache.fleece.mapper.converter.BooleanConverter;
+import org.apache.fleece.mapper.converter.ByteConverter;
+import org.apache.fleece.mapper.converter.CachedDelegateConverter;
+import org.apache.fleece.mapper.converter.ClassConverter;
+import org.apache.fleece.mapper.converter.DateConverter;
+import org.apache.fleece.mapper.converter.DoubleConverter;
+import org.apache.fleece.mapper.converter.FloatConverter;
+import org.apache.fleece.mapper.converter.IntegerConverter;
+import org.apache.fleece.mapper.converter.LongConverter;
+import org.apache.fleece.mapper.converter.ShortConverter;
+import org.apache.fleece.mapper.converter.StringConverter;
+
+import javax.json.JsonReaderFactory;
+import javax.json.spi.JsonProvider;
+import javax.json.stream.JsonGeneratorFactory;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class MapperBuilder {
+    private static final Map<Class<?>, Converter<?>> DEFAULT_CONVERTERS = new HashMap<Class<?>, Converter<?>>();
+
+    static {
+        //DEFAULT_CONVERTERS.put(Date.class, new DateConverter("yyyy-MM-dd'T'HH:mm:ssZ")); // ISO8601 long RFC822 zone
+        DEFAULT_CONVERTERS.put(Date.class, new DateConverter("yyyyMMddHHmmssZ")); // ISO8601 short
+        DEFAULT_CONVERTERS.put(Class.class, new ClassConverter());
+        DEFAULT_CONVERTERS.put(String.class, new StringConverter());
+        DEFAULT_CONVERTERS.put(BigDecimal.class, new BigDecimalConverter());
+        DEFAULT_CONVERTERS.put(BigInteger.class, new BigIntegerConverter());
+        DEFAULT_CONVERTERS.put(Byte.class, new CachedDelegateConverter<Byte>(new ByteConverter()));
+        DEFAULT_CONVERTERS.put(Double.class, new DoubleConverter());
+        DEFAULT_CONVERTERS.put(Float.class, new FloatConverter());
+        DEFAULT_CONVERTERS.put(Integer.class, new IntegerConverter());
+        DEFAULT_CONVERTERS.put(Long.class, new LongConverter());
+        DEFAULT_CONVERTERS.put(Short.class, new ShortConverter());
+        DEFAULT_CONVERTERS.put(Boolean.class, new CachedDelegateConverter<Boolean>(new BooleanConverter()));
+        DEFAULT_CONVERTERS.put(byte.class, DEFAULT_CONVERTERS.get(Byte.class));
+        DEFAULT_CONVERTERS.put(double.class, DEFAULT_CONVERTERS.get(Double.class));
+        DEFAULT_CONVERTERS.put(float.class, DEFAULT_CONVERTERS.get(Float.class));
+        DEFAULT_CONVERTERS.put(int.class, DEFAULT_CONVERTERS.get(Integer.class));
+        DEFAULT_CONVERTERS.put(long.class, DEFAULT_CONVERTERS.get(Long.class));
+        DEFAULT_CONVERTERS.put(short.class, DEFAULT_CONVERTERS.get(Short.class));
+        DEFAULT_CONVERTERS.put(boolean.class, DEFAULT_CONVERTERS.get(Boolean.class));
+    }
+
+    private JsonReaderFactory readerFactory;
+    private JsonGeneratorFactory generatorFactory;
+    private boolean doCloseOnStreams = false;
+    private int version = -1;
+    private final Map<Class<?>, Converter<?>> converters = new HashMap<Class<?>, Converter<?>>(DEFAULT_CONVERTERS);
+
+    public Mapper build() {
+        if (readerFactory == null || generatorFactory == null) {
+            final JsonProvider provider = JsonProvider.provider();
+            final Map<String, Object> config = Collections.<String, Object>emptyMap();
+            if (readerFactory == null) {
+                readerFactory = provider.createReaderFactory(config);
+            }
+            if (generatorFactory == null) {
+                generatorFactory = provider.createGeneratorFactory(config);
+            }
+        }
+
+        return new Mapper(readerFactory, generatorFactory, doCloseOnStreams, converters, version);
+    }
+
+    public MapperBuilder setReaderFactory(final JsonReaderFactory readerFactory) {
+        this.readerFactory = readerFactory;
+        return this;
+    }
+
+    public MapperBuilder setGeneratorFactory(final JsonGeneratorFactory generatorFactory) {
+        this.generatorFactory = generatorFactory;
+        return this;
+    }
+
+    public MapperBuilder setDoCloseOnStreams(final boolean doCloseOnStreams) {
+        this.doCloseOnStreams = doCloseOnStreams;
+        return this;
+    }
+
+    public MapperBuilder addPropertyEditor(final Class<?> clazz, final Converter<?> converter) {
+        this.converters.put(clazz, converter);
+        return this;
+    }
+
+    public MapperBuilder setVersion(final int version) {
+        this.version = version;
+        return this;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperException.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperException.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperException.java
new file mode 100644
index 0000000..e882c2a
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/MapperException.java
@@ -0,0 +1,31 @@
+/*
+ * 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.mapper;
+
+import javax.json.JsonException;
+
+public class MapperException extends JsonException {
+    public MapperException(final Throwable e) {
+        super(e.getMessage(), e);
+    }
+
+    public MapperException(final String s) {
+        super(s);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigDecimalConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigDecimalConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigDecimalConverter.java
new file mode 100644
index 0000000..f5828b1
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigDecimalConverter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+import java.math.BigDecimal;
+
+public class BigDecimalConverter implements Converter<BigDecimal> {
+    @Override
+    public String toString(final BigDecimal instance) {
+        return instance.toString();
+    }
+
+    @Override
+    public BigDecimal fromString(final String text) {
+        return new BigDecimal(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigIntegerConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigIntegerConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigIntegerConverter.java
new file mode 100644
index 0000000..eb3f0d7
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BigIntegerConverter.java
@@ -0,0 +1,35 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+import java.math.BigInteger;
+
+public class BigIntegerConverter implements Converter<BigInteger> {
+    @Override
+    public String toString(final BigInteger instance) {
+        return instance.toString();
+    }
+
+    @Override
+    public BigInteger fromString(final String text) {
+        return new BigInteger(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BooleanConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BooleanConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BooleanConverter.java
new file mode 100644
index 0000000..ee51806
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/BooleanConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class BooleanConverter implements Converter<Boolean> {
+    @Override
+    public String toString(final Boolean instance) {
+        return Boolean.toString(instance);
+    }
+
+    @Override
+    public Boolean fromString(final String text) {
+        return Boolean.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ByteConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ByteConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ByteConverter.java
new file mode 100644
index 0000000..32edd86
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ByteConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class ByteConverter implements Converter<Byte> {
+    @Override
+    public String toString(final Byte instance) {
+        return Byte.toString(instance);
+    }
+
+    @Override
+    public Byte fromString(final String text) {
+        return Byte.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CachedDelegateConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CachedDelegateConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CachedDelegateConverter.java
new file mode 100644
index 0000000..9d36701
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CachedDelegateConverter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class CachedDelegateConverter<T> implements Converter<T> {
+    private final ConcurrentMap<T, String> strings = new ConcurrentHashMap<T, String>();
+    private final ConcurrentMap<String, T> values = new ConcurrentHashMap<String, T>();
+    private final Converter<T> delegate;
+
+    public CachedDelegateConverter(final Converter<T> delegate) {
+        this.delegate = delegate;
+    }
+
+    @Override
+    public String toString(final T instance) {
+        String v = strings.get(instance);
+        if (v == null) {
+            v = delegate.toString(instance);
+            strings.putIfAbsent(instance, v);
+        }
+        return v;
+    }
+
+    @Override
+    public T fromString(final String text) {
+        T v = values.get(text);
+        if (v == null) {
+            v = delegate.fromString(text);
+            values.putIfAbsent(text, v);
+        }
+        return v;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CharacterConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CharacterConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CharacterConverter.java
new file mode 100644
index 0000000..6117b07
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/CharacterConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class CharacterConverter implements Converter<Character> {
+    @Override
+    public String toString(final Character instance) {
+        return Character.toString(instance);
+    }
+
+    @Override
+    public Character fromString(final String text) {
+        return text.length() > 0 ? text.charAt(0) : null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ClassConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ClassConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ClassConverter.java
new file mode 100644
index 0000000..0214c51
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ClassConverter.java
@@ -0,0 +1,37 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class ClassConverter implements Converter<Class<?>> {
+    @Override
+    public String toString(final Class<?> instance) {
+        return instance.getName();
+    }
+
+    @Override
+    public Class<?> fromString(final String text) {
+        try {
+            return Class.forName(text, true, Thread.currentThread().getContextClassLoader());
+        } catch (final ClassNotFoundException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DateConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DateConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DateConverter.java
new file mode 100644
index 0000000..fa8831b
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DateConverter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class DateConverter implements Converter<Date> {
+    // TODO: see if we can clean it
+    private final ThreadLocal<DateFormat> format;
+
+    public DateConverter(final String pattern) {
+        format = new ThreadLocal<DateFormat>() {
+            @Override
+            protected DateFormat initialValue() {
+                return new SimpleDateFormat(pattern);
+            }
+        };
+    }
+
+    @Override
+    public String toString(final Date instance) {
+        return format.get().format(instance);
+    }
+
+    @Override
+    public Date fromString(final String text) {
+        try {
+            return format.get().parse(text);
+        } catch (final ParseException e) {
+            throw new IllegalArgumentException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DoubleConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DoubleConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DoubleConverter.java
new file mode 100644
index 0000000..6faf015
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/DoubleConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class DoubleConverter implements Converter<Double> {
+    @Override
+    public String toString(final Double instance) {
+        return Double.toString(instance);
+    }
+
+    @Override
+    public Double fromString(final String text) {
+        return Double.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/EnumConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/EnumConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/EnumConverter.java
new file mode 100644
index 0000000..56aadcb
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/EnumConverter.java
@@ -0,0 +1,46 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class EnumConverter<T extends Enum<T>> implements Converter<T> {
+    private final Map<String, T> values;
+
+    public EnumConverter(final Class<T> aClass) {
+        final T[] enumConstants = aClass.getEnumConstants();
+        values = new HashMap<String, T>(enumConstants.length);
+        for (final T t : enumConstants) {
+            values.put(t.name(), t);
+        }
+    }
+
+    @Override // no need of cache here, it is already fast
+    public String toString(final T instance) {
+        return instance.name();
+    }
+
+    @Override
+    public T fromString(final String text) {
+        return values.get(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/FloatConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/FloatConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/FloatConverter.java
new file mode 100644
index 0000000..7e6fb1e
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/FloatConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class FloatConverter implements Converter<Float> {
+    @Override
+    public String toString(final Float instance) {
+        return Float.toString(instance);
+    }
+
+    @Override
+    public Float fromString(final String text) {
+        return Float.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/IntegerConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/IntegerConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/IntegerConverter.java
new file mode 100644
index 0000000..8677b3e
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/IntegerConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class IntegerConverter implements Converter<Integer> {
+    @Override
+    public String toString(final Integer instance) {
+        return Integer.toString(instance);
+    }
+
+    @Override
+    public Integer fromString(final String text) {
+        return Integer.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/LongConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/LongConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/LongConverter.java
new file mode 100644
index 0000000..62b17ec
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/LongConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class LongConverter implements Converter<Long> {
+    @Override
+    public String toString(final Long instance) {
+        return Long.toString(instance);
+    }
+
+    @Override
+    public Long fromString(final String text) {
+        return Long.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ShortConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ShortConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ShortConverter.java
new file mode 100644
index 0000000..e9c48ec
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/ShortConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class ShortConverter implements Converter<Short> {
+    @Override
+    public String toString(final Short instance) {
+        return Short.toString(instance);
+    }
+
+    @Override
+    public Short fromString(final String text) {
+        return Short.valueOf(text);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-fleece/blob/422e96f3/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/StringConverter.java
----------------------------------------------------------------------
diff --git a/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/StringConverter.java b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/StringConverter.java
new file mode 100644
index 0000000..713702f
--- /dev/null
+++ b/fleece-mapper/src/main/java/org/apache/fleece/mapper/converter/StringConverter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.mapper.converter;
+
+import org.apache.fleece.mapper.Converter;
+
+public class StringConverter implements Converter<String> {
+    @Override
+    public String toString(final String instance) {
+        return instance;
+    }
+
+    @Override
+    public String fromString(final String text) {
+        return text;
+    }
+}