Jackson deserialize object or array

前端 未结 4 1995
梦如初夏
梦如初夏 2020-12-09 04:14

I have a Jackson Question.

Is there a way to deserialize a property that may have two types, for some objects it appears like this

\"someObj\" : { \"         


        
4条回答
  •  生来不讨喜
    2020-12-09 04:38

    There’s another angle to tackle this problem more generically for objects that would be deserialized using the BeanDeserializer, by creating a BeanDeserializerModifier and registering it with your mapper. BeanDeserializerModifier is a sort of alternative to subclassing BeanDeserializerFactory, and it gives you a chance to return something other than the normal deserializer that would be used, or to modify it.

    So, first create a new JsonDeserializer that can accept another deserializer when it’s being constructed, and then holds on to that serializer. In the deserialize method, you can check if you’re being passed a JsonParser that's currently pointing at a JsonToken.START_ARRAY. If you’re not passed JsonToken.START_ARRAY, then just use the default deserializer that was passed in to this custom deserialize when it was created.

    Finally, make sure to implement ResolvableDeserializer, so that the default deserializer is properly attached to the context that your custom deserializer is using.

    class ArrayAsNullDeserialzer extends JsonDeserializer implements ResolvableDeserializer {
        JsonDeserializer mDefaultDeserializer;
    
        @Override
        /* Make sure the wrapped deserializer is usable in this deserializer's contexts */
        public void resolve(DeserializationContext ctxt) throws JsonMappingException  {
             ((ResolvableDeserializer) mDefaultDeserializer).resolve(ctxt);
        }
    
        /* Pass in the deserializer given to you by BeanDeserializerModifier */
        public ArrayAsNullDeserialzer(JsonDeserializer defaultDeserializer) {
            mDefaultDeserializer = defaultDeserializer;
        }
    
        @Override
        public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
            JsonToken firstToken = jp.getCurrentToken();
            if (firstToken == JsonToken.START_ARRAY) {
                //Optionally, fail if this is something besides an empty array
               return null;
            } else {
                return mDefaultDeserializer.deserialize(jp, ctxt);
            }
        }
    }
    

    Now that we have our generic deserializer hook, let’s create a modifier that can use it. This is easy, just implement the modifyDeserializer method in your BeanDeserializerModifier. You will be passed the deserializer that would have been used to deserialize the bean. It also passes you the BeanDesc that will be deserialized, so you can control here whether or not you want to handle [] as null for all types.

    public class ArrayAsNullDeserialzerModifier extends BeanDeserializerModifier  {
    
        @Override
        public JsonDeserializer modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer deserializer) {
            if ( true /* or check beanDesc to only do this for certain types, for example */ ) {
                return new ArrayAsNullDeserializer(deserializer);
            } else {
                return deserializer;
            }
        }
    }
    

    Finally, you’ll need to register your BeanDeserializerModifier with your ObjectMapper. To do this, create a module, and add the modifier in the setup (SimpleModules don’t seem to have a hook for this, unfortunately). You can read more about modules elsewhere, but here’s an example if you don’t already have a module to add to:

    Module m = new Module() {
        @Override public String getModuleName() { return "MyMapperModule"; }
        @Override public Version version() { return Version.unknownVersion(); }
        @Override public void setupModule(Module.SetupContext context) {
            context.addBeanDeserializerModifier(new ArrayAsNullDeserialzerModifier());
        }
    };
    

提交回复
热议问题