Deserialize multiple objects with same attributes but different class name using ObjectMapper - java

How can I deserialize multiple objects with same structure but different variable name using object mapper?
{
"id":"A0D-29G3-03",
"a":{
"flag":"NORMAL",
"date":"..."
},
"b":{
"flag":"NORMAL",
"date":"..."
}
}
I'll have more objects than A and B. This is just an example. How can I deserialize multiple objects(using ObjectMapper) with same structure but different class name? Without creating one pojo for each class.....

... different class name
a and b are not different class names, are they? They are different fields which can share the same class. You can use one single class (Abc in the example) for fields a, b, etc.
Does this work for you?
#Setter
#Getter
#ToString
#JsonIgnoreProperties(ignoreUnknown = true)
public static class AbcWrapper {
private String id;
#JsonAnySetter
Map<String, Abc> abc = new LinkedHashMap<>();
}
#Setter
#Getter
#ToString
public static class Abc {
private String flag;
private String date;
}
public static void main(String[] args) throws IOException {
String json = "{ " +
" \"id\":\"A0D-29G3-03\"," +
" \"a\":{ " +
" \"flag\":\"NORMAL\"," +
" \"date\":\"...\"" +
" }," +
" \"a1\":{ " +
" \"flag\":\"NORMAL\"," +
" \"date\":\"...\"" +
" }," +
" \"a2\":{ " +
" \"flag\":\"NORMAL\"," +
" \"date\":\"...\"" +
" }," +
" \"a3\":{ " +
" \"flag\":\"NORMAL\"," +
" \"date\":\"...\"" +
" }," +
" \"b\":{ " +
" \"flag\":\"NORMAL\"," +
" \"date\":\"...\"" +
" }" +
"}";
ObjectMapper mapper = new ObjectMapper();
final AbcWrapper abcWrapper = mapper.readValue(json.getBytes(), AbcWrapper.class);
System.out.println(abcWrapper);
}
I used lombok annotations #Setter, #Getter, #ToString in the example. You can replace them with setters/getters if you don't want to use lombok.

Related

How to populate list and piece them together in POJO class

I have this JSON which I transformed into a POJO consisting of 3 different classes.
{
"Id": "2a0dd1fc",
"name": "AABBCCDD",
"description": "test",
"active": true,
"Groups": [
{
"agentGroups": [
{
"Id": "AXSNqSWSILMPnVvB-Cdc"
}
],
"order": 1,
"duration": 0
},
{
"agentGroups": [
{
"Id": "AXZlGzTR4pYEiRgUOqOL"
}
],
"order": 2,
"duration": 60
}
]
}
-----------------------------------AgentGroup.java-----------------------------------
public class AgentGroup{
public String id;
//Getter & Setters
}
-----------------------------------Group.java-----------------------------------
public class Group{
** public List<AgentGroup> agentGroups;**
public int order;
public int duration;
//Getter & Setters
public void setAgentGroups(List<AgentGroup> agentGroups) {
this.agentGroups = agentGroups;
}
}
-----------------------------------DistributionGroup.java-----------------------------------
public class DistributionGroup{
public String id;
public String name;
public String description;
public boolean active;
**public List<Group> groups;**
//Getter & Setters
public void setGroups(List<Group> groups) {
this.groups = groups;
}
}
As you can see Group is a List and agentGroup is also a List.
I'm having difficulty populating/setting up the list values and piece them together and return the Group as a list.
I have tried to set it up like this but it does not seem to be working:
//function call
List<Group> groups=createDistributionGroup(teamIds,1)
Function:
public static Group createDistributionGroup(List<String> teamIds, int order) {
Group grp= new Group();
grp.setOrder(order);
grp.setDuration(60);
//Now How do I put AgentGroup in a list and return the group.
return grp;
}
Appreciate any help.
Your model represents your json, more or less. Here's a simple test that you can use to validate it.
String s = "{\n"
+ " \"id\": \"2a0dd1fc\",\n"
+ " \"name\": \"AABBCCDD\",\n"
+ " \"description\": \"test\",\n"
+ " \"active\": true,\n"
+ " \"groups\": [\n"
+ " {\n"
+ " \"agentGroups\": [\n"
+ " {\n"
+ " \"id\": \"AXSNqSWSILMPnVvB-Cdc\"\n"
+ " }\n"
+ " ],\n"
+ " \"order\": 1,\n"
+ " \"duration\": 0\n"
+ " },\n"
+ " {\n"
+ " \"agentGroups\": [\n"
+ " {\n"
+ " \"id\": \"AXZlGzTR4pYEiRgUOqOL\"\n"
+ " }\n"
+ " ],\n"
+ " \"order\": 2,\n"
+ " \"duration\": 60\n"
+ " }\n"
+ " ]\n"
+ " }";
DistributionGroup distributionGroup = new ObjectMapper().reader()
.readValue(s, DistributionGroup.class);
I did make a few changes to your json, I set the field Id to id, and Groups to groups, notice the case difference. If you cannot change the json, then you have to add an annotation to your model attributes to let them know that they don't conform to the bean spec. For instance, if you wish to preserve Id in your json, then add #JsonAlias("Id") to the id property on your class, so the field would look like
#JsonAlias("Id")
public String id;
To add AgentGroups to your Group in the createDistributionGroup method, it would look something like this:
AgentGroup ag1 = new AgentGroup();
ag1.setId("10");
AgentGroup ag2 = new AgentGroup();
ag1.setId("20");
grp.setAgentGroups(Arrays.asList(ag1, ag2));

Traversing through dynamic JSON to read properties of every child node

I have some JSON which is subject to change but one constant is it will always contain multiple objects with two properties; text and answerText. An example JSON would be
{
"food": {
"eggTolerance": {
"answerText": "None",
"text": "What is your egg tolerance?"
},
"lactoseTolerance": null
},
"cookingExperience": {
"experienceInLastFiveYears": {
"answerText": "Yes",
"text": "Was this experience within the last 5 years?"
},
"numberOfPies": {
"answerText": "More than 50",
"text": "How many pies have you baked?"
},
"significantPies": {
"answerText": "More than 50",
"text": "How many of these pies per quarter were at tasty?"
},
"spanOfExperience": {
"answerText": "Yes",
"text": "Do you have at least 12 months' experience baking pies?"
}
},
"cocktails": {
"manhattans": {
"answerText": "The kiss of death",
"text": "What have I done to deserve this flat, flavourless Manhattan?"
},
"Gin Martini": null
},
"waitressing": null
}
This can be changed by making it deeper or wider. For example the lactoseTolerance could have another object added to it or another object could be added to the root object.
How can I traverse this object to visit every object to get the properties of the deepest object?
I have seen this example but this just gives me the first level. In this instance I know I can then iterate the children of those objects but if the hierarchy changes the implementation is ruined.
I have used GSON lib:
Please try below code:
pom.xml
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
Then I have created QA class that have your fixed two properties; text and answerText
import com.google.gson.annotations.SerializedName;
public class QA {
#SerializedName("answerText")
private String answerText;
#SerializedName("text")
private String text;
public QA(String answerText, String text) {
this.answerText = answerText;
this.text = text;
}
#Override
public String toString() {
return "QA{" +
"answerText='" + answerText + '\'' +
", text='" + text + '\'' +
'}';
}
public String getAnswerText() {
return answerText;
}
public void setAnswerText(String answerText) {
this.answerText = answerText;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
Now in driver code:
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Map;
public class Main {
public static void main(String[] args) {
System.out.println("running!!");
InputStream inputStream = Main.class.getResourceAsStream("json.json");
String json = "{\n" +
" \"food\": {\n" +
" \"eggTolerance\": {\n" +
" \"answerText\": \"None\",\n" +
" \"text\": \"What is your egg tolerance?\"\n" +
" },\n" +
" \"lactoseTolerance\": null\n" +
" },\n" +
" \"cookingExperience\": {\n" +
" \"experienceInLastFiveYears\": {\n" +
" \"answerText\": \"Yes\",\n" +
" \"text\": \"Was this experience within the last 5 years?\"\n" +
" },\n" +
" \"numberOfPies\": {\n" +
" \"answerText\": \"More than 50\",\n" +
" \"text\": \"How many pies have you baked?\"\n" +
" },\n" +
" \"significantPies\": {\n" +
" \"answerText\": \"More than 50\",\n" +
" \"text\": \"How many of these pies per quarter were at tasty?\"\n" +
" },\n" +
" \"spanOfExperience\": {\n" +
" \"answerText\": \"Yes\",\n" +
" \"text\": \"Do you have at least 12 months' experience baking pies?\"\n" +
" }\n" +
" },\n" +
" \"cocktails\": {\n" +
" \"manhattans\": {\n" +
" \"answerText\": \"The kiss of death\",\n" +
" \"text\": \"What have I done to deserve this flat, flavourless Manhattan?\"\n" +
" },\n" +
" \"Gin Martini\": null\n" +
" },\n" +
" \"waitressing\": null\n" +
"}";
final Gson gson = new Gson();
Type type = new TypeToken<Map<String, Map<String, QA>>>(){}.getType();
Map<String, Map<String, QA>> myMap = gson.fromJson(json, type);
System.out.println("Data:"+ myMap.get("food").get("eggTolerance").getAnswerText());
}
}

Hibernate/JPA map Result of native Query to non-Entity holding Entities

I do have 3 Entities and want to Cross-Join them. As I do not need to create a new Entity for this I just wanted to map the by fetching with a native Query:
EntityA{
...
String someValue;
}
EntityB{
...
String someValue;
}
EntityC{
...
String someValue;
}
And the CrossJoined Object
CrossJoinedFoo{
EntityA entityA;
EntityB entityB;
EntityC entityC;
}
I am using it like:
private static final String _SELECT_CROSS_JOIN_ENTITIES = "SELECT * FROM "
+ "EntityA"
+ ", "
+ "EntityB"
+ ", "
+ "EntityC"
+ " WHERE (1=1) "
+ " AND " + "EntityA.someValue = :someValue"
+ " AND " + "EntityB.someValue = :someValue"
+ " AND " + "EntityC.someValue = :someValue";
Query query = entityManager.createNativeQuery(_SELECT_CROSS_JOIN_ENTITIES);
query.setParameter(":someValue", "foo");
How can I achieve this behavior?
You can go for a HQL query and use the result class strategy.
Just remember to add a constructor to CrossJoinedFoo accepting 3 entities in appropriate order:
private static final String _SELECT_CROSS_JOIN_ENTITIES =
"SELECT new my.package.CrossJoinedFoo(a,b,c) FROM "
+ "EntityA a"
+ ", "
+ "EntityB b"
+ ", "
+ "EntityC c"
+ " WHERE (1=1) "
+ " AND " + "a.someValue = :someValue"
+ " AND " + "b.someValue = :someValue"
+ " AND " + "c.someValue = :someValue";
Query query = entityManager.createQuery(_SELECT_CROSS_JOIN_ENTITIES);
query.setParameter(":someValue", "foo");
List<CrossJoinedFoo> result = query.list();
Just remember to change the package to an appropriate one.
Using #SqlResultSetMapping with #ConstructorResult
Beware that the resulted entities won't be managed

Json Parsing in Java(key is not constant)

Below is my JSON:
{
"-5": [
"15:D1_CHANNEL_ID_SK",
"23:D1_CALL_BEGIN_DATE",
"87:D1_CELL_ID"
],
"-4": [
"31:I_RECHARGE_AMOUNT",
"59:I_INBUNDLED_UNIT",
"60:I_DAY_NIGHT_FLAG",
"53:PD_UPSELL_PACK_ID",
"146:AON"
]
}
In the above Json, the key is also a variable (it is not constant). Because of that I'm not able to parse the json using mapper.readValue().
Im assuming that by mapper.readValue(), you're trying to read a string value into a map like structure (can be a POJO or a HashMap) with the help of an ObjectMapper.
The following code reads from the string and converts it into a Map<String,Object>.
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String data = "{\n" + " \"-5\": [\n" + " \"15:D1_CHANNEL_ID_SK\",\n" + " \"23:D1_CALL_BEGIN_DATE\",\n" + " \"87:D1_CELL_ID\"\n" + " ],\n" + " \"-4\": [\n" + " \"31:I_RECHARGE_AMOUNT\",\n" + " \"59:I_INBUNDLED_UNIT\",\n" + " \"60:I_DAY_NIGHT_FLAG\",\n" + " \"53:PD_UPSELL_PACK_ID\",\n" + " \"146:AON\"\n" + " ]\n" + "}";
final Map<String, Object> response = objectMapper
.readValue(data, objectMapper.getTypeFactory().constructMapType(Map.class, String.class, Object.class));
}
Of-course, the value type in the map can be an object too. In that case, the code might look like this
public static void main(String[] args) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
String data = "{\n" + " \"-5\": [\n" + " \"15:D1_CHANNEL_ID_SK\",\n" + " \"23:D1_CALL_BEGIN_DATE\",\n" + " \"87:D1_CELL_ID\"\n" + " ],\n" + " \"-4\": [\n" + " \"31:I_RECHARGE_AMOUNT\",\n" + " \"59:I_INBUNDLED_UNIT\",\n" + " \"60:I_DAY_NIGHT_FLAG\",\n" + " \"53:PD_UPSELL_PACK_ID\",\n" + " \"146:AON\"\n" + " ]\n" + "}";
final Map<String, Your Class Name> response = objectMapper
.readValue(data, objectMapper.getTypeFactory().constructMapType(Map.class, String.class, <Your Class Name>.class));
}
It is also possible to convert the value type to another container based type (like a List), which I leave for your exploration.

JSON String to POJO, using GSON, clarification needed

I have a JSON file, as String:
String compString = "{\n" +
" \"Component\": {\n" +
" \"name\": \"Application\",\n" +
" \"environment\": \"QA\",\n" +
" \"hosts\": [\n" +
" \"box1\",\n" +
" \"box2\"\n" +
" ],\n" +
" \"directories\": [\n" +
" \"/path/to/dir1/\",\n" +
" \"/path/to/dir2/\",\n" +
" \"/path/to/dir1/subdir/\",\n" +
" ]\n" +
" }\n" +
" }";
I have a bean representing it (correct if incorrectly)
public class Component {
String name;
String environment;
List<String> hosts = new ArrayList<String>();
List<String> directories = new ArrayList<String>();
// standard getters and setters
}
I am trying to feed this String to this class by:
Gson gson = new Gson();
Component component = gson.fromJson(compString, Component.class);
System.out.println(component.getName());
Above does not work. (I am getting null back, as if Component's name value is never set)
What am i missing please?
In fact, you have to remove the enclosing class from Json.
Indeed, JSON begins with the content of the enclosing class.
So your JSON would be:
String compString = "{\n" +
" \"name\": \"Application\",\n" +
" \"environment\": \"QA\",\n" +
" \"hosts\": [\n" +
" \"box1\",\n" +
" \"box2\"\n" +
" ],\n" +
" \"directories\": [\n" +
" \"/path/to/dir1/\",\n" +
" \"/path/to/dir2/\",\n" +
" \"/path/to/dir1/subdir/\",\n" +
" ]\n" +
" }\n";
String compString =
" {\n" +
" \"name\": \"Application\",\n" +
" \"environment\": \"QA\",\n" +
" \"hosts\": [\n" +
" \"box1\",\n" +
" \"box2\"\n" +
" ],\n" +
" \"directories\": [\n" +
" \"/path/to/dir1/\",\n" +
" \"/path/to/dir2/\",\n" +
" \"/path/to/dir1/subdir/\",\n" +
" ]}" ;
I think you should read more about json, I have removed something in your json string and then success.

Categories