You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@johnzon.apache.org by rs...@apache.org on 2016/05/10 16:46:10 UTC

[2/4] incubator-johnzon git commit: JOHNZON-77 implemented ObjectConverter support for @JohnzonConverter

JOHNZON-77 implemented ObjectConverter support for @JohnzonConverter


Project: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/commit/c369178b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/tree/c369178b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-johnzon/diff/c369178b

Branch: refs/heads/master
Commit: c369178b404e668da69589e5acd27b25ea3d2ec5
Parents: ef9e19e
Author: Reinhard Sandtner <rs...@apache.org>
Authored: Tue May 10 12:20:34 2016 +0200
Committer: Reinhard Sandtner <rs...@apache.org>
Committed: Tue May 10 12:20:34 2016 +0200

----------------------------------------------------------------------
 .../johnzon/mapper/MappingGeneratorImpl.java    |  19 +-
 .../johnzon/mapper/MappingParserImpl.java       |  17 +-
 .../org/apache/johnzon/mapper/Mappings.java     |  99 +++++---
 .../ObjectConverterWithAnnotationTest.java      | 229 +++++++++++++++++++
 4 files changed, 322 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/c369178b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
index bc0f531..48c999d 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingGeneratorImpl.java
@@ -133,7 +133,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
             final boolean map = clazz || primitive || array || collection ? false : Map.class.isAssignableFrom(valueClass);
             writeValue(valueClass,
                     primitive, array, collection, map, itemConverter,
-                    key == null ? "null" : key.toString(), value);
+                    key == null ? "null" : key.toString(), value, null);
         }
         return generator;
     }
@@ -260,7 +260,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
                     getter.collection, getter.map,
                     getter.itemConverter,
                     getterEntry.getKey(),
-                    val);
+                    val, getter.objectConverter);
         }
         return generator;
     }
@@ -269,7 +269,7 @@ public class MappingGeneratorImpl implements MappingGenerator {
                             final boolean primitive, final boolean array,
                             final boolean collection, final boolean map,
                             final Adapter itemConverter,
-                            final String key, final Object value) throws InvocationTargetException, IllegalAccessException {
+                            final String key, final Object value, final ObjectConverter objectConverter) throws InvocationTargetException, IllegalAccessException {
         if (array) {
             final int length = Array.getLength(value);
             if (length == 0 && config.isSkipEmptyArray()) {
@@ -315,13 +315,18 @@ public class MappingGeneratorImpl implements MappingGenerator {
                 if (writePrimitives(key, adapted.getClass(), adapted)) {
                     return;
                 }
-                writeValue(String.class, true, false, false, false, null, key, adapted);
+                writeValue(String.class, true, false, false, false, null, key, adapted, null);
                 return;
             } else {
-                ObjectConverter objectConverter = config.findObjectConverter(type);
-                if (objectConverter != null) {
+
+                ObjectConverter objectConverterToUse = objectConverter;
+                if (objectConverterToUse == null) {
+                    objectConverterToUse = config.findObjectConverter(type);
+                }
+
+                if (objectConverterToUse != null) {
                     generator.writeStartObject(key);
-                    objectConverter.writeJson(value, this);
+                    objectConverterToUse.writeJson(value, this);
                     generator.writeEnd();
                     return;
                 }

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/c369178b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
index ad6feeb..87ceb49 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/MappingParserImpl.java
@@ -294,7 +294,7 @@ public class MappingParserImpl implements MappingParser {
                         }
                     }
                 }
-                final Object convertedValue = toValue(existingInstance, jsonValue, value.converter, value.itemConverter, value.paramType);
+                final Object convertedValue = toValue(existingInstance, jsonValue, value.converter, value.itemConverter, value.paramType, value.objectConverter);
                 if (convertedValue != null) {
                     setterMethod.write(t, convertedValue);
                 }
@@ -527,14 +527,25 @@ public class MappingParserImpl implements MappingParser {
                                  object.get(mapping.factory.getParameterNames()[i]),
                                  mapping.factory.getParameterConverter()[i],
                                  mapping.factory.getParameterItemConverter()[i],
-                                 mapping.factory.getParameterTypes()[i]);
+                                 mapping.factory.getParameterTypes()[i],
+                                 null); //X TODO ObjectConverter in @JOhnzonConverter with Constructors!
         }
 
         return objects;
     }
 
     private Object toValue(final Object baseInstance, final JsonValue jsonValue, final Adapter converter,
-                           final Adapter itemConverter, final Type type) {
+                           final Adapter itemConverter, final Type type, final ObjectConverter objectConverter) {
+
+        if (objectConverter != null) {
+
+            if (jsonValue instanceof JsonObject) {
+                return objectConverter.fromJson((JsonObject) jsonValue, type, this);
+            } else {
+                throw new UnsupportedOperationException("Array handling with ObjectConverter currently not implemented");
+            }
+        }
+
         return converter == null ? toObject(baseInstance, jsonValue, type, itemConverter)
                                  : jsonValue.getValueType() == JsonValue.ValueType.STRING ? converter.to(JsonString.class.cast(jsonValue).getString())
                                                                                           : convertTo(converter, jsonValue);

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/c369178b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
index 52a6eca..8c1154b 100644
--- a/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
+++ b/johnzon-mapper/src/main/java/org/apache/johnzon/mapper/Mappings.java
@@ -85,6 +85,7 @@ public class Mappings {
         final int version;
         final Adapter converter;
         final Adapter itemConverter;
+        final ObjectConverter objectConverter;
         final boolean primitive;
         final boolean array;
         final boolean map;
@@ -93,23 +94,43 @@ public class Mappings {
         public Getter(final AccessMode.Reader reader,
                       final boolean primitive, final boolean array,
                       final boolean collection, final boolean map,
-                      final Adapter<?, ?> converter,
+                      final MapperConverter converter,
                       final int version) {
             this.reader = reader;
             this.version = version;
             this.array = array;
             this.collection = collection;
             this.primitive = primitive;
-            if (converter != null && matches(reader.getType(), converter)) {
-                this.converter = converter;
-                this.itemConverter = null;
-            } else if (converter != null) {
-                this.converter = null;
-                this.itemConverter = converter;
-            } else {
-                this.converter = null;
-                this.itemConverter = null;
+
+            Adapter theConverter = null;
+            Adapter theItemConverter = null;
+            ObjectConverter theObjectConverter = null;
+
+            if (converter != null) {
+
+                if (converter instanceof ObjectConverter) {
+                    theObjectConverter = (ObjectConverter) converter;
+                } else {
+
+                    Adapter adapter;
+                    if (converter instanceof Converter) {
+                        adapter = new ConverterAdapter((Converter) converter);
+                    } else {
+                        adapter = (Adapter) converter;
+                    }
+
+                    if (matches(reader.getType(), adapter)) {
+                        theConverter = adapter;
+                    } else {
+                        theItemConverter = adapter;
+                    }
+                }
             }
+
+            this.converter = theConverter;
+            this.itemConverter = theItemConverter;
+            this.objectConverter = theObjectConverter;
+
             this.map = map && this.converter == null;
         }
 
@@ -132,29 +153,49 @@ public class Mappings {
         public final AccessMode.Writer writer;
         public final int version;
         public final Type paramType;
-        public final Adapter<?, ?> converter;
-        public final Adapter<?, ?> itemConverter;
+        public final Adapter converter;
+        public final Adapter itemConverter;
+        public final ObjectConverter objectConverter;
         public final boolean primitive;
         public final boolean array;
 
         public Setter(final AccessMode.Writer writer, final boolean primitive, final boolean array,
-                      final Type paramType, final Adapter<?, ?> converter,
+                      final Type paramType, final MapperConverter converter,
                       final int version) {
             this.writer = writer;
             this.paramType = paramType;
             this.version = version;
             this.primitive = primitive;
             this.array = array;
-            if (converter != null && matches(writer.getType(), converter)) {
-                this.converter = converter;
-                this.itemConverter = null;
-            } else if (converter != null) {
-                this.converter = null;
-                this.itemConverter = converter;
-            } else {
-                this.converter = null;
-                this.itemConverter = null;
+
+            Adapter theConverter = null;
+            Adapter theItemConverter = null;
+            ObjectConverter theObjectConverter = null;
+
+            if (converter != null) {
+
+                if (converter instanceof ObjectConverter) {
+                    theObjectConverter = (ObjectConverter) converter;
+                } else {
+
+                    Adapter adapter;
+                    if (converter instanceof Converter) {
+                        adapter = new ConverterAdapter((Converter) converter);
+                    } else {
+                        adapter = (Adapter) converter;
+                    }
+
+                    if (matches(writer.getType(), adapter)) {
+                        theConverter = adapter;
+                    } else {
+                        theItemConverter = adapter;
+                    }
+                }
             }
+
+            this.converter = theConverter;
+            this.itemConverter = theItemConverter;
+            this.objectConverter = theObjectConverter;
         }
 
         @Override
@@ -431,8 +472,8 @@ public class Mappings {
         setters.put(key, new Setter(newSetter == null ? newWriter : new CompositeWriter(newSetter.writer, newWriter), false, false, VIRTUAL_TYPE, null, -1));
     }
 
-    private Adapter findConverter(final boolean copyDate, final AccessMode.DecoratedType decoratedType) {
-        Adapter converter = decoratedType.findConverter();
+    private MapperConverter findConverter(final boolean copyDate, final AccessMode.DecoratedType decoratedType) {
+        MapperConverter converter = decoratedType.findConverter();
         if (converter != null) {
             return converter;
         }
@@ -442,13 +483,7 @@ public class Mappings {
         Type typeToTest = decoratedType.getType();
         if (annotation != null) {
             try {
-                MapperConverter mapperConverter = annotation.value().newInstance();
-                if (mapperConverter instanceof Converter) {
-                    converter = new ConverterAdapter((Converter) mapperConverter);
-                } else {
-                    throw new UnsupportedOperationException("TODO implement");
-                }
-
+                converter = annotation.value().newInstance();
             } catch (final Exception e) {
                 throw new IllegalArgumentException(e);
             }
@@ -472,7 +507,7 @@ public class Mappings {
                 converter = adapters.get(key); // first ensure user didnt override it
                 if (converter == null) {
                     converter = new ConverterAdapter(new EnumConverter(type));
-                    adapters.put(key, converter);
+                    adapters.put(key, (Adapter<?, ?>) converter);
                 }
             } else {
                 for (final Map.Entry<AdapterKey, Adapter<?, ?>> adapterEntry : adapters.entrySet()) {

http://git-wip-us.apache.org/repos/asf/incubator-johnzon/blob/c369178b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
----------------------------------------------------------------------
diff --git a/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
new file mode 100644
index 0000000..343a5a8
--- /dev/null
+++ b/johnzon-mapper/src/test/java/org/apache/johnzon/mapper/ObjectConverterWithAnnotationTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import javax.json.JsonObject;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(value = Parameterized.class)
+public class ObjectConverterWithAnnotationTest {
+
+    private static final String MANUFACTURER_ID = "manufacturerId";
+    private static final String TYPE_INDEX = "typeIndex";
+
+
+    @Parameterized.Parameter
+    public String accessMode;
+
+
+    @Parameterized.Parameters()
+    public static Iterable<String> accessModes() {
+        return Arrays.asList("field", "method", "both", "strict-method");
+    }
+
+
+    @Test
+    public void testSerializeWithObjectConverter() {
+
+        Mapper mapper = new MapperBuilder().setAccessModeName(accessMode)
+                                           .build();
+
+        Cyclist cyclist = new Cyclist("Peter Sagan", new Bike("Specialized / S-Works", BikeType.ROAD));
+
+        String json = mapper.writeObjectAsString(cyclist);
+        Assert.assertNotNull(json);
+        Assert.assertEquals("{" +
+                              "\"name\":\"Peter Sagan\"," +
+                              "\"bike\":{" +
+                                "\"" + MANUFACTURER_ID + "\":0," +
+                                "\"" + TYPE_INDEX + "\":0" +
+                              "}" +
+                            "}", json);
+
+    }
+
+    @Test
+    public void testDeserializeWithObjectConverter() {
+
+        Mapper mapper = new MapperBuilder().setAccessModeName(accessMode)
+                                           .build();
+
+        String json = "{" +
+                        "\"name\":\"Jan Frodeno\"," +
+                        "\"bike\":{" +
+                          "\"" + MANUFACTURER_ID + "\":1," +
+                          "\"" + TYPE_INDEX + "\":2" +
+                        "}" +
+                      "}";
+
+        Cyclist expected = new Cyclist("Jan Frodeno", new Bike("Canyon", BikeType.TRIATHLON));
+
+        Object cyclist = mapper.readObject(json, Cyclist.class);
+        Assert.assertNotNull(cyclist);
+        Assert.assertEquals(expected, cyclist);
+    }
+
+
+
+    public static class Cyclist {
+
+        private String name;
+
+        @JohnzonConverter(value = BikeConverter.class)
+        private Bike bike;
+
+        public Cyclist() {
+        }
+
+        public Cyclist(String name, Bike bike) {
+            this.name = name;
+            this.bike = bike;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        @JohnzonConverter(value = BikeConverter.class)
+        public Bike getBike() {
+            return bike;
+        }
+
+        @JohnzonConverter(value = BikeConverter.class)
+        public void setBike(Bike bike) {
+            this.bike = bike;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            Cyclist cyclist = (Cyclist) o;
+
+            if (name != null ? !name.equals(cyclist.name) : cyclist.name != null) {
+                return false;
+            }
+            return bike != null ? bike.equals(cyclist.bike) : cyclist.bike == null;
+
+        }
+
+        @Override
+        public int hashCode() {
+            int result = name != null ? name.hashCode() : 0;
+            result = 31 * result + (bike != null ? bike.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public static class Bike {
+        private String manufacturer;
+        private BikeType type;
+
+        public Bike() {
+        }
+
+        public Bike(String manufacturer, BikeType type) {
+            this.manufacturer = manufacturer;
+            this.type = type;
+        }
+
+        public String getManufacturer() {
+            return manufacturer;
+        }
+
+        public void setManufacturer(String manufacturer) {
+            this.manufacturer = manufacturer;
+        }
+
+        public BikeType getType() {
+            return type;
+        }
+
+        public void setType(BikeType type) {
+            this.type = type;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (o == null || getClass() != o.getClass()) {
+                return false;
+            }
+
+            Bike bike = (Bike) o;
+
+            if (manufacturer != null ? !manufacturer.equals(bike.manufacturer) : bike.manufacturer != null) {
+                return false;
+            }
+            return type == bike.type;
+
+        }
+
+        @Override
+        public int hashCode() {
+            int result = manufacturer != null ? manufacturer.hashCode() : 0;
+            result = 31 * result + (type != null ? type.hashCode() : 0);
+            return result;
+        }
+    }
+
+    public enum BikeType {
+        ROAD,
+        TIME_TRIAL,
+        TRIATHLON
+    }
+
+    public static class BikeConverter implements ObjectConverter<Bike> {
+
+        public static final List<String> MANUFACTURERS = Arrays.asList("Specialized / S-Works", "Canyon", "Trek", "Scott");
+
+
+        @Override
+        public void writeJson(Bike instance, MappingGenerator jsonbGenerator) {
+            jsonbGenerator.getJsonGenerator().write(MANUFACTURER_ID, MANUFACTURERS.indexOf(instance.getManufacturer()));
+
+            // i know you should never use this in production but its good for our sample ;)
+            jsonbGenerator.getJsonGenerator().write(TYPE_INDEX, instance.getType().ordinal());
+        }
+
+        @Override
+        public Bike fromJson(JsonObject jsonObject, Type targetType, MappingParser parser) {
+            return new Bike(MANUFACTURERS.get(jsonObject.getInt(MANUFACTURER_ID)),
+                            BikeType.values()[jsonObject.getInt(TYPE_INDEX)]);
+        }
+    }
+}