I am very new to Json and my goal to create the Json output below from Java bean. How should I structure my Java object? Should I have MyResult class and User and Result as subclasses? What Json library can I use for this?
“MyResult” {
“AccountID”: “12345”,
"User" {
"Name": "blah blah",
"Email": “blah#blah.com”,
},
"Result" {
"Course": “blah”,
"Score": “10.0”
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
How should I structure my Java object?
Below is what your object model could look like. MOXy's JSON binding leverages JAXB annotations for mapping the domain model to JSON, so I have included those as well. JAXB implementations have default rules for mapping field/property names, but since your document differs from the default each field had to be annotated.
MyResult
package forum11001458;
import javax.xml.bind.annotation.*;
#XmlRootElement(name="MyResult")
public class MyResult {
#XmlElement(name="AccountID")
private String accountID;
#XmlElement(name="User")
private User user;
#XmlElement(name="Result")
private Result result;
}
User
package forum11001458;
import javax.xml.bind.annotation.XmlElement;
public class User {
#XmlElement(name="Name")
private String name;
#XmlElement(name="Email")
private String email;
}
Result
package forum11001458;
import javax.xml.bind.annotation.XmlElement;
public class Result {
#XmlElement(name="Course")
private String course;
#XmlElement(name="Score")
private String score;
}
What Json library can I use for this?
Below is how you can use MOXy to do the JSON binding:
jaxb.properties
To use MOXy as your JAXB provider you need to include a file called jaxb.properties with the following entry in the same package as your domain model:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
Note how MOXy's JSON binding does not require any compile time dependencies. All the necessary APIs are available in Java SE 6. You can add the necessary supporting APIs if you are using Java SE 5.
package forum11001458;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyResult.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty("eclipselink.media-type", "application/json");
File json = new File("src/forum11001458/input.json");
Object myResult = unmarshaller.unmarshal(json);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty("eclipselink.media-type", "application/json");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(myResult, System.out);
}
}
input.json/Output
{
"MyResult" : {
"AccountID" : "12345",
"User" : {
"Name" : "blah blah",
"Email" : "blah#blah.com"
},
"Result" : {
"Course" : "blah",
"Score" : "10.0"
}
}
}
Googles GSON is a really nice json lib. This is from the previous link and it basically outlines some of its functionality.
jackson is also pretty fast and easy to use
Although closed, this SO post can help you understand the differences between Jackson and GSON. Which one is "best" depends on what is important for you.
EDIT: Specifically for Jackson, your example looks a lot like the example they give for what they call Full Data Binding, you can read it here. Btw, although the announced 5 minutes needed to read that document is maybe a bit short, it gives a complete overview of the different ways Jackson can be used. You'll also notice that the examples given do not use annotations.
Or GSON
Super easy (no getters/settres, no annotations or configurations needed).
class BagOfPrimitives {
private int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
}
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
==> json is {"value1":1,"value2":"abc"}
What Json library can I use for this? Jackson Library is used to serialize Java objects into JSON and deserialize JSON string into Java objects. Add the following dependencies to pom.xml.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.4</version>
</dependency>
This dependency will transitively add the following libraries to the classpath:
jackson-annotations-2.9.4.jar
jackson-core-2.9.4.jar
jackson-databind-2.9.4.jar
**Note: Please always go with the latest jars.
How should I structure my Java object? Please see the full working code.
**MainClass.java:**
import java.io.IOException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
public class MainClass {
public static void main(String[] args) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
Result result = new Result();
result.setCourse("blah");
result.setScore("10.0");
User user = new User();
user.setName("blah blah");
user.setEmail("blah#blah.com");
MyResult myResult = new MyResult();
myResult.setAccountID("12345");
myResult.setResult(result);
myResult.setUser(user);
MyPojo myPojo = new MyPojo();
myPojo.setMyResult(myResult);
String jsonStr = mapper.writeValueAsString(myPojo);
System.out.println(jsonStr);
} }
**MyPojo.java:-**
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonPropertyOrder({ "AccountID", "User", "Result" })
public class MyPojo {
private MyResult MyResult;
public MyResult getMyResult() {
return MyResult;
}
#JsonProperty("MyResult")
public void setMyResult(MyResult MyResult) {
this.MyResult = MyResult;
} }
**MyResult.java:**
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonPropertyOrder({ "AccountID", "User", "Result" })
public class MyResult {
private User User;
private Result Result;
private String AccountID;
public User getUser() {
return User;
}
#JsonProperty("User")
public void setUser(User User) {
this.User = User;
}
public Result getResult() {
return Result;
}
#JsonProperty("Result")
public void setResult(Result Result) {
this.Result = Result;
}
public String getAccountID() {
return AccountID;
}
#JsonProperty("AccountID")
public void setAccountID(String AccountID) {
this.AccountID = AccountID;
} }
**Result.java:**
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonPropertyOrder({ "Course", "Score" })
public class Result {
private String Course;
private String Score;
public String getCourse() {
return Course;
}
#JsonProperty("Course")
public void setCourse(String Course) {
this.Course = Course;
}
public String getScore() {
return Score;
}
#JsonProperty("Score")
public void setScore(String Score) {
this.Score = Score;
} }
**User.java:**
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonPropertyOrder({ "Name", "Email" })
public class User {
private String Name;
private String Email;
public String getName() {
return Name;
}
#JsonProperty("Name")
public void setName(String Name) {
this.Name = Name;
}
public String getEmail() {
return Email;
}
#JsonProperty("Email")
public void setEmail(String Email) {
this.Email = Email;
}
#Override
public String toString() {
return "ClassPojo [Name = " + Name + ", Email = " + Email + "]";
} }
**Result:**
{
"MyResult" : {
"AccountID" : "12345",
"User" : {
"Name" : "blah blah",
"Email" : "blah#blah.com"
},
"Result" : {
"Course" : "blah",
"Score" : "10.0"
}
}
}
Note: Please note the use of Json Annotations like #JsonProperty("Email") to make json property names as same in the expected output & #JsonPropertyOrder({ "Name", "Email" } to maintain the sequence as in expected output. Refer: https://www.baeldung.com/jackson-annotations.
Related
I'm using Spring 2.6 and we make a GET request via
restTemplate.exchange(url, HttpMethod.GET, httpEntity, ResponseType.class).getBody();
The JSON response can be of two kinds:
1st:
public class ResponseType {
private String data;
}
2nd:
public class ResponseType {
private Subclass data;
}
public class Subclass {
private String classId;
private String detail;
}
In the first version I only get a reference link to the subclass resource.
If the URL contains a 'resolve' flag, than the reference link get expanded already in the first request.
The classId then also specifies what kind of class it is ( 'a.b.c' or 'x.y.z' )
No problem for JSON, but how can I get a mapping in Java?
When having more fields being dynamic (link or instance based on classId) a manual way would be difficult to implement if the combination could be 2 links and 3 objects.
It also could be that a object has the same feature - a filed with a link or a instance of a class specified by classId.
The JSON response would be this:
{
"data": "abskasdkjhkjsahfkajdf-linkToResource"
}
or this:
{
"data": {
"classId": "a.b.subclass",
"detail": "some data"
}
}
or this:
{
"data": {
"classId": "a.b.subclass",
"detail": "some data"
"data2": "some-link-id",
"data3": {
"detailB": "foo",
"detailC": "some-link-id"
}
}
}
Here I do have a possible solution for my problem. The logic to print the address only or the POJO relies soley in the CustomItemSerializer. So it is possible to use this without using duplicate code in controllers.
package com.allianz.clana.datamodel.http.epc.test;
import java.io.IOException;
import java.text.ParseException;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;
public class JacksonTester2 {
public static void main(String args[]) throws ParseException, JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
Item item2 = new Item("link");
Stuff stuff = new Stuff();
stuff.setItem(item2);
stuff.setFoo("foo");
String jsonStringStuff = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(stuff);
System.out.println(jsonStringStuff);
Item item3 = new Item("{ \"name\":\"ID3\", \"creationDate\":\"1984-12-30\", \"rollNo\": 1 }");
stuff.setItem(item3);
stuff.setFoo("bar");
jsonStringStuff = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(stuff);
System.out.println(jsonStringStuff);
}
}
class CustomItemSerializer extends StdSerializer<Item> {
private static final long serialVersionUID = 1L;
public CustomItemSerializer() {
this(null);
}
public CustomItemSerializer(Class<Item> t) {
super(t);
}
#Override
public void serialize(Item item, JsonGenerator generator, SerializerProvider arg2) throws IOException {
if (item != null) {
if (item.getItem() != null) {
System.out.println("ItemA POJO data");
generator.writePOJO(item.getItem());
} else {
System.out.println("raw data with link");
generator.writeString(item.getRawdata());
}
}
}
}
#Data
class Stuff {
Item item;
String foo;
}
#JsonSerialize(using = CustomItemSerializer.class)
#Data
#NoArgsConstructor
class Item {
private String rawdata;
#JsonIgnore
private ItemA item;
public Item(String rawdata) {
this.rawdata = rawdata;
if (rawdata.contains("{")) {
try {
this.item = new ObjectMapper().readerFor(ItemA.class).readValue(rawdata);
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
}
#Data
#NoArgsConstructor
class ItemA{
private String name;
private int rollNo;
private String creationDate;
public ItemA(String name, int rollNo, String dob) {
this.name = name;
this.rollNo = rollNo;
this.creationDate = dob;
}
}
The output looks like this:
raw data with link
{
"item" : "link",
"foo" : "foo"
}
ItemA POJO data
{
"item" : {
"name" : "ID3",
"rollNo" : 1,
"creationDate" : "1984-12-30"
},
"foo" : "bar"
}
The CustomItemSerializer decides if the link is printed or the POJO.
This question already has answers here:
What is use of the annotation #JsonIgnore?
(3 answers)
Closed 5 months ago.
I have a class like
public class MyPojo {
String name,
String age
String sub
}
And map like
map("name":"john","age":21)
Using Jacksons ObjectMapper, I get a string like
{
"name": "john",
"age": "21",
"sub": null
}
but instead I want to exclude the sub:
{
"name": "john",
"age": "21"
}
How can I do that and tell Jackson to skip sub?
P.S. Please keep in mind that I want to have ability to exclude age and include sub without changing the POJO class, so #JsonIgnore doesn't quite fit.
You can use java.util.Optional in your POJO class. You can convert Map to POJO and after that serialise it ignoring null-s. Optional allows to distinguish map.put("property", null) from not setting property at all. See below example:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
public class DateApp {
private final static JsonMapper JSON_MAPPER = JsonMapper.builder()
.enable(SerializationFeature.INDENT_OUTPUT)
.addModule(new Jdk8Module())
.build();
public static void main(String[] args) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("name", "John");
map.put("age", 21);
MyPojo pojo = JSON_MAPPER.convertValue(map, MyPojo.class);
System.out.println(pojo);
System.out.println("JSON:");
JSON_MAPPER.writeValue(System.out, pojo);
}
}
#Data
#NoArgsConstructor
#AllArgsConstructor
#JsonInclude(JsonInclude.Include.NON_NULL)
class MyPojo {
private Optional<String> name;
private Optional<String> age;
private Optional<String> sub;
}
Above code prints:
MyPojo(name=Optional[John], age=Optional[21], sub=null)
JSON:
{
"name" : "John",
"age" : "21"
}
You can try this approach in order to avoid the null attributes in the final json.
I have used ObjectMapper object and set the below property to avoid null attributes in the json.
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
Code as follows:
MyPojo.java
public class MyPojo {
private String name;
private String age;
private String sub;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getSub() {
return sub;
}
public void setSub(String sub) {
this.sub = sub;
}
#Override
public String toString() {
return "MyPojo{" +
"name=" + name +
", age=" + age +
", sub=" + sub +
'}';
}
}
Test.java
public class Test {
public static void main(String[] args) throws JsonProcessingException {
Map<String,String> inputMap = new HashMap<>();
inputMap.put("age","21");
inputMap.put("name","John");
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MyPojo p = mapper.convertValue(inputMap,MyPojo.class);
System.out.println(p);
System.out.println(mapper.writeValueAsString(p));
}
}
Output:
MyPojo{name=John, age=21, sub=null}
{"name":"John","age":"21"}
You can create your custom serializer.
Just include your map in the serializer code
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
#JsonSerialize(using = MyPojoSerializer.class)
public class MyPojo {
String name;
String age;
String sub;
}
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class MyPojoSerializer extends JsonSerializer<MyPojo> {
#Override
public void serialize(MyPojo myPojo, JsonGenerator jGen, SerializerProvider serializerProvider) throws IOException {
jGen.writeStartObject();
// Map map = ....
for (final Field field : myPojo.getClass().getDeclaredFields()) {
ReflectionUtils.makeAccessible(field);
final String fieldName = field.getName();
final Object fieldValue = ReflectionUtils.getField(field, myPojo);
if (map.containsKey(fieldName)) {
jGen.writeFieldName(fieldName);
jGen.writeObject(fieldValue);
}
}
jGen.writeEndObject();
}
}
I am try to model an Api response using Jackson. The id will be the same type in all but the body will be different types.
An example response would be:
{
"responses": [
{
"id": "jobTitle",
"body": {
"jobTitle": "Software Engineer"
}
},
{
"id": "thumbnailPhoto",
"body": "base 64 bit string"
}
]
}
I have the following implementation. Is this the correct approach? If the type for body returns as a string, would the JobTitle be ignored/ null?
#JsonIgnoreProperties(ignoreUnknown = true)
public class Response
{
#JsonProperty("id")
private String id;
#JsonProperty("body")
private String photo;
#JsonProperty("body")
private JobTitle jobTitle;
// getters and setters
}
I'm no expert in this area, but I would like to share my answer here.
I don't know why you design the JSON string as an array of responses for your original question. I would suggest a better design to be a single instance of "Response" object as below:
{
"id":"response id",
"jobTitle":"title",
"img":"img b64 string"
}
Just leave the field null if not exists.
But if you insist on using the origin design, below code below coding can be achieved, but the JSON string need small changes to add "type" info Tutorial from Baeldung.
[ {
"id" : "1",
"body" : {
"type" : "jobTitle",
"jobTitle" : "job title"
}
}, {
"id" : "2",
"body" : {
"type" : "img",
"data" : "xxxxx"
}
} ]
Java coding as below:
package org.example.test4;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import java.util.ArrayList;
public class TestApp {
public static class Response<X extends Body> {
private String id;
private X body;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public X getBody() {
return body;
}
public void setBody(X body) {
this.body = body;
}
}
#JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
#JsonSubTypes({
#JsonSubTypes.Type(value = JobTitle.class, name = "jobTitle"),
#JsonSubTypes.Type(value = IMG.class, name = "img")
})
public static abstract class Body{}
public static class JobTitle extends Body{
private String jobTitle;
public String getJobTitle() {
return jobTitle;
}
public void setJobTitle(String jobTitle) {
this.jobTitle = jobTitle;
}
}
public static class IMG extends Body{
private String data;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper om = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);;
JobTitle jt = new JobTitle();
jt.setJobTitle("job title");
System.out.println(om.writeValueAsString(jt));
IMG img = new IMG();
img.setData("xxxxx");
System.out.println(om.writeValueAsString(img));
ArrayList<Response<?>> rs = new ArrayList<Response<?>>();
Response<JobTitle> r1 = new Response<JobTitle>();
r1.setId("1");
r1.setBody(jt);
rs.add(r1);
Response<IMG> r2 = new Response<IMG>();
r2.setId("2");
r2.setBody(img);
rs.add(r2);
System.out.println(om.writeValueAsString(rs));
}
}
I want to generate Java Classes using a given JSON schema
Using the WikiMedia API, I receive the page info from a search
JSON schema:
(The small part that gives me problems)
"pages": {
"352214": {
"pageid": 352214,
"ns": 0,
"title": "Montellano",
"extract": "Montellano es un municipio español..."
}
}
As you can see the field 352214 is unique to this search which gives a problem using the POJO.
I'm using jsonschema2pojo with Jackson2 as Annotation Style
POJO
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"pageid",
"ns",
"title",
"extract"
})
public class _352214 {
#JsonProperty("pageid")
private Integer pageid;
#JsonProperty("ns")
private Integer ns;
#JsonProperty("title")
private String title;
#JsonProperty("extract")
private String extract;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
#JsonProperty("pageid")
public Integer getPageid() {
return pageid;
}
#JsonProperty("pageid")
public void setPageid(Integer pageid) {
this.pageid = pageid;
}
#JsonProperty("ns")
public Integer getNs() {
return ns;
}
#JsonProperty("ns")
public void setNs(Integer ns) {
this.ns = ns;
}
#JsonProperty("title")
public String getTitle() {
return title;
}
#JsonProperty("title")
public void setTitle(String title) {
this.title = title;
}
#JsonProperty("extract")
public String getExtract() {
return extract;
}
#JsonProperty("extract")
public void setExtract(String extract) {
this.extract = extract;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
_352214 class will suit only for the wiki search with the same field name, whenever I make another search and this field changes, it crashes. How do I solve this?
There is no standard way to parse situations like this(situations when you don't know field name). As an option you can manually parse your file using Jackson:
public void parseWikiResponse(String wikiResponse) {
JsonFactory jsonFactory = new JsonFactory();
ObjectMapper mapper = new ObjectMapper(jsonFactory);
JsonNode jsonNodes = mapper.readTree(wikiResponse);
Iterator<Map.Entry<String,JsonNode>> fieldsIterator = jsonNodes.fields();
while (fieldsIterator.hasNext()) {
Map.Entry<String,JsonNode> field = fieldsIterator.next();
/* Here you can find your field with unknown name using regExp eg */
field.getKey();
}
}
If you want only for parsing this approach should solve the problem.
There is a similar question on this topic:
Parsing JSON in Java without knowing JSON format
Hope something helped (:
I have the following JSON which I'm trying to deserialize using the Jackson API
"attachments": {
"file1": {
"content": "",
"name": "sample.json",
"type": "application/json"
},
"file2": {
"content": ""
"name": "myspreadsheet.xlsx",
"type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
}
},
I basically need an Attachment class which has a list of AttachmentFile objects which would look like this:
public static AttachmentFile {
String content;
String name;
String type;
}
How can I achieve this using a custom deserializer?
Thanks!
I use jackson 1.9.12 and there are no problems serialize and deserialize HashMap.
Attachments:
import java.util.Map;
public class Attachments
{
//#JsonDeserialize(as=HashMap.class) // use this if you want a HashMap
public Map<String, AttachmentFile> attachments;
public Attachments() {
}
public Attachments(
final Map<String, AttachmentFile> attachments
) {
this.attachments = attachments;
}
}
AttachmentFile:
public class AttachmentFile
{
public String content;
public String name;
public String type;
public AttachmentFile() {
}
public AttachmentFile(
final String content,
final String name,
final String type
) {
this.content = content;
this.name = name;
this.type = type;
}
}
Test:
import java.util.HashMap;
import java.util.Map;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.junit.Assert;
import org.junit.Test;
public class AttachmentsTest
{
#Test
public void test()
{
try {
final Map<String, AttachmentFile> attachments = new HashMap<String, AttachmentFile>();
attachments.put(
"file1",
new AttachmentFile(
"",
"sample.json",
"application/json"
)
);
attachments.put(
"file2",
new AttachmentFile(
"",
"myspreadsheet.xlsx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
);
final Attachments inputData = new Attachments();
inputData.attachments = attachments;
final ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
final String jsonString = jsonMapper.writeValueAsString(inputData);
//System.out.println(jsonString);
final Attachments outputData = jsonMapper.readValue(jsonString, inputData.getClass());
Assert.assertNotNull(outputData);
Assert.assertEquals(inputData.attachments.size(), outputData.attachments.size());
Assert.assertEquals(inputData.attachments.get("file1").name, outputData.attachments.get("file1").name);
Assert.assertEquals(inputData.attachments.get("file2").name, outputData.attachments.get("file2").name);
} catch (final Exception e) {
Assert.fail(e.getMessage());
}
}
}
You do not need a custom deserializer.
Using jacksons #JsonAnySetter annotation, you can write a method in your attachment class that looks like this
class Attachment
{
ArrayList files = new ArrayList();
#JsonAnySetter
public void setFile(String name, Object value)
{
files.add(value);
}
}
You may have to tweak that code (using more annotations), to make sure that value is deserialized as AttachmentFile. But I think you get the basic idea.