有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java使用Jackson反序列化为字符串或对象

我有一个物体有时看起来像这样:

{
   "foo" : "bar",
   "fuzz" : "bla"
}

有时看起来是这样的:

{
   "foo" : { "value" : "bar", "baz": "asdf" },
   "fuzz" : { "thing" : "bla", "blip" : "asdf" }
}

这些课程看起来像:

public class Foo {
   String value;
   String baz;
}

public class Fuzz {
   String thing;
   String blip;
}

其中第一个案例是第二个案例的简写。我想一直反序列化到第二个案例中

此外,这在我们的代码中是一种非常常见的模式,因此我希望能够以一种通用的方式进行序列化,因为还有其他类似于上面Foo的类具有相同的模式,即使用字符串作为更复杂对象的语法糖

我想使用它的代码应该是这样的


public class Thing { 
  @JsonProperty("fuzz")
  Fuzz fuzz;

  @JsonProperty("foo")
  Foo foo;
}

如何编写一个自定义反序列化程序(或其他模块)来处理这两种情况


共 (1) 个答案

  1. # 1 楼答案

    为了使其通用,我们需要能够指定要在对象中为JSON primitive设置的名称。一些灵活性提供了注释方法。让我们定义简单注释:

    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    @interface JsonPrimitiveName {
        String value();
    }
    

    名称意味着:如果原语出现在JSON中,请使用value()获取给定原语的属性名称。它将JSON primitivePOJO字段绑定。处理JSON objectJSON primitive的简单反序列化程序:

    class PrimitiveOrPojoJsonDeserializer extends JsonDeserializer implements ContextualDeserializer {
    
        private String primitiveName;
        private JavaType type;
    
        @Override
        public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            JsonDeserializer<Object> deserializer = ctxt.findRootValueDeserializer(type);
            if (p.currentToken() == JsonToken.START_OBJECT) {
                return deserializer.deserialize(p, ctxt);
            } else if (p.currentToken() == JsonToken.VALUE_STRING) {
                BeanDeserializer beanDeserializer = (BeanDeserializer) deserializer;
                try {
                    Object instance = beanDeserializer.getValueInstantiator().getDefaultCreator().call();
                    SettableBeanProperty property = beanDeserializer.findProperty(primitiveName);
                    property.deserializeAndSet(p, ctxt, instance);
                    return instance;
                } catch (Exception e) {
                    throw JsonMappingException.from(p, e.getMessage());
                }
            }
    
            return null;
        }
    
        @Override
        public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) {
            JsonPrimitiveName annotation = property.getAnnotation(JsonPrimitiveName.class);
    
            PrimitiveOrPojoJsonDeserializer deserializer = new PrimitiveOrPojoJsonDeserializer();
            deserializer.primitiveName = annotation.value();
            deserializer.type = property.getType();
    
            return deserializer;
        }
    }
    

    现在我们需要如下注释POJO字段:

    class Root {
    
        @JsonPrimitiveName("value")
        @JsonDeserialize(using = PrimitiveOrPojoJsonDeserializer.class)
        private Foo foo;
    
        @JsonPrimitiveName("thing")
        @JsonDeserialize(using = PrimitiveOrPojoJsonDeserializer.class)
        private Fuzz fuzz;
    
        // getters, setters
    }
    

    我假设所有的类都是POJO-s,并且遵循所有规则,有getterssetters和默认构造函数。如果构造函数不存在,您需要以某种方式更改此beanDeserializer.getValueInstantiator().getDefaultCreator().call()行,以满足您的需求

    示例应用程序:

    import com.fasterxml.jackson.core.JsonParser;
    import com.fasterxml.jackson.core.JsonToken;
    import com.fasterxml.jackson.databind.BeanProperty;
    import com.fasterxml.jackson.databind.DeserializationContext;
    import com.fasterxml.jackson.databind.JavaType;
    import com.fasterxml.jackson.databind.JsonDeserializer;
    import com.fasterxml.jackson.databind.JsonMappingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
    import com.fasterxml.jackson.databind.deser.BeanDeserializer;
    import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
    import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
    
    import java.io.File;
    import java.io.IOException;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    public class JsonApp {
    
        public static void main(String[] args) throws Exception {
            File jsonFile = new File("./resource/test.json").getAbsoluteFile();
    
            ObjectMapper mapper = new ObjectMapper();
            System.out.println(mapper.readValue(jsonFile, Root.class));
        }
    }
    

    缩短JSON的打印:

    Root{foo=Foo{value='bar', baz='null'}, fuzz=Fuzz{thing='bla', blip='null'}}
    

    对于完整的JSON负载:

    Root{foo=Foo{value='bar', baz='asdf'}, fuzz=Fuzz{thing='bla', blip='asdf'}}