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
上面的类具有使用 String 作为语法糖的相同模式更复杂的对象。
我想使用它的代码看起来像这样
public class Thing {
@JsonProperty("fuzz")
Fuzz fuzz;
@JsonProperty("foo")
Foo foo;
}
如何编写通常处理这两种情况的自定义反序列化器(或其他模块)?
解决方案
为了使其通用,我们需要能够指定我们想在对象中设置的名称JSON primitive
。一些灵活性提供了注释方法。让我们定义简单的注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface JsonPrimitiveName {
String value();
}
名称意味着:如果原语将出现在JSON
使用value()
中以获取给定原语的属性名称。JSON primitive
它与POJO
字段绑定。处理JSON object
和的简单反序列化器JSON 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 并遵循所有规则 - havegetters
和setters
默认构造函数。如果构造函数不存在,您需要以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'}}
推荐阅读
- reactjs - React Native Promise、setState 和 Navigation 问题
- python - MoveTargetOutOfBoundsException - Python 网页抓取
- c++ - C++ 使用 32 位和 64 位库编译应用程序
- javascript - 使 React 表按字母顺序排序
- c++ - 如何从我的主窗口停止在我的对话框类中运行的线程
- java - 未能执行目标 com.spotify:docker-maven-plugin:1.2.1:build (build-image)
- javascript - 使用保留字 const 定义的变量
- c# - c# 具有 2 个键的隐式泛型类型
- mongodb - 当我创建一个 $group 时,如何返回所有对象中存在的属性的总和?
- python - 关闭 MacBook 盖子后 Python 线程池挂起