yasson icon indicating copy to clipboard operation
yasson copied to clipboard

Deserializing Object or String

Open jsorel opened this issue 1 year ago • 1 comments

When trying to deserialize a bean property which can be a String or an Object, there is no way to deserialize the object version.

Version Yasson 3.0.3

To Reproduce

import jakarta.json.bind.JsonbBuilder;
import jakarta.json.bind.JsonbException;
import jakarta.json.bind.annotation.JsonbTypeDeserializer;
import jakarta.json.bind.serializer.DeserializationContext;
import jakarta.json.bind.serializer.JsonbDeserializer;
import jakarta.json.stream.JsonParser;
import java.lang.reflect.Type;

public class Test {

    public static class Parent {

        @JsonbTypeDeserializer(DomainDeserializer.class)
        public Object domain;
    }

    public static class Child {
        public String name;
    }

    public static class DomainDeserializer implements JsonbDeserializer<Object> {
        @Override
        public Object deserialize(JsonParser parser, DeserializationContext ctx, Type rtType) {
            final JsonParser.Event event = parser.next();
            if (event == JsonParser.Event.START_OBJECT) {
                // Deserialize inner object
                return ctx.deserialize(Child.class, parser);
            } else if (event == JsonParser.Event.VALUE_STRING) {
                return parser.getString();
            } else {
                throw new JsonbException("Unexpected json element " + event.name() + " " + parser.getString());
            }
        }
    }

    public static void main(String[] args) {

        Parent parent1 = JsonbBuilder.create().fromJson("{\"domain\": \"test\"}", Parent.class);
        Parent parent2 = JsonbBuilder.create().fromJson("{\"domain\": {\"name\":\"test\"}}", Parent.class);

    }
}

Additional context

In the first case Parent parent1 = JsonbBuilder.create().fromJson("{\"domain\": \"test\"}", Parent.class); We get :

Exception in thread "main" jakarta.json.bind.JsonbException: Internal error: There are no more elements available!
	at org.eclipse.yasson.internal.DeserializationContextImpl.deserializeItem(DeserializationContextImpl.java:142)
	at org.eclipse.yasson.internal.DeserializationContextImpl.deserialize(DeserializationContextImpl.java:127)
	at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:55)
	at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:62)
	at org.apache.sis.internal.coveragejson.Test.main(Test.java:48)
Caused by: java.util.NoSuchElementException: There are no more elements available!
	at org.eclipse.yasson.internal.deserializer.YassonParser.validate(YassonParser.java:192)
	at org.eclipse.yasson.internal.deserializer.YassonParser.next(YassonParser.java:71)
	at org.apache.sis.internal.coveragejson.Test$DomainDeserializer.deserialize(Test.java:34)
	at org.eclipse.yasson.internal.deserializer.UserDefinedDeserializer.deserialize(UserDefinedDeserializer.java:69)
	at org.eclipse.yasson.internal.deserializer.UserDefinedDeserializer.deserialize(UserDefinedDeserializer.java:26)
	at org.eclipse.yasson.internal.deserializer.ObjectDeserializer.deserialize(ObjectDeserializer.java:78)
	at org.eclipse.yasson.internal.deserializer.ObjectDeserializer.deserialize(ObjectDeserializer.java:31)
	at org.eclipse.yasson.internal.deserializer.DefaultObjectInstanceCreator.deserialize(DefaultObjectInstanceCreator.java:57)
	at org.eclipse.yasson.internal.deserializer.DefaultObjectInstanceCreator.deserialize(DefaultObjectInstanceCreator.java:29)
	at org.eclipse.yasson.internal.deserializer.PositionChecker.deserialize(PositionChecker.java:85)
	at org.eclipse.yasson.internal.deserializer.PositionChecker.deserialize(PositionChecker.java:34)
	at org.eclipse.yasson.internal.deserializer.NullCheckDeserializer.deserialize(NullCheckDeserializer.java:46)
	at org.eclipse.yasson.internal.deserializer.NullCheckDeserializer.deserialize(NullCheckDeserializer.java:26)
	at org.eclipse.yasson.internal.DeserializationContextImpl.deserializeItem(DeserializationContextImpl.java:138)
	... 4 more

In the second Parent parent2 = JsonbBuilder.create().fromJson("{\"domain\": {\"name\":\"test\"}}", Parent.class);

Exception in thread "main" jakarta.json.bind.JsonbException: Unable to deserialize property 'domain' because of: Unexpected json element KEY_NAME name
	at org.eclipse.yasson.internal.deserializer.ObjectDeserializer.deserialize(ObjectDeserializer.java:80)
	at org.eclipse.yasson.internal.deserializer.ObjectDeserializer.deserialize(ObjectDeserializer.java:31)
	at org.eclipse.yasson.internal.deserializer.DefaultObjectInstanceCreator.deserialize(DefaultObjectInstanceCreator.java:57)
	at org.eclipse.yasson.internal.deserializer.DefaultObjectInstanceCreator.deserialize(DefaultObjectInstanceCreator.java:29)
	at org.eclipse.yasson.internal.deserializer.PositionChecker.deserialize(PositionChecker.java:85)
	at org.eclipse.yasson.internal.deserializer.PositionChecker.deserialize(PositionChecker.java:34)
	at org.eclipse.yasson.internal.deserializer.NullCheckDeserializer.deserialize(NullCheckDeserializer.java:46)
	at org.eclipse.yasson.internal.deserializer.NullCheckDeserializer.deserialize(NullCheckDeserializer.java:26)
	at org.eclipse.yasson.internal.DeserializationContextImpl.deserializeItem(DeserializationContextImpl.java:138)
	at org.eclipse.yasson.internal.DeserializationContextImpl.deserialize(DeserializationContextImpl.java:127)
	at org.eclipse.yasson.internal.JsonBinding.deserialize(JsonBinding.java:55)
	at org.eclipse.yasson.internal.JsonBinding.fromJson(JsonBinding.java:62)
	at org.apache.sis.internal.coveragejson.Test.main(Test.java:49)
Caused by: jakarta.json.bind.JsonbException: Unexpected json element KEY_NAME name
	at org.apache.sis.internal.coveragejson.Test$DomainDeserializer.deserialize(Test.java:41)
	at org.eclipse.yasson.internal.deserializer.UserDefinedDeserializer.deserialize(UserDefinedDeserializer.java:69)
	at org.eclipse.yasson.internal.deserializer.UserDefinedDeserializer.deserialize(UserDefinedDeserializer.java:26)
	at org.eclipse.yasson.internal.deserializer.ObjectDeserializer.deserialize(ObjectDeserializer.java:78)
	... 12 more

Expected behavior In the first case I would have expected a VALUE_STRING event but instead we have nothing. In the second case I would have expected a START_OBJECT event but instead it jumps to the first attribute.

Or am I doing something wrong here ?

jsorel avatar May 09 '23 10:05 jsorel