I'm trying to deserialize an existing JSON document using Jackson, and was wondering if it was possible to perform the following translation without resorting to a stack of custom deserialization.
The input JSON looks like this:
{
"type": "foo",
"content": ["a", "b", {"some": "object", "goes": "here"}, 4]
}
The first 3 elements in content
don't change, and are always String, String, SomeDataStructure, Integer (optional)
And I would like to deserialize into something like this:
class Foo {
public static class FooContent {
String some;
String goes;
}
String aString;
String bString;
FooContent content;
Integer cInt;
}
Now I've already come across BeanAsArrayDeserializer, which sounds like it might be what I want, but I can't seem to find anything even remotely like a piece of example code to get me started.
So, any ideas?
You can always implement your custom deserializer. See below source code:
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
;
public class JacksonTest {
public static void main(String[] args) throws Exception {
String json = "{\"type\": \"foo\",\"content\": [\"a\", \"b\", {\"some\": \"object\", \"goes\": \"here\"}, 4]}";
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
mapper.configure(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS, true);
Root pojo = mapper.readValue(json, Root.class);
System.out.println(pojo);
}
}
class Root {
public String type;
@JsonDeserialize(using = FooDeserializer.class)
public Foo content;
@Override
public String toString() {
return content.toString();
}
}
class Foo {
public static class FooContent {
public String some;
public String goes;
@Override
public String toString() {
return "{" + some + ", " + goes + "}";
}
}
String aString;
String bString;
FooContent content;
Integer cInt;
@Override
public String toString() {
return "Foo [aString=" + aString + ", bString=" + bString + ", content=" + content
+ ", cInt=" + cInt + "]";
}
}
class FooDeserializer extends JsonDeserializer<Foo> {
@Override
public Foo deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException,
JsonProcessingException {
Foo f = new Foo();
int index = 0;
while (jp.nextToken() != JsonToken.END_ARRAY) {
JsonToken token = jp.getCurrentToken();
if (token.isStructStart()) {
f.content = jp.readValueAs(Foo.FooContent.class);
index++;
} else {
switch (index++) {
case 0:
f.aString = jp.getText();
break;
case 1:
f.bString = jp.getText();
break;
case 3:
f.cInt = Integer.parseInt(jp.getText());
break;
}
}
}
return f;
}
}
Above app prints:
Foo [aString=a, bString=b, content={object, here}, cInt=4]
The feature that allows to use the BeanAsArrayDeserializer
(internally) is @JsonFormat
. You can read some information about it in this blog post.
I also just learned about it recently, but I think a mapping that works for your case would look something like the following. You'd need a wrapper to hold the content
field though, which would then be of type Foo
.
@JsonFormat(shape = Shape.ARRAY)
@JsonPropertyOrder({ "aString", "bString", "content", "cInt" })
class Foo {
public static class FooContent {
String some;
String goes;
}
@JsonFormat(shape = Shape.STRING)
String aString;
@JsonFormat(shape = Shape.STRING)
String bString;
FooContent content;
@JsonFormat(shape = Shape.NUMBER)
Integer cInt;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.