How to do a partial deserialization with Jackson

有些话、适合烂在心里 提交于 2021-01-03 07:26:54

问题


In my REST microservice, I request an object from another service that returns me a huge nested JSON, for example:

{
  "address": "19th Street",
  "contact_info": {
     "phones": {
        "home": {
           "first": {
             "another_nested": 1234
           }
        }
     } 
  } 
}

What I need to fetch this data from another service, perform a change only in the first field, and then send it via HTTP. What I'm trying to avoid is to deserialize everything on my side and having to maintain the classes here. Is there a way to get the raw value of contact_info and just have the representation of address with Jackson? Something like this:

public class FullAddress {
  String address;
  RawValue contactInfo;
}

回答1:


The simplest approach would be using JsonNode:

@Data
public class FullAddress {
    private String address;
    private JsonNode contactInfo;
}

Or either Map<String, Object>:

@Data
public class FullAddress {
    private String address;
    private Map<String, Object> contactInfo;
}

It works for both serialization and deserialization.


If you, however, wants to store the raw JSON, then you could define a custom deserializer:

public class RawJsonDeserializer extends JsonDeserializer<String> {

    @Override
    public String deserialize(JsonParser jp, DeserializationContext ctxt)
           throws IOException, JsonProcessingException {

        ObjectMapper mapper = (ObjectMapper) jp.getCodec();
        JsonNode node = mapper.readTree(jp);
        return mapper.writeValueAsString(node);
    }
}

And then use use it as follows:

@Data
public class FullAddress {

    private String address;

    @JsonDeserialize(using = RawJsonDeserializer.class)
    private String contactInfo;
}

For serializing back, however, you can annotate the contactInfo field with @JsonRawValue.




回答2:


You can use the JsonIgnoreProperties on class docs so it will ignore all other properties that not present in class

// To ignore any unknown properties in JSON input without exception:
@JsonIgnoreProperties(ignoreUnknown=true)



回答3:


There is also ObjectMapper.readerForUpdating which basically allows you to update in place a JSON object. There's not much documentation for it though:

https://fasterxml.github.io/jackson-databind/javadoc/2.9/com/fasterxml/jackson/databind/ObjectMapper.html#readerForUpdating-java.lang.Object-

Example here: https://www.logicbig.com/tutorials/misc/jackson/reader-for-updating.html

(Apologies for only a partial answer here - but it might be of use for someone)




回答4:


I recommend to always define model classes for your JSON string even if you need to map only a few fields from that JSON string. It's neater and in future anybody can easily add additional fields to model if it will be needed. Jackson supports partial mapping.

Complete working example in Kotlin:

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import org.junit.Test

class Test {

    data class ModelInner(
            var attributeB1: String? = null,
    )

    data class ModelRoot(
            var attributeA2: List<ModelInner>? = null,
    )

    @Test
    fun test0() {
        val json = """
        {
            "attributeA0": "A0",
            "attributeA1": "A1",
            "attributeA2": [
                {
                    "attributeB0": "B00",
                    "attributeB1": "B01"
                },
                {
                    "attributeB0": "B10",
                    "attributeB1": "B11"
                }
            ]
        }
        """

        val om = ObjectMapper()
        om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)

        val order = om.readValue(json, ModelRoot::class.java)

        print(order)
    }
}

Output:

ModelRoot(attributeA2=[ModelInner(attributeB1=B01), ModelInner(attributeB1=B11)])




回答5:


Another solution to this is to use @JsonAnyGetter @JsonAnySetter. See the write-up here: https://www.concretepage.com/jackson-api/jackson-jsonanygetter-and-jsonanysetter-example



来源:https://stackoverflow.com/questions/58102069/how-to-do-a-partial-deserialization-with-jackson

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!