Hi, I'm working on a deserializer for Optionals with specifiable values for Optional.empty().
Here is the source code of the deserializer I came up with: 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; } } This is how I create the ObjectMapper: new ObjectMapper() .registerModule(new JavaTimeModule()) .registerModule( new SimpleModule() .addDeserializer( Optional.class, new EmptyOptionalDeserializer() .register(Integer.class, new Integer(-1)) .register(String.class, "") ) ); It works as expected for "real" values, but if null occurres it does not. For example if I have this JSON string: {"test":null} And this class: public class A { public Optional<String> test; } And want to deserialize: A a = mapper.readValue(json, A.class); I expected a.test to be an empty Optional now, but it is actually null. Looking a bit deeper into it, I can see that EmptyOptionalDeserializer#createContextual will be called and thus the actual deserializer is instantiated. And now the problem arises: the deserializer's deserialze method will not be called, and a.test will be set to null by something else, so a work around like public class A { public Optional<String> test = Optional.empty(); } does not work either. If i run the same code against a JSON string like this: {"test":""} It is perfectly fine and a.test is an empty Optional. What am I doing wrong? Regards, cap5lut -- 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.