Deserialize JSON in Jackson where key is a value - java

{
{
"1234": {
"name": "bob"
}
},
{
"5678": {
"name": "dan"
}
}
}
I have a class representing name (and other fields, I've just made it simple for this question). But the each element is key'd with the id of the person.
I've tried several things including:
class Name {
String Name;
//getter and setter
}
class NameId {
String id;
Name name;
//getter and setters
}
//json is the string containing of the above json
ArrayList<NameId> map = objectMapper.readValue(json, ArrayList.class);
for (Object m : map) {
LinkedHashMap<String, NameId> l = (LinkedHashMap)m;
Map<String, NameId> value = (Map<String, NameId>) l;
//System.out.println(l);
//System.out.println(value);
for (Object key : value.keySet()) {
System.out.println("key: " + key);
System.out.println("obj: " + value.get(key));
NameId nameId = (NameId)value.get(key);
}
}
The problem I have is it doesn't allow that cast to NameId. The error I get is:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to NameId
Any ideas on the best way to parse such a json string like this properly?

Your json is malformed. You need the square brackets around it otherwise it isn't considered a json array. If your json looks like (for example)
[
{
"1234" : {
"name" : "dan"
}
},
{
"5678" : {
"name" : "mike"
}
}
]
you can write a custom deserializer for the object mapper. See the working example below:
public static void main(String... args) throws Exception {
String testJson = "[{ \"1234\" : { \"name\" : \"dan\" } },{ \"5678\" : { \"name\" : \"mike\" } }]";
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(NameId.class, new MyDeserializer());
mapper.registerModule(module);
ArrayList<NameId> map = mapper.readValue(testJson.getBytes(), new TypeReference<List<NameId>>() {
});
for (NameId m : map) {
System.out.println(m.id);
System.out.println(m.name.name);
System.out.println("----");
}
}
#JsonDeserialize(contentUsing = MyDeserializer.class)
static class NameId {
String id;
Name name;
//getter and setters
}
static class Name {
String name;
//getter and setter
}
static class MyDeserializer extends JsonDeserializer<NameId> {
#Override
public NameId deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = p.getCodec().readTree(p);
Map.Entry<String, JsonNode> nodeData = node.fields().next();
String id = nodeData.getKey();
String name = nodeData.getValue().get("name").asText();
Name nameObj = new Name();
nameObj.name = name;
NameId nameIdObj = new NameId();
nameIdObj.name = nameObj;
nameIdObj.id = id;
return nameIdObj;
}
}

try this
Iterator<String> iterator1 =outerObject.keys();
while(iterator1.hasNext())
{
JsonObject innerObject=outerObject.getJsonObject(iterator1.next());
Iterator<String> iterator2=innerObject.keys();
while(iterator2.hasNext()){
String name=innerObject.getString(iterator2.next());
}
}

Your json is not valid. Maybe a little bit different:
{
"1234": {
"name": "bob"
},
"5678": {
"name": "dan"
}
}
And you could model something like:
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
And instead of attemping to use a list, use a map:
Map<Integer, Person> map = new ObjectMapper().readValue(json,
TypeFactory.defaultInstance()
.constructMapType(Map.class, Integer.class, Person.class));

no custom deserializer needed.
first, the json file as #klaimmore suggested (named test.json):
{
"1234": {
"name": "bob"
},
"5678": {
"name": "dan"
}
}
Secondly. here's the 2 separate class files:
#JsonDeserialize
public class Name {
String name;
public Name(String name) {
this.name = name;
}
/**
* #return the name
*/
public String getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(String name) {
this.name = name;
}
}
and
#JsonDeserialize
public class NameId {
Name name;
String id;
/**
* #return the id
*/
public String getId() {
return id;
}
/**
* #param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* #return the name
*/
public Name getName() {
return name;
}
/**
* #param name the name to set
*/
public void setName(Name name) {
this.name = name;
}
}
and the extra simple json parser class.
public class JsonParser {
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
String jsonString = new String(Files.readAllBytes(Paths.get("test.json")));
ObjectMapper mapper = new ObjectMapper();
Map<String,NameId> nameIdList = mapper.readValue(jsonString, new TypeReference<Map<String,NameId>>(){});
nameIdList.entrySet().forEach(nameIdEntry -> System.out.println("name id is: " + nameIdEntry.getKey() +
" and name is: " + nameIdEntry.getValue().getName().getName()));
}
}
also. this is pretty much a dupe of How to convert json string to list of java objects. you should read this.

Related

Convert POJO to POJO with custom converter using json configuration

We have two Pojo files.
Person {
String name;
int age;
String address;
String phoneNo;
boolean isMarried;
}
and
OtherPerson {
//mandatory fields are name and age
String name_other;
int age_other;
//other fields
Map<String, Object> otherFields;
}
and a json file which defines the mapping between the fields using name
mappingJson {
"name":"name_other",
"age":"age_other",
"address":"address_other",
"phoneNo":"phoneno_other",
"isMarried":"ismarried_other"
}
Please let me know the best approach to convert Person to OtherPerson. So that the mandatory fields map to name_other and age_other while the other fields should be added to the map(otherFields)
It may be
Person->Person(json)->OtherPerson
Or Person->OtherPerson.
EDIT:
"Use case: We have an API which used to accepts a POJO 'A' but now it needs to accept POJO 'B' as an input argument. This POJO needs to get converted into POJO 'A' which can then be used for persisting into the database. Also POJO 'B' is not under our control"
That's a perfect fit for Jackson Converter! :)
It could work like this:
class OtherPerson {
#JsonProperty("name")
public String name_other;
#JsonProperty("age")
public int age_other;
Map<String, Object> otherFields = new LinkedHashMap<>();;
#JsonAnySetter
public void add(String key, Object value) {
otherFields.put(key, value);
}
}
// ...
Person person = new Person();
person.name = "Avinash";
person.age = 25;
person.address = "Mumbai";
person.phoneNo = "910731";
person.isMarried = true; // :( sorry ladies!
// ...
ObjectMapper mapper = new ObjectMapper();
// If we cannot put #JsonAutoDetect on top of Person.class,
// we need to add handling of non-public fields
// since Person seems to neither have public fields nor setters
mapper.configOverride(Person.class)
.setVisibility(JsonAutoDetect.Value.defaultVisibility()
.withFieldVisibility(JsonAutoDetect.Visibility.NON_PRIVATE));
OtherPerson other = mapper.convertValue(person, OtherPerson.class);
VoilĂ !
I personally would do this without JSON. It's my understanding that some fields in the Map are optional while name and age are mandatory. In the case of the optional content, I would use the Ternary operator to create the person object. This allows you to add some default value if the optional field is not available.
Main
import java.util.HashMap;
import java.util.Map;
/**
*
* #author blj0011
*/
public class JavaApplication30 {
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
Map<String, Object> map1 = new HashMap();
map1.put("address", "123 Hello Street");
map1.put("phoneNo", "555-555-5555");
map1.put("isMarried", true);
OtherPerson otherPerson = new OtherPerson("John Doe", 22, map1);
Map<String, Object> map2 = new HashMap();
map2.put("address", "4456 Bye Road");
map2.put("isMarried", false);
OtherPerson otherPerson2 = new OtherPerson("Jane Doe", 21, map2);
Person person1 = new Person(otherPerson.getName_other(), otherPerson.getAge_other(),
otherPerson.getOtherFields().containsKey("address") ? otherPerson.getOtherFields().get("address").toString(): "",
otherPerson.getOtherFields().containsKey("phoneNo") ? otherPerson.getOtherFields().get("phoneNo").toString(): "",
otherPerson.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson.getOtherFields().get("isMarried").toString()): false);
System.out.println(person1);
Person person2 = new Person(otherPerson2.getName_other(), otherPerson2.getAge_other(),
otherPerson2.getOtherFields().containsKey("address") ? otherPerson2.getOtherFields().get("address").toString(): "",
otherPerson2.getOtherFields().containsKey("phoneNo") ? otherPerson2.getOtherFields().get("phoneNo").toString(): "",
otherPerson2.getOtherFields().containsKey("isMarried") ? Boolean.valueOf(otherPerson2.getOtherFields().get("isMarried").toString()): false);
System.out.println(person2);
}
}
Person
/**
*
* #author blj0011
*/
public class Person {
private String name;
private int age;
private String address;
private String phoneNo;
private boolean isMarried;
public Person(String name, int age, String address, String phoneNo, boolean isMarried) {
this.name = name;
this.age = age;
this.address = address;
this.phoneNo = phoneNo;
this.isMarried = isMarried;
}
public boolean isIsMarried() {
return isMarried;
}
public void setIsMarried(boolean isMarried) {
this.isMarried = isMarried;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", age=" + age + ", address=" + address + ", phoneNo=" + phoneNo + ", isMarried=" + isMarried + '}';
}
}
OtherPerson
/**
*
* #author blj0011
*/
public class OtherPerson {
//mandatory fields are name and age
private String name_other;
private int age_other;
//other fields
private Map<String, Object> otherFields;
public OtherPerson(String name_other, int age_other, Map<String, Object> otherFields) {
this.name_other = name_other;
this.age_other = age_other;
this.otherFields = otherFields;
}
public Map<String, Object> getOtherFields() {
return otherFields;
}
public void setOtherFields(Map<String, Object> otherFields) {
this.otherFields = otherFields;
}
public String getName_other() {
return name_other;
}
public void setName_other(String name_other) {
this.name_other = name_other;
}
public int getAge_other() {
return age_other;
}
public void setAge_other(int age_other) {
this.age_other = age_other;
}
}
Output
Person{name=John Doe, age=22, address=123 Hello Street, phoneNo=555-555-5555, isMarried=true}
Person{name=Jane Doe, age=21, address=4456 Bye Road, phoneNo=, isMarried=false}
As you can see in the output OtherPerson2 did not have a phone number. Empty string was use as the default value.

Java objects to JSON without key

I'm getting to know json better. But I have some problems with that. I want to create JSON objects from Java classes.
I'm trying Java-objects convert to JSON with jackson.
What I want is that:
{
"id" : "005be2f0",
"attachments":
[
{"id":"Y98-8370"},
{"id":"Y98-8371"},
{"id":"Y98-8372"},
{"filename" : "DummyDoc", "filetype" : "pdf"}
]
}
But what I got with the following classes is that:
{
"id" : "005be2f0",
"attachments" : [ {
"id" :
[
{"id":"Y98-8370"},
{"id":"Y98-8371"},
{"id":"Y98-8372"},
],
"filename" : "DummyDoc",
"filetype" : "pdf"
} ]
}
And this are my classes:
public class Attachment {
#JsonPropertyOrder({ "id", "filename", "filetype" })
public class Attachment {
#JsonProperty("id")
private List<AttachmentID> id = new ArrayList<>();
#JsonProperty("filename")
private String filename;
#JsonProperty("filetype")
private String filetype;
public List<AttachmentID> getId() {
return id;
}
public void setId(List<AttachmentID> id) {
this.id = id;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getFiletype() {
return filetype;
}
public void setFiletype(String filetype) {
this.filetype = filetype;
}
}
I need this class for ID of the attachment.
public class AttachmentID {
#JsonProperty("id")
private String id;
public AttachmentID(String attachmentID) {
this.id = attachmentID;
}
public AttachmentID() {
// TODO Auto-generated constructor stub
}
#JsonProperty("id")
public String getAttachmentID() {
return id;
}
#JsonProperty("id")
public void setAttachmentID(String attachmentID) {
this.id = attachmentID;
}
}
And my RecordAttachment class.
#JsonPropertyOrder({ "id", "attachments" })
public class RecordAttachment {
#JsonProperty("id")
private String id;
#JsonProperty("attachments")
private List<Attachment> attachments = null;
#JsonProperty("id")
public String getId() {
return id;
}
#JsonProperty("id")
public void setId(String id) {
this.id = id;
}
#JsonProperty("attachments")
public List<Attachment> getAttachments() {
return attachments;
}
#JsonProperty("attachments")
public void setAttachments(List<Attachment> attachments) {
this.attachments = attachments;
}
}
is that possible?
Does this have to do with JsonNode, ObjectNode etc.?
I would be very happy if someone could help me.
I mean with key the IDs in array.
Solution 1 : Custom serializer
Details : You can tell jackson how to serialize your object. If you want to serialize it always in the same way, you can specify at the class level that it should always use this serializer. If you believe you will need other serializers, you should customize your objectMapper instead:
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Attachment.class, new AttachmentSerializer());
The attachment serializer:
public class AttachmentSerializer extends StdSerializer<Attachment> {
public AttachmentSerializer() {
this(null);
}
public AttachmentSerializer(Class<Attachment> t) {
super(t);
}
#Override
public void serialize(
Attachment attachment, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeArrayFieldStart("attachments");
for (AttachmentID attachmentID : attachment.getId()) {
jgen.writeStartObject();
jgen.writeStringField("id", attachmentID.getAttachmentID());
jgen.writeEndObject();
}
jgen.writeStartObject();
jgen.writeStringField("filename", attachment.getFilename());
jgen.writeStringField("filetype", attachment.getFiletype());
jgen.writeEndObject();
jgen.writeEndArray();
jgen.writeEndObject();
}
}
and add :
#JsonSerialize(using = AttachmentSerializer.class)
#JsonPropertyOrder({"id", "filename", "filetype"})
public class Attachment {
I've added custom serializer just on your Attachment class because it is the only one that needs special handling.
Solution 2: create a custom RecordAttachmentDTO with the target fields needed and serialize it instead of RecordAttachment.
public class RecordAttachmentDTO {
private String id;
private List<Map<String, String>> attachments = new ArrayList<>();
public RecordAttachmentDTO(RecordAttachment recordAttachment) {
this.id = recordAttachment.getId();
List<Attachment> attachments = recordAttachment.getAttachments();
attachments.forEach(attachment -> addAttachment(attachment));
}
private void addAttachment(Attachment attachment) {
attachment.getId().forEach(attachmentID -> attachments.add(Collections.singletonMap("id", attachmentID.getAttachmentID())));
Map<String, String> fileMap = new HashMap<>();
fileMap.put("filename", attachment.getFilename());
fileMap.put("fileType", attachment.getFiletype());
attachments.add(fileMap);
}
public List<Map<String, String>> getAttachments() {
return attachments;
}
public void setAttachments(List<Map<String, String>> attachments) {
this.attachments = attachments;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}
This solution will help you have multiple serializers if needed. This solution is basically a wrapper of your original object. Instead of serializing the original object, you are serializing a wrapper instead.
Solution 3: build JsonNode objects
public static String serializeRecordAttachment(RecordAttachment recordAttachment) throws JsonProcessingException {
ObjectMapper objectMapper = new ObjectMapper();
ObjectNode recordNode = objectMapper.createObjectNode();
recordNode.put("id", recordAttachment.getId());
List<Attachment> attachments = recordAttachment.getAttachments();
recordNode.set("attachments",
createAttachmentNode(objectMapper,attachments));
return objectMapper.writeValueAsString(recordNode.toString);
}
private static ArrayNode createAttachmentNode(ObjectMapper objectMapper, List<Attachment> attachments) {
ArrayNode attachmentsNode = objectMapper.createArrayNode();
attachments.forEach(attachment -> addAttachment(objectMapper, attachmentsNode, attachment);
return attachmentsNode;
}
private static void addAttachment(ObjectMapper objectMapper, ArrayNode attachmentsNode, Attachment attachment) {
attachment.getId().forEach(idField -> {
ObjectNode attchIdNode = objectMapper.createObjectNode();
attchIdNode.put("id", idField.getAttachmentID());
attachmentsNode.add(attchIdNode);
});
ObjectNode fileNode = objectMapper.createObjectNode();
fileNode.put("filename", attachment.getFilename());
fileNode.put("filetype", attachment.getFiletype());
attachmentsNode.add(fileNode);
}
This solution is similar with Solution 2, the advantage is that you don't need a wrapper object.

Parse JSON String using ObjectMapper java API

I have a JSON as below. The goal is to get the corresponding "ip","PRODUCTTYPE" and "ID" values.
{
"customerId": "dummy1",
"nameIdmap": {
"10.2.1.0": "{PRODUCTTYPE=null, ID=123}",
"10.2.1.3": "{PRODUCTTYPE=null, ID=456}",
"10.2.1.4": "{PRODUCTTYPE=null, ID=789}",
"10.2.1.5": "{PRODUCTTYPE=null, ID=193}"
}
}
I am using the ObjectMapper API to parse and fetch the values.
ObjectMapper om = new ObjectMapper();
JsonNode node = om.readTree(stringToBeParsed);
String customerID = node.get("customerId").asText();
System.out.println("The Customer ID is ::: "+customerID);
JsonNode nameIdmap = node.get("nameIdmap");
StreamSupport.stream(nameIdmap.spliterator(), false).forEach(
kv -> {
System.out.println(kv.asText().split(",")[0] +" ,
"+kv.asText().split(",")[1]);
});
But the issue is I, am unable to get the key which is the ip-address in this case. Tried different ways to achieve but could not get what i want.
I checked if the nameIdmap is an array nameIdmap.isArray() but it is false.
I also tried below but could not get the ip i.e the key
JsonNode nameIdmap = node.get("nameIdmap");
StreamSupport.stream(nameIdmap.spliterator(), false).collect(Collectors.toList())
.forEach(item -> {
System.out.println(item.asText());
});;
You can try Custom Deserializer as below
1. Create Item class
This is a POJO which stands for an ID and a map of String and IPItem
public class SOItem {
#Override
public String toString() {
return "SOItem [id=" + id + ", map=" + map + "]";
}
String id;
Map<String, SOIPItem> map = new HashMap();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, SOIPItem> getMap() {
return map;
}
public void setMap(Map<String, SOIPItem> map) {
this.map = map;
}
}
2. Create IPItem class
This is a POJO for an ID and ProductType
public class SOIPItem {
private String type;
private String id;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#Override
public String toString() {
return "SOIPItem [type=" + type + ", id=" + id + "]";
}
public SOIPItem(String type, String id) {
super();
this.type = type;
this.id = id;
}
}
3. Create a Custom Deserializer
import java.io.IOException;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.ObjectCodec;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
public class SOCustDeser extends StdDeserializer<SOItem> {
public SOCustDeser() {
this(null);
}
public SOCustDeser(Class<?> vc) {
super(vc);
}
/**
*
*/
private static final long serialVersionUID = -394222274225082713L;
#Override
public SOItem deserialize(JsonParser parser, DeserializationContext arg1)
throws IOException, JsonProcessingException {
SOItem soItem = new SOItem();
ObjectCodec codec = parser.getCodec();
JsonNode node = codec.readTree(parser);
soItem.setId(node.get("customerId").asText());
JsonNode idmap = node.get("nameIdmap");
Iterator<String> fieldNames = idmap.fieldNames();
while(fieldNames.hasNext()) {
String ip = fieldNames.next();
String textValue = idmap.get(ip).asText();
Pattern p = Pattern.compile("(.*?)=(.*?),(.*?)(\\d+)");
Matcher m = p.matcher(textValue);
if (m.find()) {
soItem.map.put(ip, new SOIPItem(m.group(2), m.group(4)));
}
}
return soItem;
}
}
4. Test class
import java.io.File;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
public class MicsTest {
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper();
SimpleModule sm = new SimpleModule();
sm.addDeserializer(SOItem.class, new SOCustDeser());
om.registerModule(sm);
SOItem item = om.readValue(new File("c:\\temp\\test.json"), SOItem.class);
System.out.println(item);
}
}
5. Output
SOItem [id=dummy1, map={10.2.1.0=SOIPItem [type=null, id=123], 10.2.1.3=SOIPItem [type=null, id=456], 10.2.1.5=SOIPItem [type=null, id=193], 10.2.1.4=SOIPItem [type=null, id=789]}]
You can get the field names by nameIdmap.getFieldNames as an iterator. You can then iterate over like that:
...
Iterator<String> fieldNames = idmap.getFieldNames();
while(fieldNames.hasNext()) {
String ip = fieldNames.next();
String textValue = idmap.get(ip).getTextValue()
System.out.println(ip + ":" + textValue);
}
If the nested information is also JSON you can then access it further via idmap.get(ip).get("ID"); if not then you still have the option to find it by regex like that:
Pattern p = Pattern.compile("ID=(\\d+)");
Matcher m = p.matcher(textValue);
if(m.find()) {
System.out.println(ip + ":" + m.group(1));
}
Best way to handle these scenarios is to create a matching pojo for your json. This way it gives you flexibility to play around with the data.
Create classes like these
public class Someclass {
private String customerId;
Map<String, String> nameIdmap;
public Map<String, String> getNameIdmap() {
return nameIdmap;
}
public void setNameIdmap(Map<String, String> nameIdmap) {
this.nameIdmap = nameIdmap;
}
public Someclass() {
}
public String getCustomerId() {
return customerId;
}
public void setCustomerId(String customerId) {
this.customerId = customerId;
}
}
And this code will translate your json to SomeClass class
String json = "<copy paste your json here>";
Someclass someclass = objectMapper.readValue(json, Someclass.class);
String s = someclass.getNameIdmap().get("10.2.1.0");
String[] splits = s.split(" ");
String productType = splits[0].split("=")[1];
String id = splits[1].split("=")[1];
System.out.println(productType + " " + id);

JSON to POJO with Integer as Array attribute key Name

I have the following json which has a product array with product_id as each array.Product ids are numbers. When I am looking online for the pojo classes I am getting Class names which starts with digits which is not allowed.
{
"_id:" : "1234AG567",
"products" : {
"1234":{
"product_name" : "xyz",
"product_type" : "abc"
},
"3456":{
"product_name" : "zzz",
"product_type" : "def"
}
}
}
Below are the Pojo classes I am getting
public class MyPojo
{
private Products products;
public Products getProducts ()
{
return products;
}
public void setProducts (Products products)
{
this.products = products;
}
#Override
public String toString()
{
return "ClassPojo [products = "+products+"]";
}
}
public class Products
{
private 1234 1234;
private 3456 3456;
public 1234 get1234 ()
{
return 1234;
}
public void set1234 (1234 1234)
{
this.1234 = 1234;
}
public 3456 get3456 ()
{
return 3456;
}
public void set3456 (3456 3456)
{
this.3456 = 3456;
}
#Override
public String toString()
{
return "ClassPojo [1234 = "+1234+", 3456 = "+3456+"]";
}
}
public class 3456
{
private String product_name;
private String product_type;
public String getProduct_name ()
{
return product_name;
}
public void setProduct_name (String product_name)
{
this.product_name = product_name;
}
public String getProduct_type ()
{
return product_type;
}
public void setProduct_type (String product_type)
{
this.product_type = product_type;
}
#Override
public String toString()
{
return "ClassPojo [product_name = "+product_name+", product_type = "+product_type+"]";
}
}
public class 1234
{
private String product_name;
private String product_type;
public String getProduct_name ()
{
return product_name;
}
public void setProduct_name (String product_name)
{
this.product_name = product_name;
}
public String getProduct_type ()
{
return product_type;
}
public void setProduct_type (String product_type)
{
this.product_type = product_type;
}
#Override
public String toString()
{
return "ClassPojo [product_name = "+product_name+", product_type = "+product_type+"]";
}
}
I have used the http://pojo.sodhanalibrary.com/ to convert
Any help how to create pojo for this JSON is welcome. Thanks in advance.
You can use Map to store the products and wrap it in another class to store the whole json. E.g. Product class would look like this:
class Product {
#JsonProperty("product_name")
private String productName;
#JsonProperty("product_type")
private String productType;
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductType() {
return productType;
}
public void setProductType(String productType) {
this.productType = productType;
}
}
Wrapper class would look like this:
class ProductList{
#JsonProperty("_id")
private String id;
private Map<String, Product> products;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Product> getProducts() {
return products;
}
public void setProducts(Map<String, Product> products) {
this.products = products;
}
}
Here's is the deserialization example with Jackson:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ProductList list = mapper.readValue("{\"_id\" : \"1234AG567\",\"products\" : {\"1234\":{\"product_name\" : \"xyz\",\"product_type\" : \"abc\"},\"3456\":{\"product_name\" : \"zzz\",\"product_type\" : \"def\"}}}", ProductList.class);
System.out.println(list.getId());
System.out.println(list.getProducts());
}
Please note that your json has a typo in it. Id field should be _id and not _id: (if that is the actual field name then you can change JsonProperty annotation to _id:.
Here is documentation for Jackson.
The JSON is valid, but you WILL NOT be able to create POJOs to represent that. Like you have already seen, you cannot create classes that begin with numbers, and you don't want to do this anyway as they won't provide any meaning to you.
I'm going to guess that products is an array of Product, and that number is an ID or something. The JSON should look something like this:
{
"products": [
{
"id": "1234",
"product_name": "xyz",
"product_type": "abc"
},
{
"id": "3456",
"product_name": "zzz",
"product_type": "def"
}]
}
Which would deserialize into a class that contains
private List<Product> products;
assuming that that the Product class looks like
class Product {
private Integer id;
#JsonProperty(value = "product_name")
private String productName;
#JsonProperty(value = "product_type")
private String productType;
}

Jackson data-bind deserialization: Skip over an element dependent on a value

I am using jackson library for deserializing json data.
Is there a way to skip some element if a attribute does not fit a criteria?
For Example
The java classes:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Group
{
private String name;
private int id;
private List<User> userList;
}
#JsonIgnoreProperties(ignoreUnknown = true)
public class User
{
private String firstName;
private String lastName;
private boolean deleted;
}
The Json File:
["test.Group", {
"name" : "testgroup1",
"id" : 3
"userList" : [ "java.util.ArrayList", [
["test.User", {
"firstName" : "John",
"lastName" : "Doe",
"deleted" : false } ],
["test.User", {
"firstName" : "John",
"lastName" : "Doe",
"deleted" : true } ],
["test.User", {
"firstName" : "John",
"lastName" : "Doe",
"deleted" : false } ] ] ]
}]
Usually I am deserialzing like this:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
test.Group g1 = mapper.readValue(jsonString,test.Group.class);
Now, Is it possible to skip every user-element whose attribute "deleted" has value true ?
I there a way to do this with data-bind or do I have to use another method like tree or streaming ?
EDIT
I am developing for android, not desktop.
The reason for this question is, that there can be thousands of User elements and I want to minimize the memory usage.
Not skipping, but removing after reading using Java 8 (assuming your User has a getter for deleted):
g1.getUserList().removeIf(User::isDeleted);
You can inject an intermediary by parsing to a tree node and then filtering on the nodes. An example:
public static void main(String[] args)
{
Group g = new Group();
g.setId(1);
g.setName("Test");
User u1 = new User();
u1.setDeleted(false);
u1.setFirstName("John");
u1.setLastName("Jones");
User u2 = new User();
u2.setDeleted(true);
u2.setFirstName("Jane");
u2.setLastName("Jones");
g.addUser(u1);
g.addUser(u2);
try
{
ObjectMapper mapper = new ObjectMapper();
String jsonVal = mapper.writeValueAsString(g);
JsonNode node = mapper.readTree(jsonVal);
for (Iterator<Entry<String, JsonNode>> it = node.fields(); it.hasNext(); )
{
Map.Entry<String, JsonNode> field = it.next();
String key = field.getKey();
if ("userList".equals(key))
{
JsonNode users = field.getValue();
if (users.isArray())
{
for (Iterator<JsonNode> x = users.iterator(); x.hasNext();)
{
JsonNode entry = x.next();
if (entry.get("deleted").asBoolean())
{
System.out.println("Remove " + entry.get("firstName").asText() + " " + entry.get("lastName").asText());
x.remove();
}
else
{
System.out.println("Don't remove " + entry.get("firstName").asText() + " " + entry.get("lastName").asText());
}
}
}
}
}
Group grp = mapper.treeToValue(node, Group.class);
System.out.println("Final group: " + grp);
}
catch (Exception e)
{
System.out.println("Something went wrong...");
e.printStackTrace();
}
}
Output results in :
Don't remove John Jones
Remove Jane Jones
Final group: Group [name=Test, id=1, userList=[User [firstName=John, lastName=Jones, deleted=false]]]
Here is a second approach using a custom deserializer on the Group object. This is just something I read up on so there may be efficiencies that can be added:
public class Answer28536024 {
#JsonDeserialize(using = GroupDeserializer.class)
public static class Group
{
private String name;
private int id;
private List<User> userList;
public Group()
{
userList = new ArrayList<User>();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public void addUser(User u)
{
userList.add(u);
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
#Override
public String toString() {
return "Group [name=" + name + ", id=" + id + ", userList=" + userList
+ "]";
}
}
public static class GroupDeserializer extends JsonDeserializer<Group>
{
#Override
public Group deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
JsonNode node = jp.getCodec().readTree(jp);
Group group = new Group();
group.setName(node.get("name").asText());
group.setId(node.get("id").asInt());
JsonNode users = node.get("userList");
if (users.isArray())
{
for (JsonNode userNode : users)
{
if (!userNode.get("deleted").asBoolean())
{
User user = new User();
user.setFirstName(userNode.get("firstName").asText());
user.setLastName(userNode.get("lastName").asText());
user.setDeleted(false);
group.addUser(user);
}
}
}
return group;
}
}
public static class User
{
private String firstName;
private String lastName;
private boolean deleted;
public User()
{
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
#Override
public String toString() {
return "User [firstName=" + firstName + ", lastName=" + lastName
+ ", deleted=" + deleted + "]";
}
}
public static void main(String[] args)
{
Group g = new Group();
g.setId(1);
g.setName("Test");
User u1 = new User();
u1.setDeleted(false);
u1.setFirstName("John");
u1.setLastName("Jones");
User u2 = new User();
u2.setDeleted(true);
u2.setFirstName("Jane");
u2.setLastName("Jones");
g.addUser(u1);
g.addUser(u2);
try
{
ObjectMapper mapper = new ObjectMapper();
String jsonVal = mapper.writeValueAsString(g);
System.out.println(jsonVal);
Group grp = mapper.readValue(jsonVal, Group.class);
System.out.println("Final group: " + grp);
}
catch (Exception e)
{
System.out.println("Something went wrong...");
e.printStackTrace();
}
}
}
Output for this one:
{"name":"Test","id":1,"userList":[{"firstName":"John","lastName":"Jones","deleted":false},{"firstName":"Jane","lastName":"Jones","deleted":true}]}
Final group: Group [name=Test, id=1, userList=[User [firstName=John, lastName=Jones, deleted=false]]]

Categories