Hello,
I have a problem with a deserializer I am working on.

At the deserializer I want to register values, which indicate that the 
resulting Optional<T> should be empty. But if the value in the JSON string 
is null, the Optional<T> will be null as well, else it works as expected.

Here is the code for the deserializer:
public class EmptyOptionalDeserializer extends JsonDeserializer<Optional<?>> 
implements ContextualDeserializer {
    private Map<Class<?>, Set<Object>> emptyValues;
    private JavaType valueType;


    public EmptyOptionalDeserializer() {
        this(Collections.synchronizedMap(new HashMap<>()), null);
    }


    /**
     * This constructor is only used for the contextual deserialization.
     * @param emptyValues Reference to the empty values map.
     * @param valueType Optional's value type.
     */
    protected EmptyOptionalDeserializer(Map<Class<?>, Set<Object>> 
emptyValues, JavaType valueType) {
        this.emptyValues = emptyValues;
        this.valueType = valueType;
    }


    /**
     * {@inheritDoc}
     */
    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext ctxt, 
BeanProperty property) throws JsonMappingException {
        return new EmptyOptionalDeserializer(emptyValues, property.getType
().containedType(0));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Optional<?> deserialize(JsonParser parser, DeserializationContext 
ctxt) throws IOException, JsonProcessingException {
        Object value = ctxt.readValue(parser, valueType);


        if(value == null) {
            return Optional.empty();
        }


        if(!emptyValues.containsKey(valueType.getRawClass())) { // class 
not registered
            return Optional.of(value);
        }


        Set<Object> emptyValues = this.emptyValues.get(valueType.getRawClass
());


        if(emptyValues == null) {
            return Optional.of(value);
        }


        return emptyValues.contains(value) ? Optional.empty() : Optional.of(
value);
    }


    /**
     * Registers values for a type which will count as empty optional.
     * @param type Type to register empty values for.
     * @param emptyValues Empty values.
     * @return Returns itself for method chaining.
     */
    public EmptyOptionalDeserializer register(Class<?> type, Object... 
emptyValues) {
        Collections.addAll(this.emptyValues.computeIfAbsent(type, t -> new 
HashSet<>()), emptyValues);
        return this;
    }
}

If I have a JSON string like
{"test":null}

and a POJO like
public class A {
    public Optional<String> test;
}

and create the ObjectMapper like
new ObjectMapper()
    .registerModule(
        new SimpleModule()
            .addDeserializer(
                Optional.class,
                new EmptyOptionalDeserializer()
                    .register(String.class, "")
            )
    );

and try to deserialize it to A, the Optional A.test will be null. The 
EmptyOptionalDeserializer#createContextual method will be called and thus 
the actual deserializer will created, but its deserialize method is not 
called.
If it were
{"test":""}
the deserializer would work as expected.

What am I doing wrong?

Regards.

-- 
You received this message because you are subscribed to the Google Groups 
"jackson-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jackson-user+unsubscr...@googlegroups.com.
To post to this group, send email to jackson-user@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to