You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by sa...@apache.org on 2014/09/11 20:29:18 UTC

[02/22] renamed fleece to johnzon

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JsrProvider.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JsrProvider.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/JsrProvider.java
new file mode 100644
index 0000000..70a0791
--- /dev/null
+++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/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.johnzon.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-johnzon/blob/6e86a53e/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WadlDocumentMessageBodyWriter.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WadlDocumentMessageBodyWriter.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WadlDocumentMessageBodyWriter.java
new file mode 100644
index 0000000..5adab66
--- /dev/null
+++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/WadlDocumentMessageBodyWriter.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.johnzon.jaxrs;
+
+import org.apache.johnzon.jaxrs.xml.WadlDocumentToJson;
+import org.w3c.dom.Document;
+
+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.xml.stream.XMLStreamException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import static org.apache.johnzon.jaxrs.Jsons.isJson;
+
+public class WadlDocumentMessageBodyWriter implements MessageBodyWriter<Document> {
+    private final WadlDocumentToJson converter = new WadlDocumentToJson();
+
+    @Override
+    public boolean isWriteable(final Class<?> aClass, final Type type,
+                               final Annotation[] annotations, final MediaType mediaType) {
+        return isJson(mediaType) && Document.class.isAssignableFrom(aClass);
+    }
+
+    @Override
+    public long getSize(final Document document, final Class<?> aClass,
+                        final Type type, final Annotation[] annotations,
+                        final MediaType mediaType) {
+        return -1;
+    }
+
+    @Override
+    public void writeTo(final Document document, final Class<?> aClass,
+                        final Type type, final Annotation[] annotations,
+                        final MediaType mediaType, final MultivaluedMap<String, Object> stringObjectMultivaluedMap,
+                        final OutputStream outputStream) throws IOException, WebApplicationException {
+        try {
+            outputStream.write(converter.convert(document).getBytes());
+        } catch (final XMLStreamException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJson.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJson.java b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJson.java
new file mode 100644
index 0000000..0768e09
--- /dev/null
+++ b/johnzon-jaxrs/src/main/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJson.java
@@ -0,0 +1,98 @@
+/*
+ * 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.johnzon.jaxrs.xml;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonBuilderFactory;
+import javax.json.JsonObjectBuilder;
+import javax.xml.stream.XMLStreamException;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+public class WadlDocumentToJson {
+    private final JsonBuilderFactory builderFactory = Json.createBuilderFactory(Collections.<String, Object>emptyMap());
+
+    public String convert(final Document doc) throws XMLStreamException {
+        final JsonObjectBuilder builder = builderFactory.createObjectBuilder();
+        if (doc.getChildNodes().getLength() != 1) {
+            return "{}";
+        }
+        final Node item = doc.getChildNodes().item(0);
+        return builder.add(item.getNodeName(), createNode(item)).build().toString();
+    }
+
+    private void addChildrens(/*final String nodeName, */final JsonObjectBuilder builder, final NodeList children) {
+        final Map<String, Collection<Node>> nodesByName = new LinkedHashMap<String, Collection<Node>>();
+        for (int i = 0; i < children.getLength(); i++) {
+            final Node node = children.item(i);
+            if ("#text".equals(node.getNodeName())) {
+                continue;
+            }
+
+            final String name = node.getNodeName();
+            Collection<Node> nodes = nodesByName.get(name);
+            if (nodes == null) {
+                nodes = new LinkedList<Node>();
+                nodesByName.put(name, nodes);
+            }
+            nodes.add(node);
+        }
+
+        for (final Map.Entry<String, Collection<Node>> entry : nodesByName.entrySet()) {
+            final JsonArrayBuilder arrayBuilder = builderFactory.createArrayBuilder();
+            for (final Node n : entry.getValue()) {
+                final JsonObjectBuilder jsonObjectBuilder = createNode(n);
+                if (jsonObjectBuilder != null) {
+                    arrayBuilder.add(jsonObjectBuilder);
+                }
+            }
+            builder.add(entry.getKey(), arrayBuilder);
+        }
+    }
+
+    private JsonObjectBuilder createNode(final Node node) {
+        JsonObjectBuilder childBuilder = null;
+
+        if (node.hasAttributes()) {
+            childBuilder = builderFactory.createObjectBuilder();
+            final NamedNodeMap attributes = node.getAttributes();
+            for (int j = 0; j < attributes.getLength(); j++) {
+                final Node namedItem = attributes.item(j);
+                childBuilder.add(namedItem.getNodeName(), namedItem.getNodeValue());
+            }
+        }
+
+        if (node.hasChildNodes()) {
+            if (childBuilder == null) {
+                childBuilder = builderFactory.createObjectBuilder();
+            }
+            addChildrens(/*node.getNodeName(),*/ childBuilder, node.getChildNodes());
+        }
+        return childBuilder;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.java
new file mode 100644
index 0000000..3cccf83
--- /dev/null
+++ b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JohnzonProviderTest.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.johnzon.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 JohnzonProviderTest {
+    private final static String ENDPOINT_ADDRESS = "local://johnzon";
+    private static Server server;
+
+    @BeforeClass
+    public static void bindEndpoint() throws Exception {
+        final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(JohnzonResource.class);
+        sf.setProviders(asList(new JohnzonProvider<Object>()));
+        sf.setResourceProvider(JohnzonResource.class, new SingletonResourceProvider(new JohnzonResource(), 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("johnzon").type(MediaType.APPLICATION_JSON_TYPE).post(new Johnzon("client")).readEntity(String.class);
+        assertTrue(Boolean.parseBoolean(result));
+    }
+
+    @Test
+    public void object() {
+        final Johnzon johnzon = client().path("johnzon").get(Johnzon.class);
+        assertEquals("johnzon", johnzon.getName());
+    }
+
+    @Test
+    public void array() {
+        final Johnzon[] johnzon = client().path("johnzon/all1").get(Johnzon[].class);
+        assertEquals(2, johnzon.length);
+        for (int i = 0; i < johnzon.length; i++) {
+            assertEquals("johnzon" + (i + 1), johnzon[i].getName());
+        }
+    }
+
+    @Test
+    public void list() {
+        final ParameterizedType list = new ParameterizedType() {
+            @Override
+            public Type[] getActualTypeArguments() {
+                return new Type[]{Johnzon.class};
+            }
+
+            @Override
+            public Type getRawType() {
+                return List.class;
+            }
+
+            @Override
+            public Type getOwnerType() {
+                return null;
+            }
+        };
+        final List<Johnzon> johnzons = client().path("johnzon/all2").get(new GenericType<List<Johnzon>>(list));
+        assertEquals(2, johnzons.size());
+        int i = 1;
+        for (final Johnzon f : johnzons) {
+            assertEquals("johnzon" + i, f.getName());
+            i++;
+        }
+    }
+
+    private static WebClient client() {
+        final WebClient client = WebClient.create(ENDPOINT_ADDRESS, asList(new JohnzonProvider<Object>())).accept(MediaType.APPLICATION_JSON_TYPE);
+        WebClient.getConfig(client).getRequestContext().put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);
+        return client;
+    }
+
+    public static class Johnzon {
+        private String name;
+
+        public Johnzon(final String name) {
+            this.name = name;
+        }
+
+        public Johnzon() {
+            // no-op
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(final String name) {
+            this.name = name;
+        }
+    }
+
+    @Path("johnzon")
+    public static class JohnzonResource {
+        @GET
+        public Johnzon johnzon() {
+            return new Johnzon("johnzon");
+        }
+
+        @GET
+        @Path("all1")
+        public Johnzon[] johnzons1() {
+            return new Johnzon[] { new Johnzon("johnzon1"), new Johnzon("johnzon2") };
+        }
+
+        @GET
+        @Path("all2")
+        public List<Johnzon> johnzons2() {
+            return asList(johnzons1());
+        }
+
+        @POST
+        public String asParam(final Johnzon f) {
+            return Boolean.toString("client".equals(f.getName()));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JsrProviderTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JsrProviderTest.java b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/JsrProviderTest.java
new file mode 100644
index 0000000..9954cbb
--- /dev/null
+++ b/johnzon-jaxrs/src/test/java/org/apache/johnzon/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.johnzon.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://johnzon";
+    private static Server server;
+
+    @BeforeClass
+    public static void bindEndpoint() throws Exception {
+        final JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+        sf.setResourceClasses(JohnzonResource.class);
+        sf.setProviders(asList(new JsrProvider()));
+        sf.setResourceProvider(JohnzonResource.class, new SingletonResourceProvider(new JohnzonResource(), 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("johnzon/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("johnzon/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("johnzon")
+    public static class JohnzonResource {
+        @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-johnzon/blob/6e86a53e/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJsonTest.java
----------------------------------------------------------------------
diff --git a/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJsonTest.java b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJsonTest.java
new file mode 100644
index 0000000..ba19b0d
--- /dev/null
+++ b/johnzon-jaxrs/src/test/java/org/apache/johnzon/jaxrs/xml/WadlDocumentToJsonTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.johnzon.jaxrs.xml;
+
+import org.junit.Test;
+import org.w3c.dom.Document;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.ByteArrayInputStream;
+
+import static org.junit.Assert.assertEquals;
+
+public class WadlDocumentToJsonTest {
+    @Test
+    public void xmlToJson() throws Exception {
+        final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+            .parse(new ByteArrayInputStream(("" +
+                    "<application xmlns=\"http://wadl.dev.java.net/2009/02\">\n" +
+                    "    <resources base=\"http://example.com/api\">\n" +
+                    "        <resource path=\"books\">\n" +
+                    "            <method name=\"GET\"/>\n" +
+                    "            <resource path=\"{bookId}\">\n" +
+                    "                <param required=\"true\" style=\"template\" name=\"bookId\"/>\n" +
+                    "                <method name=\"GET\"/>\n" +
+                    "                <method name=\"DELETE\"/>\n" +
+                    "                <resource path=\"reviews\">\n" +
+                    "                    <method name=\"GET\">\n" +
+                    "                        <request>\n" +
+                    "                            <param name=\"page\" required=\"false\" default=\"1\" style=\"query\"/>\n" +
+                    "                            <param name=\"size\" required=\"false\" default=\"20\" style=\"query\"/>\n" +
+                    "                        </request>\n" +
+                    "                    </method>\n" +
+                    "                </resource>\n" +
+                    "            </resource>\n" +
+                    "        </resource>\n" +
+                    "        <resource path=\"readers\">\n" +
+                    "            <method name=\"GET\"/>\n" +
+                    "        </resource>\n" +
+                    "    </resources>\n" +
+                    "</application>").getBytes()));
+
+        final String json = new WadlDocumentToJson().convert(doc);
+        assertEquals("{\"application\":{\"xmlns\":\"http://wadl.dev.java.net/2009/02\",\"resources\":[{\"base\":\"http://example.com/api\",\"resource\":[{\"path\":\"books\",\"method\":[{\"name\":\"GET\"}],\"resource\":[{\"path\":\"{bookId}\",\"param\":[{\"name\":\"bookId\",\"required\":\"true\",\"style\":\"template\"}],\"method\":[{\"name\":\"GET\"},{\"name\":\"DELETE\"}],\"resource\":[{\"path\":\"reviews\",\"method\":[{\"name\":\"GET\",\"request\":[{\"param\":[{\"default\":\"1\",\"name\":\"page\",\"required\":\"false\",\"style\":\"query\"},{\"default\":\"20\",\"name\":\"size\",\"required\":\"false\",\"style\":\"query\"}]}]}]}]}]},{\"path\":\"readers\",\"method\":[{\"name\":\"GET\"}]}]}]}}", json);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-mapper/pom.xml
----------------------------------------------------------------------
diff --git a/johnzon-mapper/pom.xml b/johnzon-mapper/pom.xml
new file mode 100644
index 0000000..31d5007
--- /dev/null
+++ b/johnzon-mapper/pom.xml
@@ -0,0 +1,44 @@
+<?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>johnzon</artifactId>
+    <groupId>org.apache.johnzon</groupId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>johnzon-mapper</artifactId>
+  <name>Johnzon :: Mapper</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.johnzon</groupId>
+      <artifactId>johnzon-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+  </dependencies>
+
+  <properties>
+    <staging.directory>${project.parent.reporting.outputDirectory}</staging.directory>
+  </properties>
+</project>

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Converter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Converter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Converter.java
new file mode 100644
index 0000000..3c36273
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper;
+
+public interface Converter<T> {
+    String toString(T instance);
+    T fromString(String text);
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.java
new file mode 100644
index 0000000..1c1a01d
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonConverter.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.johnzon.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 JohnzonConverter {
+    Class<? extends Converter<?>> value();
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnore.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnore.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnore.java
new file mode 100644
index 0000000..6b75dc5
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/JohnzonIgnore.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.johnzon.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 JohnzonIgnore {
+    /**
+     * Example: @JohnzonIgnore(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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
new file mode 100644
index 0000000..1367a65
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mapper.java
@@ -0,0 +1,670 @@
+/*
+ * 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.johnzon.mapper;
+
+import org.apache.johnzon.mapper.converter.EnumConverter;
+import org.apache.johnzon.mapper.reflection.Mappings;
+
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonNumber;
+import javax.json.JsonObject;
+import javax.json.JsonReader;
+import javax.json.JsonReaderFactory;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+import javax.json.JsonValue.ValueType;
+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.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static java.util.Arrays.asList;
+
+public class Mapper {
+    protected static final JsonObject EMPTY_OBJECT = Json.createObjectBuilder().build();
+    private static final Converter<Object> FALLBACK_CONVERTER = new FallbackConverter();
+
+    protected final Mappings mappings;
+    protected final JsonReaderFactory readerFactory;
+    protected final JsonGeneratorFactory generatorFactory;
+    protected final boolean close;
+    protected final ConcurrentMap<Type, 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, final Comparator<String> attributeOrder) {
+        this.readerFactory = readerFactory;
+        this.generatorFactory = generatorFactory;
+        this.close = doClose;
+        this.converters = new ConcurrentHashMap<Type, Converter<?>>(converters);
+        this.version = version;
+        this.mappings = new Mappings(attributeOrder);
+    }
+
+    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));
+        } else if (type == short.class || type == Short.class) {
+            return generator.write(Short.class.cast(value).shortValue());
+        } else if (type == char.class || type == Character.class) {
+            return generator.write(Character.class.cast(value).toString());
+        } else if (type == byte.class || type == Byte.class) {
+            return generator.write(Byte.class.cast(value).byteValue());
+        }        
+        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
+                    || type == byte.class || type == Byte.class
+                    || type == short.class || type == Short.class) {
+            return generator.write(key, Number.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));
+        } else if (type == char.class || type == Character.class) {
+            return generator.write(key, Character.class.cast(value).toString());
+        } 
+        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 static <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 Type aClass) {
+        final Converter<T> converter = (Converter<T>) converters.get(aClass);
+        if (converter != null) {
+            return converter;
+        }
+        if (Class.class.isInstance(aClass)) {
+            final Class<?> clazz = Class.class.cast(aClass);
+            if (clazz.isEnum()) {
+                final Converter<T> enumConverter = new EnumConverter(clazz);
+                converters.putIfAbsent(clazz, enumConverter);
+                return enumConverter;
+            }
+        }
+        return null;
+    }
+
+    private Object convertTo(final Type aClass, final String text) {
+        final Converter<?> converter = findConverter(aClass);
+        if (converter == null) {
+            converters.putIfAbsent(aClass, FALLBACK_CONVERTER);
+            return FALLBACK_CONVERTER;
+        }
+        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.findOrCreateClassMapping(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, getter.array,
+                                    getter.collection, getter.map,
+                                    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);
+            final boolean clazz = mappings.getClassMapping(valueClass) != null;
+            final boolean array = clazz || primitive ? false : valueClass.isArray();
+            final boolean collection = clazz || primitive || array ? false : Collection.class.isAssignableFrom(valueClass);
+            final boolean map = clazz || primitive || array || collection ? false : Map.class.isAssignableFrom(valueClass);
+            generator = writeValue(generator, valueClass,
+                                    primitive, array, collection, map,
+                                    key == null ? "null" : key.toString(), value);
+        }
+        return generator;
+    }
+
+    private JsonGenerator writeValue(final JsonGenerator generator, final Class<?> type,
+                                     final boolean primitive, final boolean array,
+                                     final boolean collection, final boolean map,
+                                     final String key, final Object value) throws InvocationTargetException, IllegalAccessException {
+        if (array) {
+            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) {
+            JsonGenerator gen = generator.writeStartArray(key);
+            for (final Object o : Collection.class.cast(value)) {
+                gen = writeItem(gen, o);
+            }
+            return gen.writeEnd();
+        } else if (map) {
+            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, String.class, true, false, false, false, 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.findOrCreateClassMapping(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 (SortedMap.class.isAssignableFrom(raw)) {
+                        map = new TreeMap();
+                    } else 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) {
+                        
+                        Type keyType;
+                        if (ParameterizedType.class.isInstance(fieldArgTypes[0])) {
+                            keyType = fieldArgTypes[0];
+                        } else {
+                            keyType = 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) : jsonValue.getValueType() == ValueType.STRING ?
+                                                            value.converter.fromString(JsonString.class.cast(jsonValue).getString()):
+                                                                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 {
+      
+        if(jsonValue == null || jsonValue == JsonValue.NULL) {           
+            return null;
+        }
+        
+        if (type == Boolean.class || type == boolean.class) {
+            
+            //if this would be commented out than the json string value "true" would pe parsed to a bool literal
+            //but this is according to json spec invalid
+            /*if (JsonString.class.isInstance(jsonValue)) {
+                return Boolean.valueOf(JsonString.class.cast(jsonValue).getString());
+            }*/
+            
+            if(jsonValue == JsonValue.FALSE) {
+                return Boolean.FALSE;
+            }
+            
+            if(jsonValue == JsonValue.TRUE) {
+                return Boolean.TRUE;
+            }
+            
+            throw new MapperException("Unable to parse "+jsonValue+" to boolean");
+        }
+        
+        if (type == Character.class || type == char.class) {
+            
+            return convertTo(Class.class.cast(type), (JsonString.class.cast(jsonValue).getString()));
+        }
+        
+        if (JsonObject.class.isInstance(jsonValue)) {
+            return buildObject(type, JsonObject.class.cast(jsonValue));
+        } else if (JsonArray.class.isInstance(jsonValue)) {
+            return buildArray(type, JsonArray.class.cast(jsonValue));
+        } else if (JsonNumber.class.isInstance(jsonValue)) {
+                
+                final JsonNumber number = JsonNumber.class.cast(jsonValue);
+                
+                if (type == Long.class || type == long.class) {
+                    return number.longValue();
+                }
+                
+                if (type == Integer.class || type == int.class) {
+                    return number.intValue();
+                }
+                                
+                if (type == Short.class || type == short.class) {
+                    return (short) number.intValue();
+                }
+                
+                if (type == Byte.class || type == byte.class) {
+                    return (byte) number.intValue();
+                }
+                
+                if (type == Float.class || type == float.class) {
+                    return (float) number.doubleValue();
+                }
+                
+                if (type == Double.class || type == double.class) {
+                    return number.doubleValue();
+                }
+                
+                if (type == BigInteger.class) {
+                    return number.bigIntegerValue();
+                }
+                if (type == BigDecimal.class) {
+                    return number.bigDecimalValue();
+                }
+           
+        } else if (JsonString.class.isInstance(jsonValue)) {
+            return convertTo(Class.class.cast(type), (JsonString.class.cast(jsonValue).getString()));
+        }
+
+        
+        throw new MapperException("Unable to parse "+jsonValue+" to "+type);
+    }
+
+    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 (SortedSet.class == mapping.raw) {
+            collection = new TreeSet<T>();
+        } else if (Set.class == mapping.raw) {
+            collection = new HashSet<T>(jsonArray.size());
+        } else if (Queue.class == mapping.raw) {
+            collection = new ArrayBlockingQueue<T>(jsonArray.size());
+          //fail fast if collection is not know, assume Collection.class to be compatible with ArrayList is wrong for almost all cases
+        } else if (List.class == mapping.raw /*|| Collection.class == mapping.raw*/) {
+            collection = new ArrayList<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;
+    }
+
+    private static class FallbackConverter implements Converter<Object> {
+        @Override
+        public String toString(final Object instance) {
+            return instance.toString();
+        }
+
+        @Override
+        public Object fromString(final String text) {
+            throw new UnsupportedOperationException("Using fallback converter, " +
+                "this only works in write mode but not in read. Please register a custom converter to do so.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
new file mode 100644
index 0000000..e31aab6
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperBuilder.java
@@ -0,0 +1,127 @@
+/*
+ * 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.johnzon.mapper;
+
+import org.apache.johnzon.mapper.converter.BigDecimalConverter;
+import org.apache.johnzon.mapper.converter.BigIntegerConverter;
+import org.apache.johnzon.mapper.converter.BooleanConverter;
+import org.apache.johnzon.mapper.converter.ByteConverter;
+import org.apache.johnzon.mapper.converter.CachedDelegateConverter;
+import org.apache.johnzon.mapper.converter.CharacterConverter;
+import org.apache.johnzon.mapper.converter.ClassConverter;
+import org.apache.johnzon.mapper.converter.DateConverter;
+import org.apache.johnzon.mapper.converter.DoubleConverter;
+import org.apache.johnzon.mapper.converter.FloatConverter;
+import org.apache.johnzon.mapper.converter.IntegerConverter;
+import org.apache.johnzon.mapper.converter.LongConverter;
+import org.apache.johnzon.mapper.converter.ShortConverter;
+import org.apache.johnzon.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.Comparator;
+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(Character.class, new CharacterConverter());
+        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(char.class, new CharacterConverter());
+        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 Comparator<String> attributeOrder = null;
+    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, attributeOrder);
+    }
+
+    public MapperBuilder setAttributeOrder(final Comparator<String> attributeOrder) {
+        this.attributeOrder = attributeOrder;
+        return this;
+    }
+
+    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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperException.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperException.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MapperException.java
new file mode 100644
index 0000000..6b5f00a
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigDecimalConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigDecimalConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigDecimalConverter.java
new file mode 100644
index 0000000..b5864e0
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigIntegerConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigIntegerConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BigIntegerConverter.java
new file mode 100644
index 0000000..16710dd
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BooleanConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BooleanConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/BooleanConverter.java
new file mode 100644
index 0000000..668b7df
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ByteConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ByteConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ByteConverter.java
new file mode 100644
index 0000000..f4d7991
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CachedDelegateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CachedDelegateConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CachedDelegateConverter.java
new file mode 100644
index 0000000..e1babff
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CharacterConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CharacterConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/CharacterConverter.java
new file mode 100644
index 0000000..d028eb6
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ClassConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ClassConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/ClassConverter.java
new file mode 100644
index 0000000..31e0f2c
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DateConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DateConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DateConverter.java
new file mode 100644
index 0000000..00af32a
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DoubleConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DoubleConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/DoubleConverter.java
new file mode 100644
index 0000000..ac73684
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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-johnzon/blob/6e86a53e/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/EnumConverter.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/EnumConverter.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/converter/EnumConverter.java
new file mode 100644
index 0000000..793356d
--- /dev/null
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/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.johnzon.mapper.converter;
+
+import org.apache.johnzon.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);
+    }
+}