jackson-databind icon indicating copy to clipboard operation
jackson-databind copied to clipboard

Existing object of local/anonymous class cannot be updated

Open avshenuk opened this issue 4 years ago • 2 comments

When using readerForUpdating with an existing object, Jackson fails with:

Cannot deserialize Class mypackage.MyClass$1 (of type local/anonymous) as a Bean
	at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.isPotentialBeanType(BeanDeserializerFactory.java:883)
	at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:137)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:414)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:349)
	at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)

Version information 2.10.3

To Reproduce

package mypackage;
public class MyClass {
   public static void main(int[] args) {
       Object resultObject = new Object() {
           int value;
       }
       new ObjectMapper().readerForUpdating(resultObject).readValue("{\"value\": 2}");
   }
}

Expected behavior Since Jackson is not required to construct an instance of the anonymous class, it should be able to populate the fields on the existing object. Investigation shows that the method

public Object deserialize(JsonParser p, DeserializationContext ctxt, Object bean) throws IOException

in com.fasterxml.jackson.databind.deser.BeanDeserializer doesn't use ValueInstantiator _valueInstantiator field.

So can it be made optional when you're updating an existing instance?

avshenuk avatar Aug 02 '21 10:08 avshenuk

Workaround that worked for me was to write a custom deserializer and simply exclude the validation code:

protected static class CustomDeserializer<T> extends JsonDeserializer<T> {
        @Override
        public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
            throw new IllegalStateException("Unsupported");
        }

        @Override
        @SuppressWarnings("unchecked")
        public T deserialize(JsonParser p, DeserializationContext ctxt, T intoValue) throws IOException {
            JavaType javaType = ctxt.getTypeFactory().constructType(intoValue.getClass());
            JsonDeserializer<T> jsonDeserializer = (JsonDeserializer<T>) ((BeanDeserializerFactory) ctxt.getFactory())
                    .buildBeanDeserializer(ctxt, javaType, ctxt.getConfig().introspect(javaType));
            ((ResolvableDeserializer) jsonDeserializer).resolve(ctxt);
            jsonDeserializer = (JsonDeserializer<T>) ctxt.handleSecondaryContextualization(jsonDeserializer, null, javaType);
            return jsonDeserializer.deserialize(p, ctxt, intoValue);
        }
    }

avshenuk avatar Aug 02 '21 16:08 avshenuk

Would definitely be nice to support this at some point in future.

cowtowncoder avatar Sep 04 '21 00:09 cowtowncoder