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

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, ...
}

Related

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());
}

How to create a nested json using collections in java

I am creating a Json format for my nav bar menu and menu items.. i have put some effort and have done some work for one loop but what i want is to be nested json
My database has Data like This
What i want is to create a Json format from this table like this
var data = {
"India":
[
{ "Submenu": "delhi", "link" : "https://www.google.com" },
{ "Submenu": "mumbai", "link" : "https://www.google.com" }
],
"USA":
[
{ "Submenu": "NY", "link" : "https://www.google.com" },
{ "Submenu": "california", "link" : "https://www.google.com" }
],
"England":
[
{ "Submenu": "London", "link" : "https://www.google.com" },
{ "Submenu": "Menchester", "link" : "https://www.google.com" }
],
"logout":
[]
};
Till now i have tried this
LinkedHashMap<Object, Object> lhm = null;
List<Map<Object, Object>> list = new ArrayList<Map<Object, Object>>();
String sql="select menu,submenu and link from table_name";
String name,link;
String str = null;
Gson gson = new Gson();
try {
resultSet = statement.executeQuery(sql);
while(resultSet.next()){
lhm= new LinkedHashMap<Object, Object>();
name= resultSet.getString("submenu");
link= resultSet.getString("link");
lhm.put("submenu", name);
lhm.put("link", link);
list.add(lhm);
str = gson.toJson(list);
}
System.out.println(str);
from this i am getting result like this
[{"submenu":"Delhi","link":"https://www.google.com"},{"submenu":"mumbai","link":"https://www.google.com"},{"submenu":"NY","link":"https://www.google.com"},{"submenu":"California","link":"https://www.google.com"},{"submenu":"London","link":"https://www.google.com"},{"submenu":"Mencherter","link":"https://www.google.com"}]
now i have got the sub menus and there link .. i am facing trouble on linking the submenus to there respective menus .. i am facing issue in looping the data acc to my requirement if anyone of you have any suggestion and idea please help me out
First retrieve required dat from DB:
select menu, sub-menu, link from table_name;
Then create a Map to hold a menu content:
Map<String, List<Map<String, String>> map = new LinkedHashMap<>();
Then read result sets and fill a map, using menu name as a key:
while(rs.next()) {
map.compute(rs.getString("menu"), (menu, subMenus) -> {
Map<String, String> mapSubMenu = new LinkedHashMap<>();
mapSubMenu.put("Submenu", rs.getString("sub-menu"));
mapSubMenu.put("link", rs.getString("link"));
subMenus = subMenus != null ? subMenus : new ArrayList<>();
subMenus.add(mapSubMenu);
return subMenus;
});
}
Try Using Map<String,List<Map<Object, Object>>> instead of List<Map<Object, Object>> so that you can give menu name to your main menu.
LinkedHashMap<Object, Object> lhm; //initiaze
Map<String,List<Map<Object, Object>>> map;
List<Map<Object, Object>> list;
while(rs.next())
{
String menu = rs.getString("menu");
String subMenu = rs.getString("sub-menu");
String link = rs.getString("link");
lhm.put("submenu", name);
lhm.put("link", link);
if (map.containsKey(menu)) //check if mainmenu already present
{
map.get(menu).add(lhm);
}
else
{
//initialize list here
list.add(lhm);
map.put(menu,list);
}
}
str = gson.toJson(list);
Follow idea only and customize code as your need

how to declare a java bean for the below json structire

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]

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

JSON to XML conversion without changing the sequence

I am using the below code to convert json to xml of multiple XML files with different JSON structures.
String toXmlRequest = fullRequest.toString();
JSONObject jsonObj = new JSONObject(toXmlRequest);
String XmlRequest = XML.toString(jsonObj);
System.out.println(XmlRequest);
Input
{
"EnrollmentRequest":
{
"data":
{
"commonDataContext":
{
"requestId": "ADA12131",
"clientId": "ABCDEF",
"timestamp":"2013-12-13T11:10:00.715-05:00"
},
"cardNumber" : "123456789012345" ,
"firstName" : "John" ,
"lastName" : "Smith" ,
"email" : "JohnSmith#g.com" ,
"enrollStatus" : "E" ,
"pathEnroll" : "NewAcct",
"cardSavedIndicator" : "Y"
}
}
}
Output
<EnrollmentRequest>
<data>
<firstName>John</firstName>
<lastName>Smith</lastName>
<commonDataContext>
<clientId>ABCDEF</clientId>
<requestId>ADA12131</requestId>
<timestamp>2013-12-13T11:10:00.715-05:00</timestamp>
</commonDataContext>
<pathEnroll>NewAcct</pathEnroll>
<enrollStatus>E</enrollStatus>
<cardSavedIndicator>Y</cardSavedIndicator>
<cardNumber>123456789012345</cardNumber>
<email>JohnSmith#g.com</email>
</data>
</EnrollmentRequest>
The sequence of the output is getting changed. It is not able to keep the actual sequence. Is there any way this can be kept intact.
This is not possible using org.json.JSONObject directly. The reason is that JSONObject uses an internal store of type HashMap. HashMap does not preserve insertion order
It would be possible with a LinkedHashMap, however it does not appear possible to configure JSONObject to use one.
/**
* Construct an empty JSONObject.
*/
public JSONObject() {
this.map = new HashMap<String, Object>();
}
An alternative would be to read using a library that does preserve order, e.g. Jackson....
ObjectMapper mapper = new ObjectMapper();
JsonNode jackson = mapper.readTree(fullRequest);
and then feed that into XML
String xmlRequest = XML.toString(new JSONAdapter(jackson));
with the necessary type adaption to make the Jackson object look like a org.json.JSONObject. Incomplete example below:
private static class JSONAdapter extends JSONObject {
private JsonNode jackson;
public JSONAdapter(JsonNode jackson) {
this.jackson = jackson;
}
#Override
public Iterator<String> keys() {
return jackson.fieldNames();
}
#Override
public Object opt(String key) {
return get(key);
}
#Override
public Object get(String key) throws JSONException {
JsonNode nested = jackson.get(key);
if (nested.isObject()) {
return new JSONAdapter(nested);
} else if (nested.isTextual()) {
return nested.asText();
} else if (nested.isNumber()) {
return nested.asDouble();
} else if (nested.isBoolean()) {
return nested.asBoolean();
}
return null;
}
}
Output
<EnrollmentRequest>
<data>
<commonDataContext>
<requestId>ADA12131</requestId>
<clientId>ABCDEF</clientId>
<timestamp>2013-12-13T11:10:00.715-05:00</timestamp>
</commonDataContext>
<cardNumber>123456789012345</cardNumber>
<firstName>John</firstName>
<lastName>Smith</lastName>
<email>JohnSmith#g.com</email>
<enrollStatus>E</enrollStatus>
<pathEnroll>NewAcct</pathEnroll>
<cardSavedIndicator>Y</cardSavedIndicator>
</data>
</EnrollmentRequest>
For embedded json arrays, you need to apply one more condition to check if it array and return it as json array.
if(nested.isArray()) {
JSONArray arr = new JSONArray();
for(JsonNode value : nested){
arr.put(value.asText());
}
return arr;
}

Categories

Resources