这可能吗?我想将JSON反序列化到POJO结构中,但除此之外,还要在POJO(或子POJO)中保存原始JSON的副本。例如,假设我有以下结构:
{
"test": 123,
"testStr": "foo",
"testSubModel": {
"testStr2": "foobar",
"testFloat2": 1.2
}
}
现在我有一套简单的两个POJO:
package test.model;
public class TestModel {
private int test;
private String testStr;
private TestSubModel testSubModel;
public int getTest() {
return test;
}
public String getTestStr() {
return testStr;
}
public TestSubModel getTestSubModel() {
return testSubModel;
}
}
package test.model;
public class TestSubModel {
private String testStr2;
private float testFloat2;
private String rawJson; // i want this to contain something like { "testStr2": "foobar", "testFloat2": 1.2 }
public String getTestStr2() {
return testStr2;
}
public float getTestFloat2() {
return testFloat2;
}
}
除了正确设置pojo字段之外,是否还可以使用类的完整JSON设置TestSubModel
中的rawJson
?
虽然我可以用自定义方法重新创建它,但我没有映射的任何额外JSON字段都会丢失,我想保留这些字段以用于异常日志记录(即,我需要上游系统发送的原始JSON,而不是可能丢失通常不存储在POJO中的字段的res构造的JSON)。
我希望有一种方法可以通过注释(但不要认为它在那里)或自定义后反序列化钩子(这样Jackson就可以做它通常的事情来映射对象,而不需要我自己为每个适用的类编写代码)。我尝试了一些与委托解析器
,但JsonParser是不可重复的,因为当我读到它一次不能重用调用对象反序列化对象=super.deserialize(p, ctxt);
除了得到树和转换为字符串。
我决定尝试一下,尽管结果比我想象的要复杂。使用此解决方案,只需将rawJsonMoules
注册为ObjectMapper,然后将@RawJson
应用到目标字段。
代码肯定也可以优化一点(反序列化器中的反射肯定是次优的)。如果你有任何问题,请告诉我。
输出:TestModel{test=123,testStr='foo',testSubModel=testSubModel{testStr2='foobar',testFloat2=1.2,rawJson='{“testStr2”:“foobar”,“testFloat2”:1.2}}
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
import com.fasterxml.jackson.databind.deser.ResolvableDeserializer;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
public class SO67140419 {
public static void main(String[] args) throws JsonProcessingException {
String json = """
{
"test": 123,
"testStr": "foo",
"testSubModel": {
"testStr2": "foobar",
"testFloat2": 1.2
}
}""";
var rawJsonModule = new SimpleModule();
// Credits to schummar for this technique; take the default deserializer and
// pass it to RawJsonDeserializer, which intercepts all deserialization
// https://stackoverflow.com/a/18405958/5378187
rawJsonModule.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
return new RawJsonDeserializer(beanDesc, deserializer);
}
});
var mapper = new ObjectMapper();
mapper.registerModule(rawJsonModule);
var model = mapper.readValue(json, TestModel.class);
System.out.println(model);
}
}
@JsonIgnore
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface RawJson {}
class RawJsonDeserializer extends StdDeserializer<Object> implements ResolvableDeserializer {
/**
* The default deserializer
*/
private final JsonDeserializer<?> deser;
private final BeanDescription desc;
public RawJsonDeserializer(BeanDescription desc, JsonDeserializer<?> deser) {
super((JavaType) null);
this.deser = deser;
this.desc = desc;
}
@Override
public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
// Read p into a json node in case we need it later for an @RawJson field
JsonNode node = p.getCodec().readTree(p);
p = p.getCodec().treeAsTokens(node); // Refresh p
if (p.getCurrentToken() == null) {
p.nextToken();
}
// Deserialize object using the default deserialization
Object obj = deser.deserialize(p, ctxt);
// Check for RawJson annotated fields
for (Field f : desc.getBeanClass().getDeclaredFields()) {
if (f.getDeclaredAnnotation(RawJson.class) == null) {
continue;
} else if (f.getType() != String.class) {
throw new IllegalStateException("@RawJson annotation applied to non-string field: " + f);
}
// Set the field to the json we stored earlier
try {
f.setAccessible(true);
f.set(obj, node.toString());
} catch (IllegalAccessException e) {
throw new IOException(e);
}
}
return obj;
}
@Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
// Not sure why we need this but ok
if (deser instanceof ResolvableDeserializer rd) {
rd.resolve(ctxt);
}
}
}
class TestModel {
private int test;
private String testStr;
private TestSubModel testSubModel;
public int getTest() {
return test;
}
public String getTestStr() {
return testStr;
}
public TestSubModel getTestSubModel() {
return testSubModel;
}
@Override
public String toString() {
return "TestModel{" +
"test=" + test +
", testStr='" + testStr + '\'' +
", testSubModel=" + testSubModel +
'}';
}
}
class TestSubModel {
private String testStr2;
private float testFloat2;
@RawJson
private String rawJson; // i want this to contain something like { "testStr2": "foobar", "testFloat2": 1.2 }
public String getTestStr2() {
return testStr2;
}
public float getTestFloat2() {
return testFloat2;
}
@Override
public String toString() {
return "TestSubModel{" +
"testStr2='" + testStr2 + '\'' +
", testFloat2=" + testFloat2 +
", rawJson='" + rawJson + '\'' +
'}';
}
}
问题内容: 我需要从Java pojo创建这样的Json有效负载: 所以我创建了一个Java pojo像这样: 我喜欢Label类中的“ add”属性是动态的,因此它也可以采用“ remove”,“ set”之类的值。除了为每个人创建另一个POJO之外,还有其他方法吗? 问题答案: 您可以使用JsonAnyGetter批注来创建动态对。下面的示例显示了如何为同一类生成3个不同的键: 上面的代码打印
问题内容: 我正在将Jersey用于REST WS,并且得到的响应为JSON。 我想将此响应转换为POJO。怎么做 ? 问题答案: 要在Java和JSON之间进行转换,有很多可供选择的API 。 您可以“手动”遍历JSON组件并提取值以填充Java对象,或者可以使用JSON到Java的绑定API来解决许多低级映射问题。
我有下面的JSON,我想解析到下面的bean类。 豆类 1 Bean类2 在这里,我无法使用下面的代码解析这些JavaPOJO。 jsonObjMapper.readValue(jsonString,DistributedCookieBean.class); 堆栈跟踪: org . code Haus . Jackson . map . jsonmappingexception:无法从START_
假设我有一个具有公共字段 和 的类 。假设我有另一个 pojo 类 ,但它使用 setter 和 getter,所以它有 setX() 和 setY()。 我想使用一些自动方法从实例复制到并返回。 至少使用默认设置,推土机的 未正确复制字段。 那么,是否有一个简单的配置更改可以让我使用Dozer或其他库来完成上述操作?
我正在尝试将JSON转换为POJO类。这个JSON是我从第三方REST API调用得到的,我想把它转换成POJO类。为此,我使用jackson databind jar,下面是我代码的一部分。 这里现在不是POJO类,我声明了Object类型的ModelObjcet变量,我的问题是我们是否需要在将JSON转换为POJO之前创建带有必填字段和getter setter方法的POJO类? 如果是,那么
有人能帮助我,我如何反序列化下面的JSON,我不能改变?我正在使用Jackson进行序列化。 列可以具有未知数量的标题及其值,例如,“Header1”用于行数组中。 到目前为止,我有以下结构: 问题是当我反序列化成QueryResult时映射是空的;我了解TypeReference,但不知道如何指定TypeReference 编辑: 我的对象映射器代码如下: queryResultString的内