使用Jackson反序列化器读取子JSON对象。

huangapple go评论79阅读模式
英文:

Use Jackson deserializer to read child JSON object

问题

I have a Spring Boot application with Jackson dependency, and a Service with this code:

Dto dto = new ObjectMapper().readValue(jsonString, Dto.class);

I have a JSON similar to this one:

{
	"meta": {
	...
	},
	"results": [
		{
			"id": {"raw": "1"},
			"name": {"raw": "Hello World"}
			"number": {"raw": 7.5}
		}
	]
}

And I have a Java class like this one:

public class Dto {
    private AnotherDto meta;
    private List<ResultDto> results;
    // getters/setters
}
public class ResultDto {
    @JsonProperty("id")
    private Wrapper<String> id;

    // More fields and getters/setters
}

Then, I have a generic Wrapper class like this one (idea from Baeldung: https://www.baeldung.com/jackson-deserialization ):

@JsonDeserialize(using = WrapperDeserializer.class)
public class Wrapper<T> {
    T value;
    // getters/setters
}

Lastly, I have the next deserializer:

public class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {
    private JavaType type;

    @Override
    public Wrapper<?> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        Wrapper<?> wrapper = new Wrapper<>();
        wrapper.setValue(deserializationContext.readValue(jsonParser, type));
        return wrapper;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        this.type = beanProperty.getType().containedType(0);
        return this;
    }
}

The main doubt is, how I can access to jsonParser object in order to get the child JSON information? In this case, I would like to access {"raw": "1"}, so I could get the child into "raw" key and get the proper value, so ID "1" would be saved in final Java object.

I wouldn't want to make deserializationContext.readValue(jsonParser, type) as in this example, because it would throw this error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
 at [Source: 

Because {"raw": "1"} is not a valid String. I would want to have only the "1" value.

英文:

I have a Spring Boot application with Jackson dependency, and a Service with this code:

Dto dto = new ObjectMapper().readValue(jsonString, Dto.class);

I have a JSON similar to this one:

{
	&quot;meta&quot;: {
	...
	},
	&quot;results&quot;: [
		{
			&quot;id&quot;: {&quot;raw&quot;: &quot;1&quot;},
			&quot;name&quot;: {&quot;raw&quot;: &quot;Hello World&quot;}
			&quot;number&quot;: {&quot;raw&quot;: 7.5}
		}
	]
}

And I have a Java class like this one:

public class Dto {
    private AnotherDto meta;
    private List&lt;ResultDto&gt; results;
    // getters/setters
}
public class ResultDto {
    @JsonProperty(&quot;id&quot;)
    private Wrapper&lt;String&gt; id;

    // More fields and getters/setters
}

Then, I have a generic Wrapper class like this one (idea from Baeldung: https://www.baeldung.com/jackson-deserialization ):

@JsonDeserialize(using = WrapperDeserializer.class)
public class Wrapper&lt;T&gt; {
    T value;
    // getters/setters
}

Lastly, I have the next deserializer:

public class WrapperDeserializer extends JsonDeserializer&lt;Wrapper&lt;?&gt;&gt; implements ContextualDeserializer {
    private JavaType type;

    @Override
    public Wrapper&lt;?&gt; deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JacksonException {
        Wrapper&lt;?&gt; wrapper = new Wrapper&lt;&gt;();
        wrapper.setValue(deserializationContext.readValue(jsonParser, type));
        return wrapper;
    }

    @Override
    public JsonDeserializer&lt;?&gt; createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        this.type = beanProperty.getType().containedType(0);
        return this;
    }
}

The main doubt is, how I can access to jsonParser object in order to get the child JSON information? In this case, I would like to access {&quot;raw&quot;: &quot;1&quot;}, so I could get the child into raw key and get the proper value, so ID "1" would be saved in final Java object.

I wouldn't want to make deserializationContext.readValue(jsonParser, type) as in this example, because it would throw this error:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type `java.lang.String` from Object value (token `JsonToken.START_OBJECT`)
 at [Source: 

Because {&quot;raw&quot;: &quot;1&quot;} is not a valid String. I would want to have only the "1" value.

答案1

得分: 1

你已经非常接近了。主要问题是你在字段名称 value 处使用了,实际应该是 raw。另外,WrapperDeserializer 不是必要的。

所有代码都按你的要求,除了以下部分:

Wrapper.java

public class Wrapper<T> {

    T raw;

    // getters, setters & toString()
}

main

public static void main(String[] args) throws JsonMappingException, JsonProcessingException {

    ObjectMapper objectMapper = new ObjectMapper();

    String json = "{
        "results": [
            {
                "id": {"raw": "1"},
                "name": {"raw": "Hello World"},
                "number": {"raw": 7.5}
            }
        ]
    }";

    Dto readValue = objectMapper.readValue(json, Dto.class);

    System.out.println(readValue);
}

输出

Dto [results=[ResultDto [id=Wrapper [raw=1], name=Wrapper [raw=Hello World], number=Wrapper [raw=7.5]]]]
英文:

You are really close. The main issue is that you used the field name value where it should be raw. Also, the WrapperDeserializer is not required.

All the code is as you have it besides the following:

Wrapper.java

public class Wrapper&lt;T&gt; {

	T raw;
  
    // getters, setters &amp; toString()
}

main

	public static void main(String[] args) throws JsonMappingException, JsonProcessingException {
	
		ObjectMapper objectMapper = new ObjectMapper();
		
		String json = &quot;{\r\n&quot; + 
				&quot;    \&quot;results\&quot;: [\r\n&quot; + 
				&quot;        {\r\n&quot; + 
				&quot;            \&quot;id\&quot;: {\&quot;raw\&quot;: \&quot;1\&quot;},\r\n&quot; + 
				&quot;            \&quot;name\&quot;: {\&quot;raw\&quot;: \&quot;Hello World\&quot;},\r\n&quot; + 
				&quot;            \&quot;number\&quot;: {\&quot;raw\&quot;: 7.5}\r\n&quot; + 
				&quot;        }\r\n&quot; + 
				&quot;    ]\r\n&quot; + 
				&quot;}&quot;;
		
		Dto readValue = objectMapper.readValue(json, Dto.class);
		
		System.out.println(readValue);
}

Output

Dto [results=[ResultDto [id=Wrapper [raw=1], name=Wrapper [raw=Hello World], number=Wrapper [raw=7]]]]

huangapple
  • 本文由 发表于 2023年4月10日 22:17:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/75977888.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定