how to declare a java bean for the below json structire - java

I have below json response as part of a webservice response ,where inner object name is value which is dynamic.Not able to understand how to declare a equivalent java bean...
{
"error": [
{
"fea09b93175b626e4bb3d248ccb890bc": {
"name": "80_5595_10.zip (5.0)",
"error": [
"Location path does not exist"
]
}
},
{
"5a8745c1967adabe9d492d3595f37ce1": {
"name": "80_7208_01.zip (5.0)",
"error": [
"Location path does not exist"
]
}
}
]

You could do it that way (example using Jackson).
I declared a bean as follow:
class Error {
String id;
String name;
List<String> error;
// Getters / Setters
#Override
public String toString() {
return "id="+id+", name="+name+", error="+error;
}
}
Your JSON structure is Map<String, List<Map<String, Error>>>
// Parse your JSON into a Map<String, List<Map<String, Error>>>
ObjectMapper mapper = new ObjectMapper();
Map<String, List<Map<String, Error>>> map =
mapper.readValue(json, new TypeReference<Map<String, List<Map<String, Error>>>>() {});
You now have this Map structure
{ error = [
{ fea09b93175b626e4bb3d248ccb890bc = Error#36d64342 },
{ 5a8745c1967adabe9d492d3595f37ce1 = Error#39ba5a14 }
]
}
Then take each error element of the Map and set their id to be the same as their key. And add them into a List
List<Map<String, Error>> errorsMap = map.get("error");
List<Error> errors = new ArrayList<>();
for(Map<String, Error> errorMap : errorsMap) {
String key = new ArrayList<>(errorMap.keySet()).get(0);
Error error = errorMap.get(key);
error.setId(key);
errors.add(error);
}
errors.forEach(System.out::println);
Outputs:
id=fea09b93175b626e4bb3d248ccb890bc, name=80_5595_10.zip (5.0), error=[Location path does not exist]
id=5a8745c1967adabe9d492d3595f37ce1, name=80_7208_01.zip (5.0), error=[Location path does not exist]

Related

How to model JSON with key value pairs?

This simple JSON is returned by https://httpbin.org/get which is handy for testing.
{
"args": {},
"headers": {
"Content-Length": "0",
"Host": "httpbin.org",
"User-Agent": "AemSConnector v1.0",
"X-Amzn-Trace-Id": "Root=1-606c333f-338353e14fc31e375617f4ba"
},
"origin": "81.40.159.142",
"url": "https://httpbin.org/get"
}
I'm trying to figure out how to build a Java class to model this.
I have tried:
public class ModelTest {
public String origin;
public String url;
public HashMap<String, String> headers;
public HashMap<String, String> args;
// getters and setters and default constructor here...
}
}
And also just this:
public class ModelTest {
public String origin;
public String url;
// getters and setters and default constructor here...
}
}
But when I try to convert the JSON string to this model, I just get a null point exception in the logs, no helpful info.
The code I am using is this:
// ModelTest model = null;
ModelTest model = new ModelTest();
model = (ModelTest) getObjectFromJson(reply, model);
}
:
public static Object getObjectFromJson(String jsonString, Object obj) {
Gson gson = new Gson();
Object returnValue = null;
try {
returnValue = gson.fromJson(jsonString, obj.getClass());
} catch (Exception e) {
log.error("Exception occured in Something :: getObjectFromJson --> ", e);
}
return returnValue;
}
exception:
2021-04-06 12:09:04.245 ERROR [com.adobe.aem.guides.wknd.core.util.MyConnector] Exception occured in Something :: getObjectFromJson -->
java.lang.NullPointerException: null
at com.adobe.aem.guides.wknd.core.util.SpineConnector.getObjectFromJson(MyConnector.java:77) [aem-guides-wknd.core:0.2.1.SNAPSHOT]
at com.adobe.aem.guides.wknd.core.util.SpineConnector.get(MyConnector.java:50) [aem-guides-wknd.core:0.2.1.SNAPSHOT]
at com.adobe.aem.guides.wknd.core.servlets.SpineServlet.doGet(MyServlet.java:64) [aem-guides-wknd.core:0.2.1.SNAPSHOT]
I found a solution. The Model was fine, it was the getObjectFromJson method which was causing the issues, even with a non-null object (as the commenters pointed out)
I scrapped it, and did the mapping in-line and it worked as expected:
Gson gson = new Gson();
model = gson.fromJson(reply, ModelTest.class);

Remove duplicate from object and merge in array

Code sample:-
public List<UserDto> getUserCandidates(String taskId) {
List<UserCandidates> listResponse;
ResponseEntity<String> response=restTemplate.getForEntity(configProperties.getUrl()+"/task/"+taskId+"/identity-links",
String.class);
listResponse =new Gson().fromJson(response.getBody(), new TypeToken<ArrayList<UserCandidates>>(){}.getType());
listResponse.forEach(result->{
if(!StringUtils.isEmpty(result.getUserId())){
ResponseEntity<UserRefer> userResponse=restTemplate.getForEntity(configProperties.getUrl()+"/user/"+result.getUserId()+"/profile", UserRefer.class);
userDtoList.add(new UserDto(result.getUserId(), Arrays.asList(result.getGroupId()), Arrays.asList(result.getType()), userResponse.getBody().getFirstName(),
userResponse.getBody().getLastName(), userResponse.getBody().getEmail()));
}
else if(!StringUtils.isEmpty(result.getGroupId())) {
ResponseEntity<String> responseGroup=restTemplate.getForEntity(configProperties.getUrl()+"/user"+"?memberOfGroup="+result.getGroupId(), String.class);
List<UserResponse> listGroup=new Gson().fromJson(responseGroup.getBody(), new TypeToken<ArrayList<UserResponse>>(){}.getType());
listGroup.forEach(resultGroup->{
userDtoList.add(new UserDto(resultGroup.getId(),Arrays.asList(result.getGroupId()),
Arrays.asList(result.getType()),resultGroup.getFirstName(),resultGroup.getLastName(),resultGroup.getEmail()));
});
}
});
return userDtoList;
}
So in if condition the response from API I'm getting is
UserRefer(id=demo, firstName=Demo, lastName=Demo, email=demo#camunda.org) - userResponse object
And from listResponse object data is [UserCandidates(userId=null, groupId=accounting, type=candidate), UserCandidates(userId=null, groupId=sales, type=candidate), UserCandidates(userId=demo, groupId=null, type=assignee)]
next in else if condition the response for listGroup is [UserResponse(status=null, id=demo, firstName=Demo, lastName=Demo, email=demo#camunda.org), UserResponse(status=null, id=mary, firstName=Mary, lastName=Anne, email=mary#camunda.org)]
So now you can see the data is duplicate. The output i want is for when userId is not empty from the data it should take type and merge the array
else if grouped not empty the data it should take for groupType and merge in the array removing duplicte and merging in same object
Output :-
[
{
"userId": "demo",
"name": "Demo Demo",
"type": [
"candidate",
"assignee"
],
"email": "demo#camunda.org",
"groupId": [
"accounting",
"sales"
]
},
{
"userId": "mary",
"name": "Mary Anne",
"type": [
"candidate"
],
"email": "mary#camunda.org",
"groupId": [
"accounting",
"sales"
]
}
]
You need some fundamental changes in your code.
1- instead of using ResponseEntity<String> use ResponseEntity<UserCandidates[]> response by this changing you don't need use Gson() dependency.
2- You don't need to use StringUtils to check to be empty. there is same method for both string and list objects.
3- For the duplicate date I define a Map<String,UserDto> with id as key and userDto object as a value. and where the userDto data is created I store it in the map with the id. as you see for storing userDto object in the map I used merge method that for the duplicate key(id) it has a merge function.
Tip: for readability would be nice to separate the restTemplate call in other class may you reuse it too.
mergeFunction is somthing like this:
private UserDto mergeFunction(UserDto u1,UserDto u2){
u1.getType().addAll(u2.getType());
u1.getGroupId().addAll(u2.getGroupId());
return u1;
}
and complete code is:
public List<UserDto> getUserCandidates(String taskId) {
Map<String, UserDto> userDtoMap = new HashMap<>();
Map<String, String> params = new HashMap<>();
ResponseEntity<UserCandidates[]> response = restTemplate
.getForEntity(configProperties.getUrl() + "/task/" + taskId + "/identity-links",
UserCandidates[].class, params);
Arrays.asList(response.getBody()).forEach(result -> {
if (!result.getUserId().isEmpty()) {
ResponseEntity<UserRefer> userResponse = restTemplate
.getForEntity(configProperties.getUrl() + "/**", UserRefer.class);
userDtoMap.merge(result.getUserId(), new UserDto(result.getUserId(),
new ArrayList<>(Arrays.asList(result.getGroupId())), Arrays.asList(result.getType()),
userResponse.getBody().getFirstName(),
userResponse.getBody().getLastName(),
userResponse.getBody().getEmail()), (u1, u2) -> mergeFunction(u1,u2));
} else if (!result.getGroupId().isEmpty()) {
String requestUri = configProperties.getUrl() + "/user" +
"?memberOfGroup={memberOfGroup}";
Map<String, String> userResParam = new HashMap<>();
userResParam.put("memberOfGroup", result.getGroupId());
ResponseEntity<UserResponse[]> responseGroup = restTemplate
.getForEntity(requestUri, UserResponse[].class, userResParam);
Arrays.asList(responseGroup.getBody()).forEach(resultGroup -> {
userDtoMap.merge(resultGroup.getId(), new UserDto(resultGroup.getId(),
Arrays.asList(result.getGroupId()),
Arrays.asList(result.getType()), resultGroup.getFirstName(),
resultGroup.getLastName(),
resultGroup.getEmail()), (u1, u2) -> mergeFunction(u1,u2));
});
}
});
return new ArrayList<>(userDtoMap.values());
}

Sending json array to rest endpoint results in jackson parsing exception

My used stack
spring boot 1.5.6 realease
ajax jquery 3.3.1
My objective
I m trying to print some data into jasper report so I created a rest controller, I got the idea to send json data from front end and got it parsed thanks to jackson api into List of pojo then using the JRDataBean to process my report
My code
When pushing the print button I m sending this json array using ajax that I got from the chrome console by making it a global variable then using a copy ( atrick that I googled to get variable content as string )
here is my json
.
[ {
"codeInterne": 45,
"clientName": "TalcorpDZ",
"clientPhone": "+213778217469",
"codeExterne": "CLI201801",
"email": "talcorpdz#gmail.com",
"clientType": 0,
"clientEtat": 1,
"identifiant": "TalcorpDZ",
"contacts": [
{
"nom": "Taleb",
"prenom": "Mohammed Housseyn",
"telephonePortable": "04330256699",
"email": null
}
],
"adresses": [
{
"adress": "Batiments des enseignants Mohammed Khemisti",
"ville": "Maghnia"
}
]
},
{
"codeInterne": 64,
"clientName": "lkjhgf",
"clientPhone": "+213778217469",
"codeExterne": "dfghjk",
"email": "talcorpdz#gmail.com",
"clientType": 1,
"clientEtat": 1,
"identifiant": "lkjhgf",
"contacts": [
{
"nom": "Taleb",
"prenom": "Mohammed",
"telephonePortable": "02354649",
"email": "talcorpdz#gmail.com"
}
],
"adresses": [
{
"adress": "Batiments des enseignants Mohammed Khemist",
"ville": "Maghnia"
}
]
}
]
and here is the part where I do the post request
.
$(document).on('click', '#menu0-func1-menu0-func1', function(){
console.log(printData);
var settings = {
"async" : true,
"crossDomain" : true,
"url" : "http://"+document.location.host+"/facturation/print/client",
"method" : "POST",
"headers" : {
"cache-control" : "no-cache",
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
"processData" : false,
"contentType" : "application/json",
"dataType" : "json",
"data" : printData
}
$.ajax(settings).done(function(response) {
console.log(response);
});
});
the post is well received by my controller which is coded as the following :
#RestController
#RequestMapping(PrintController.API)
public class PrintController {
public static final String API="print";
#PostMapping("client")
public void export(#RequestBody List<ClientJsonDto> datas,HttpServletResponse response){
System.out.println(datas);
// processing the print mechanisme
}
}
finally here is my ClientJsonDto.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"codeInterne",
"clientName",
"clientPhone",
"codeExterne",
"email",
"clientType",
"clientEtat",
"identifiant",
"contacts",
"adresses"
})
public class ClientJsonDto {
#JsonProperty("codeInterne")
private Integer codeInterne;
#JsonProperty("clientName")
private String clientName;
#JsonProperty("clientPhone")
private String clientPhone;
#JsonProperty("codeExterne")
private String codeExterne;
#JsonProperty("email")
private String email;
#JsonProperty("clientType")
private Integer clientType;
#JsonProperty("clientEtat")
private Integer clientEtat;
#JsonProperty("identifiant")
private String identifiant;
#JsonProperty("contacts")
private List<Contact> contacts = null;
#JsonProperty("adresses")
private List<Adress> adresses = null;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
// getters, setters
}
adress.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"adress",
"ville"
})
public class Adress {
#JsonProperty("adress")
private String adress;
#JsonProperty("ville")
private String ville;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
//getters, setters
}
contact.java
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"nom",
"prenom",
"telephonePortable",
"email"
})
public class Contact {
#JsonProperty("nom")
private String nom;
#JsonProperty("prenom")
private String prenom;
#JsonProperty("telephonePortable")
private String telephonePortable;
#JsonProperty("email")
private String email;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
//getters setters
}
the exception that I m facing is:
2018-11-18 15:12:40.255 WARN 1768 --- [nio-8082-exec-9]
.w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP
message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Unrecognized token 'object': was expecting ('true',
'false' or 'null'); nested exception is
com.fasterxml.jackson.core.JsonParseException: Unrecognized token
'object': was expecting ('true', 'false' or 'null') at [Source:
java.io.PushbackInputStream#1df244f9; line: 1, column: 9]
what can I do to see what my rest controller is receiving as request body before that jackson tries to marshal?
what can I do to fix this exception?
Your json value and mapping is all correct but i can't see producer and consumer with post mapping request as you have to explicitly define the producer and consumer.
The error could be due to the format of data you are giving to your controller. Your controller method is expecting JSON string. For example in case of jQuery, JSON.stringify() gives you JSON string. So I would suggest you confirm this at the client side from where you're sending the data to this controller.
Code which you need to change and check.
#RestController
#RequestMapping(PrintController.API)
public class PrintController {
public static final String API="print";
#PostMapping("client",produces=MediaType.APPLICATION_JSON_VALUE,consumes=MediaType.APPLICATION_JSON_VALUE)
public void export(#RequestBody List<ClientJsonDto> datas,HttpServletResponse response){
System.out.println(datas);
// processing the print mechanisme
}
}
I believe you want to see what is being received so that you can find why it is not getting mapped to your DTO.
Try changing
#RequestBody List<ClientJsonDto> datas
to
#RequestBody List<Map> datas
or
#RequestBody List datas
And see if you can print and debug it.
Finally got fixed
I based my fix upon this tutorial,what I mentioned is I m handling my array in a shady way so I tried the same principle, and I added the JSON.stringify and changed the datatype to text
here is all the changes that I made
$(document).on('click', '#menu0-func1-menu0-func1', function(){
console.log(printData);
var jsonData =JSON.parse(JSON.stringify(printData));
var settings = {
"async" : true,
"crossDomain" : true,
"url" : "http://"+document.location.host+"/facturation/print/client",
"method" : "POST",
"headers" : {
"cache-control" : "no-cache",
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
"processData" : false,
"contentType" : "application/json",
"dataType" : "text",
"data" : JSON.stringify(printData)
}
$.ajax(settings).done(function(response) {
console.log(response);
});
});
the print data that I m printing is handled as below
var printData =[];
function displayList(){
console.log("click");
if(console.log($('#search-client').val())){
console.log($('#search-client').val().toLowerCase());
}
var as=clientsData.filter((n,i,a) =>{return (
n.email.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].nom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].prenom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.adresses[0].ville.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].telephonePortable.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0)});
var html=' ';
console.log(as.length);
printData = [];
for(var i=0; i<as.length ; i++){
var ClientJsonDto = as[i];
html+=[{client : as[i] , index : i}].map(RefCliElement).join('');
printData.push(ClientJsonDto);
}
console.log(JSON.stringify(printData));
$('#clientList').html(html);
console.log(html);
}
before the fix it was like this, may be this idea is to avoid because I was using a jquery array of objects whithout knowing
var printData;
function displayList(){
console.log("click");
if(console.log($('#search-client').val())){
console.log($('#search-client').val().toLowerCase());
}
var as=clientsData.filter((n,i,a) =>{return (
n.email.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].nom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].prenom.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.adresses[0].ville.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0 ||
n.contacts[0].telephonePortable.toLowerCase().indexOf($('#search-client').val().toLowerCase()) >= 0)});
var html=' ';
console.log(as.length);
for(var i=0; i<as.length ; i++){
html+=[{client : as[i] , index : i}].map(RefCliElement).join('');
}
printData = as;
$('#clientList').html(html);
console.log(html);
}
wish this helps entry level like me in the futur

Add Map Values to a JSON object in identical key field names

I have the following Java Map. Map<String, String> containing values such as:
876234876, google
mike#hotmail, hotmail
9879892, google
I need to convert it to the following JSON object structure and Java JSON objects are not my friend.
"addresses" : [
{ "address":"876234876", "domain":"google" },
{ "address":"mike#hotmail", "domain":"hotmail" },
{ "address":"9879892", "domain":"google" }
]
To create the JSON you ask, you need to insert a JSONObject into a JSONArray. So for each Entry of your Map<String, String>, create a JSONObject like {"address": entry.key, "domain": entry.value} and add those to a JSONArray.
Let's use a Stream.map to create that object and insert the result into the array directly:
public static JSONObject createJson(Map<String, String> value) {
JSONObject result = new JSONObject();
JSONArray addresses = new JSONArray();
result.put("addresses", addresses);
value.entrySet().stream() //iterate the map
.map(e -> { //build an object
JSONObject address = new JSONObject();
address.put("address", e.getKey());
address.put("domain", e.getValue());
return address;
})
.forEach(addresses::put); //insert into the array
return result;
}
And test it with :
public static void main(String[] args) {
Map<String, String> values = new HashMap<>();
values.put("876234876", "google");
values.put("mike#hotmail", "hotmail");
values.put("9879892", "google");
System.out.println(createJson(values).toString(4));
}
And the result :
{"addresses": [
{
"address": "9879892",
"domain": "google"
},
{
"address": "876234876",
"domain": "google"
},
{
"address": "mike#hotmail",
"domain": "hotmail"
}
]}
Using the API : JSON In Java
<!-- https://mvnrepository.com/artifact/org.json/json -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180130</version>
</dependency>
Check this solution:
List<String> addresses = new ArrayList<>();
map.forEach((k, v) -> {
Map<String, String> nn = new HashMap<>();
nn.put("address", k);
nn.put("domain", v);
addresses.add(JSONValue.toJSONString(nn));
});
JSONObject result = new JSONObject(Collections.singletonMap("addresses", new JSONArray(addresses)));
Your JAVA objects should look like this :
List of addresses
#XmlRootElement
public class Foo {
private List<Address> addresses;
// Getter, Setter, ...
}
Address
public class Address {
private String address;
private String domain;
// Getters, setters, ...
}

manipulating json data in java...java newbie

I'm learning java at the moment and building a small app in Kafka Streams to ingest data and create a new stream essentially.
I have a main class like this:
public class Main {
public static void main(final String[] args) throws Exception {
final Properties streamsConfiguration = new Properties();
streamsConfiguration.put("application.id", "streams-consumer-logs");
streamsConfiguration.put("client.id", "consumer-client");
streamsConfiguration.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
streamsConfiguration.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String().getClass().getName());
streamsConfiguration.put(StreamsConfig.DEFAULT_TIMESTAMP_EXTRACTOR_CLASS_CONFIG, WallclockTimestampExtractor.class);
streamsConfiguration.put("servers");
final Serde<String> stringSerde = Serdes.String();
final Serde<Long> longSerde = Serdes.Long();
System.out.println(streamsConfiguration);
final KStreamBuilder builder = new KStreamBuilder();
final KStream<String, String> textLines = builder.stream( stringSerde, stringSerde,"sdp_logs");
//textLines.print();
System.out.println("test");
KStream<String, String> wordCounts = textLines
.map((key, value) -> {
//how do I manipulate this value which is a json object?
Gson gson = new Gson();
String json = gson.toJson(value);
FilterLogs filterlogs = new FilterLogs(json);
String filterlogs = filterlogs.execute();
return KeyValue.pair(key, json);
});
//KStream<String, Long> streamWrite = wordCounts.toStream();
wordCounts.print();
final KafkaStreams streams = new KafkaStreams(builder, streamsConfiguration);
streams.cleanUp();
streams.start();
Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
}
}
I then have a FilterLogs class that looks like this:
public class FilterLogs {
private type? jsoonObj;
public FilterLogs (type? jsonObj) {
this.jsonObj = jsonObj;
}
public type? getResult() { return result; }
public void execute () {
//manipulation of jsonObj goes in here?
}
}
}
My json object looks like this that value returns KStream<String, String> wordCounts = textLines.map((key, value) -> {}:
{
"tags": [
"dgtl"
],
"beat": {
"hostname": "host1",
"name": "host`",
"version": "5.4.1"
},
"input_type": "log",
"#timestamp": "2017-09-27T20:01:52.282Z",
"source": "/log/state-change.log",
"offset": 1725163,
"message": "message of the log is here"
"type": "log"
}
From my understanding in Java (as I come from the a functional programming paradigm) is that I have to take value, pass it to the class FilterLogs in my case, and then that class should return the new value...right?
Where I'm confused is what type to use for the class and how do I actually parse through the json and do stuff with it?
Normally, in javascript, I can just parse through it with a bunch of loops and do what I want but I don't quite get how to do this in Java.
What if I want my json object to return like this?
{
"tags": [
"dgtl"
],
"beat": {
"hostname": "host1"
},
"offset": 1725163,
"message": "message of the log is here"
}
You should checkout the new
JSON-P( for JSON processing & parsing) - http://json-b.net/
JSON-B (for JSON Binding) apis that was released recently - https://github.com/javaee/jsonp
They were made purposely for all of your usecases

Categories

Resources