Custom Jackson Deserializer Getting Access to Current Field Class

前端 未结 4 984
遥遥无期
遥遥无期 2021-01-05 07:13

I\'m trying to write a custom deserializer for Jackson and I want to make it generic (generic in the sense of working on any type, not as in \"generics\").

However I

相关标签:
4条回答
  • 2021-01-05 07:40

    You don't -- deserializers are registered by type, so you need to construct deserializer to know what type it is expected to deserialize.

    If you do want to registered a generic deserializer, you can however make things more dynamic by implementing ContextualDeserializer. Its createContextual() method is called with BeanProperty argument, and you can check things like name of the property (which may be null, in case of root values which are not referenced by a property) and type (which is the declared type). This method can then return a new instance (do NOT modify original deserializer, since it is shared by all properties), configured with all extra information you need.

    0 讨论(0)
  • 2021-01-05 07:40

    Roughly speaking, and without exception catching and error checking...

    JsonToken tok = jp.nextValue();
    
    Field field = findField(jp.getCurrentName());
    
    Class<?> fc = field.getType();
    
    if(fc == int.class) {
       field.setInt(this, jp.getIntValue());
    } // handle all the primitive types and String in the same way, then...
    } ... else if(tok == JsonToken.START_ARRAY) {
       if(fc.isArray()) {
          // Load into an array
       } else if(Collection.class.isAssignableFrom(fc)) {
          // Load into a collection
       } else {
          // throw
       }
    } else if(tok == JsonToken.START_OBJECT) {
       // Recursively create that object from the JSON stream
    }
    

    ... and loop until tok is END_OBJECT. To find a of the current class by name:

    Field findField(String name) {
        for(Class<?> c = getClass(); c != null; c = c.getSuperclass()) {
            for(Field field : c.getDeclaredFields()) {
                if(field.getName().equals(name)) {
                    return field;
                }
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-05 07:43

    I have solved my particular problem by adding an implementation of Deserializers to the ObjectMapper. Eg

       Deserializers d = new Deserializers.Base() {
    
       @Override
       public JsonDeserializer<?> findEnumDeserializer(Class<?> type, DeserializationConfig config, BeanDescription beanDesc, BeanProperty property)
                      throws JsonMappingException {
                    if (property.getType().getContentType() != null)
                        return new EnumDeserializer(property.getType().getContentType().getRawClass());
                    return new EnumDeserializer(property.getType().getRawClass());
                }
    
            };
            mapper.setDeserializerProvider(mapper.getDeserializerProvider().withAdditionalDeserializers(d));
    

    This will return my custom EnumDeserializer instantiated for each separate Enum type.

    0 讨论(0)
  • 2021-01-05 07:48

    I solved it like this.

    Get current field java type...

    @Override
    public Enum deserialize(JsonParser jsonparser, DeserializationContext context) throws IOException, JsonProcessingException {
        System.out.println("EnumDeserializer ....");
        Field field = findField(jsonparser.getCurrentName(), jsonparser.getCurrentValue().getClass());
        Class<?> javaType = field.getType();
        return null;
    }
    
    public Field findField(String name, Class<?> c) {
        for (; c != null; c = c.getSuperclass()) {
            for (Field field : c.getDeclaredFields()) {
                if (Modifier.isStatic(field.getModifiers())) {
                    continue;
                }
                if (field.getName().equals(name)) {
                    return field;
                }
            }
        }
        return null;
    }
    

    0 讨论(0)
提交回复
热议问题