diff --git a/genson/src/main/java/com/owlike/genson/ext/jsr353/JSR353Bundle.java b/genson/src/main/java/com/owlike/genson/ext/jsr353/JSR353Bundle.java index 46bb3c81..14f4a64f 100644 --- a/genson/src/main/java/com/owlike/genson/ext/jsr353/JSR353Bundle.java +++ b/genson/src/main/java/com/owlike/genson/ext/jsr353/JSR353Bundle.java @@ -37,7 +37,7 @@ public Converter create(Type type, Genson genson) { }); } - public class JsonValueConverter implements Converter { + public static class JsonValueConverter implements Converter { @Override public void serialize(JsonValue value, ObjectWriter writer, Context ctx) { diff --git a/genson/src/main/java/com/owlike/genson/reflect/BeanDescriptor.java b/genson/src/main/java/com/owlike/genson/reflect/BeanDescriptor.java index 0e17d46a..d6531d94 100644 --- a/genson/src/main/java/com/owlike/genson/reflect/BeanDescriptor.java +++ b/genson/src/main/java/com/owlike/genson/reflect/BeanDescriptor.java @@ -126,7 +126,7 @@ public void deserialize(T into, ObjectReader reader, Context ctx) { reader.skipValue(); } } else if (unknownPropertyHandler != null) { - unknownPropertyHandler.onUnknownProperty(into, propName, reader, ctx); + unknownPropertyHandler.readUnknownProperty(propName, reader, ctx).accept(into); } else if (failOnMissingProperty) throw missingPropertyException(propName); else reader.skipValue(); } @@ -157,7 +157,7 @@ protected T _deserWithCtrArgs(ObjectReader reader, Context ctx) { reader.skipValue(); } } else if (unknownPropertyHandler != null) { - Consumer callback = unknownPropertyHandler.onUnknownProperty(null, propName, reader, ctx); + Consumer callback = unknownPropertyHandler.readUnknownProperty(propName, reader, ctx); unknownProperties.add(callback); } else if (failOnMissingProperty) throw missingPropertyException(propName); else reader.skipValue(); @@ -190,9 +190,8 @@ protected T _deserWithCtrArgs(ObjectReader reader, Context ctx) { property.mutate(bean, newValues[i]); } } - if (!unknownProperties.isEmpty()) { - unknownProperties.forEach(callback -> callback.accept(bean)); - } + unknownProperties.forEach(callback -> callback.accept(bean)); + reader.endObject(); return bean; } diff --git a/genson/src/main/java/com/owlike/genson/reflect/Evolvable.java b/genson/src/main/java/com/owlike/genson/reflect/Evolvable.java index 43fd87f3..83f03dd7 100644 --- a/genson/src/main/java/com/owlike/genson/reflect/Evolvable.java +++ b/genson/src/main/java/com/owlike/genson/reflect/Evolvable.java @@ -1,5 +1,6 @@ package com.owlike.genson.reflect; +import javax.json.JsonValue; import java.util.Map; /** @@ -19,12 +20,12 @@ interface Evolvable { * @param propName property name * @param propValue property value */ - void addUnknownProperty(String propName, Object propValue); + void addUnknownProperty(String propName, JsonValue propValue); /** * Return a map of unknown properties. * * @return a map of unknown properties */ - Map unknownProperties(); + Map unknownProperties(); } diff --git a/genson/src/main/java/com/owlike/genson/reflect/EvolvableHandler.java b/genson/src/main/java/com/owlike/genson/reflect/EvolvableHandler.java index b77f562f..c344af8e 100644 --- a/genson/src/main/java/com/owlike/genson/reflect/EvolvableHandler.java +++ b/genson/src/main/java/com/owlike/genson/reflect/EvolvableHandler.java @@ -1,11 +1,13 @@ package com.owlike.genson.reflect; import com.owlike.genson.Context; -import com.owlike.genson.GenericType; +import com.owlike.genson.Converter; +import com.owlike.genson.ext.jsr353.JSR353Bundle; import com.owlike.genson.stream.ObjectReader; import com.owlike.genson.stream.ObjectWriter; import javax.json.JsonValue; + import java.util.Map; import java.util.function.Consumer; @@ -25,41 +27,37 @@ * @author Aleksandar Seovic 2018.05.20 */ public class EvolvableHandler implements UnknownPropertyHandler { - private static final GenericType UNKNOWN = new GenericType() {}; + private static final Converter CONVERTER = new JSR353Bundle.JsonValueConverter(); @Override - public Consumer onUnknownProperty(T target, String propName, ObjectReader reader, Context ctx) { - // TODO: change this to read property as an opaque value, using ObjectReader directly - Object propValue = ctx.genson.deserialize(UNKNOWN, reader, ctx); + public Consumer readUnknownProperty(String propName, ObjectReader reader, Context ctx) { + try { + JsonValue propValue = CONVERTER.deserialize(reader, ctx); - if (target == null) { - // this is a bit ugly... - // the issue is that we may not have a target object while parsing JSON when using creators, - // so we need to store the parsed value somewhere and apply it later return objTarget -> { if (objTarget instanceof Evolvable) { ((Evolvable) objTarget).addUnknownProperty(propName, propValue); } }; + } catch (Exception e) { + throw new RuntimeException(e); } - - if (target instanceof Evolvable) { - ((Evolvable) target).addUnknownProperty(propName, propValue); - } - return null; } @Override - public void writeUnknownProperties(T source, ObjectWriter writer, Context ctx) { - if (source instanceof Evolvable) { - Map props = ((Evolvable) source).unknownProperties(); - if (props != null) { - for (String propName : props.keySet()) { - writer.writeName(propName); - // TODO: change this to write property as an opaque value, using ObjectWriter directly - ctx.genson.serialize(props.get(propName), writer, ctx); + public void writeUnknownProperties(T bean, ObjectWriter writer, Context ctx) { + try { + if (bean instanceof Evolvable) { + Map props = ((Evolvable) bean).unknownProperties(); + if (props != null) { + for (String propName : props.keySet()) { + writer.writeName(propName); + CONVERTER.serialize(props.get(propName), writer, ctx); + } } } + } catch (Exception e) { + throw new RuntimeException(e); } } } \ No newline at end of file diff --git a/genson/src/main/java/com/owlike/genson/reflect/EvolvableObject.java b/genson/src/main/java/com/owlike/genson/reflect/EvolvableObject.java index 4796b127..7256cfdb 100644 --- a/genson/src/main/java/com/owlike/genson/reflect/EvolvableObject.java +++ b/genson/src/main/java/com/owlike/genson/reflect/EvolvableObject.java @@ -2,6 +2,7 @@ import com.owlike.genson.annotation.JsonIgnore; +import javax.json.JsonValue; import java.util.HashMap; import java.util.Map; @@ -12,10 +13,10 @@ */ public abstract class EvolvableObject implements Evolvable { @JsonIgnore - private Map unknownProperties; + private Map unknownProperties; @Override - public void addUnknownProperty(String propName, Object propValue) { + public void addUnknownProperty(String propName, JsonValue propValue) { if (unknownProperties == null) { unknownProperties = new HashMap<>(); } @@ -23,7 +24,7 @@ public void addUnknownProperty(String propName, Object propValue) { } @Override - public Map unknownProperties() { + public Map unknownProperties() { return unknownProperties; } } diff --git a/genson/src/main/java/com/owlike/genson/reflect/UnknownPropertyHandler.java b/genson/src/main/java/com/owlike/genson/reflect/UnknownPropertyHandler.java index c3bf8e0b..aa6450eb 100644 --- a/genson/src/main/java/com/owlike/genson/reflect/UnknownPropertyHandler.java +++ b/genson/src/main/java/com/owlike/genson/reflect/UnknownPropertyHandler.java @@ -29,14 +29,14 @@ public interface UnknownPropertyHandler { * property value somewhere so it can be written later by the * {@link #writeUnknownProperties} method. * - * @param target the object we are deserializing JSON into, if known * @param propName the name of the unknown property * @param reader the ObjectReader to read property value from * @param ctx deserialization context * - * @return the optional Consumer that will be called once the target object is known + * @return the Consumer that will be called with the target bean, + * once the target bean is known */ - Consumer onUnknownProperty(T target, String propName, ObjectReader reader, Context ctx); + Consumer readUnknownProperty(String propName, ObjectReader reader, Context ctx); /** * Write unknown properties encountered during deserialization. @@ -45,12 +45,10 @@ public interface UnknownPropertyHandler { * that want to write unknown properties during serialization. The default * implementation is a no-op. * - * @param source the object we are serializing into JSON + * @param bean the object we are serializing into JSON * @param writer the ObjectReader to read property value from * @param ctx serialization context - * - * @return a map of unknown properties */ - default void writeUnknownProperties(T source, ObjectWriter writer, Context ctx) { + default void writeUnknownProperties(T bean, ObjectWriter writer, Context ctx) { } }