Converting Dynamic ArrayList to Json - java

I want to convert an array list to json string of a specific format. I get all the users emails in an array list and want to convert it into the following format of JSON.
[
{"email":"abc#gmail.com"},
{"email":"xyz#gmail.com"}
]
My controller action is
public static Result apiCustomers(){
List<Customer> customerList = Model.coll(Customer.class).find().toArray();
List<String> emails = new ArrayList<String>();
for(Customer c : customerList){
emails.add(c.email);
}
//ObjectNode result = Json.newObject();
//result.put("emails", Json.toJson(emails));
return ok();
}
How can I convert the emails list to the above json format?
Thanks in advance

Why use another JSON ser/des lib? Play has one built-in (a wrapper around jackson - which is really fast).
Starting from your code:
public static Result apiCustomers(){
List<Customer> customerList = Model.coll(Customer.class).find().toArray();
List<String> emails = new ArrayList<String>();
for(Customer c : customerList){
emails.add(c.email);
}
return ok(Json.toJson(emails));
}
This uses some defaults but should be enough.
Or manually:
public static Result apiCustomers(){
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
List<Customer> customerList = Model.coll(Customer.class).find().toArray();
for(Customer c : customerList){
ObjectNode mail = Json.newObject();
mail.put("email", c.email);
arrayNode.add(mail);
}
return ok(arrayNode);
}
No need for Gson.

You can use this library:
http://code.google.com/p/google-gson/
Pretty easy tutorial about it here:
http://www.mkyong.com/java/how-do-convert-java-object-to-from-json-format-gson-api/
Or you can write a custom toJson method to your classes or an util Json (not a big deal)
in your case it should be something like that (i didn't test it):
public String toJson(List<String> emails) {
StringBuilder result = new StringBuilder();
result.append("[");
result.append("\n");
for (String s : emails) {
result.append("{");
result.append("\"email\":");
result.append("\"");
result.append(s);
result.append("\"");
result.append("}");
result.append(",");
result.append("\n");
}
result.append("]");
return result.toString();
}

With the benefit of Java 8 (and I suspect a newer Jackson version):
private static final ObjectMapper mapper = new ObjectMapper();
...
List<Customer> customerList = Model.coll(Customer.class).find().toArray();
ArrayNode emails = mapper.createArrayNode();
customerList.forEach(c -> emails.add(c.email));

Related

How can I read two JSON files with different data at the same time?

My part of the task is:
I need to collect productId-s into list from two JSON files with different data and pass it into the custom method with directory of JSON files.
I have two JSON files with different data as the following:
JSON №1
JSON №2
And my code is in the next format:
public class Main {
public static void main(String[] args) throws IOException, ParseException {
JSONParser parser = new JSONParser();
InputStream isOne = JSONParser.class.getResourceAsStream("/test/java/resources/json/file/product_0001690510.json");
InputStream isTwo = JSONParser.class.getResourceAsStream("/test/java/resources/json/file/product_0001694109.json");
// ... need to use somehow InpuStream for reading two JSON files with different structure inside
JSONArray arr = obj.getJSONArray("products"); // notice that `"products": [...]`
String productId = null;
for (int i = 0; i < arr.length(); i++) {
productId = arr.getJSONObject(i).getString("productID");
}
List<String> productIds = new ArrayList<>(Collections.singleton(productId));
for (var file : obj.keySet()) {
System.out.println(getAllExportsWithProductIds(file, productIds));
}
}
public static List<String> getAllExportsWithProductIds(String directory, List<String> productIds) throws IOException {
var matchingObjects = new ArrayList<String>();
try (var fileStream = Files.walk(Path.of(directory))) {
for (var file : fileStream.toList()) {
var json = Json.readString(Files.readString(file));
var objects = JsonDecoder.array(json);
for (var object : objects) {
var objectProductIDs = JsonDecoder.field(
object, "products",
JsonDecoder.array(JsonDecoder.field("productID", JsonDecoder::string))
);
for (var productId : objectProductIDs) {
if (productIds.contains(productId)) {
matchingObjects.add(Json.writeString(object));
break;
}
}
}
}
}
return matchingObjects;
}
}
Full code
Based on it my question is:
Can I read all provided JSON files at the same time to collect productId-s into list? If yes, how can I do that if I have the different data of two JSON files.
To clarify a bit:
"By different data, I mean, in general, the number of these fields
(for example, productId fields in both of JSON-s: №1 and №2
accordingly), their order. That is, how an array object differs from
another.
If these JSON-s have the same data, it'd be easier to parse, but
in this specific usecase I need to find the way how to handle both of
them in different way as their data is not in the same format of representation."
My detailed explanation how I see it in abstract way:
How I see it abstractly in the lifecycle of developing.
I've already read different articles and checked libraries as:
java-jq
Jackson object mapper tutorial
and so on,
but I'm still struggling with understanding how to apply it correctly, for this reason, I'm looking for a concrete solution.
Thank you in advance for any smart and helpful ideas. If you need some additional details, I'm ready to provide without any problem.
UPD:
There's I have another version of code, which is collecting productID-s, I need just to find the way how to combine with the first version of code and that's it:
public class ProductIdImporter {
public ProductIdImporter() {
// TODO Auto-generated constructor stub
}
public void importJson() {
List<Path> paths = Arrays.asList(Paths.get("C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001690510.json"),
Paths.get("C:\\Users\\pc\\IdeaProjects\\jsonapi\\src\\test\\java\\resources\\json\\product_0001694109.json"));
ObjectMapper jsonMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Set<String> productIds = paths.stream().map(path -> {
try {
return jsonMapper.readValue(Files.newInputStream(path), ExportList[].class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}).map(Arrays::asList)
.flatMap(List::stream)
.map(ExportList::productList)
.flatMap(List::stream)
.map(Product::getId)
.collect(Collectors.toSet());
productIds.forEach(System.out::println);
}
public static void main(String[] args) {
ProductIdImporter importer = new ProductIdImporter();
importer.importJson();
}
static class ExportList {
public List<Product> products;
public ExportList() {
}
public List<Product> productList() {
return products;
}
}
static class Product {
public String productID;
public Product() {
}
public String getId() {
return productID;
}
}
}
Taking the JSON №1 you have included in your post basically it is an array of json objects with the same format like below (I have included just the first one element and deleted all the properties you are not interested to parse):
[{
"products": [
{
"colorWayID": "IMP5002620012114",
"productID": "0001755256"
},
{
"colorWayID": "IMP8473190012114",
"productID": "0001690510"
},
{
"colorWayID": "IMP9100570012114",
"productID": "0001700877"
}
],
...other properties excluded from parsing
}]
To iterate over this array you can read your json file into a ArrayNode and iterate over every element:
ArrayNode arrayNode = (ArrayNode) mapper.readTree(json);
for (int i = 0; i < arrayNode.size(); ++i) {/*inspecting products property*/}
The products property is an array of JsonNode containing the productID property you want to extract, you can use the JsonNode#get method to extract both the products and productID properties:
List<String> productIds = new ArrayList<>();
ArrayNode arrayNode = (ArrayNode) mapper.readTree(json);
for (int i = 0; i < arrayNode.size(); ++i) {
//products property is also an array
ArrayNode products =(ArrayNode) arrayNode.get(i).get("products");
for (int j = 0; j < products.size(); ++j) {
//adding productId to your list
productIds.add(products.get(j).get("productID").asText());
}
}
This process can be repeated for other json files with variations depending from the json structure contained in them, but substantially it remains the same.

How to collect data after Flux.subscribe to send it as a json array?

This is an example that I made it, what should I do to get the treated data to send the result list as a WS json response ?
#Produces(MediaType.APPLICATION_JSON)
public List<String> tryFlux(#QueryParam("names") List<String> names) {
String[] array = new String[names.size()];
Flux.fromIterable(asList(names.toArray(array))).
doOnNext(this::executeService).doOnError(ex -> handleError(ex, names)).retry(1).subscribe();
return ??; //Need help here
}
You can wrap already resolved values with Mono to return JSON data.
#Produces(MediaType.APPLICATION_JSON)
public Mono<JSONResponseObject> tryFlux(#QueryParam("names") List<String> names) {
String[] array = new String[names.size()];
Flux.fromIterable(asList(names.toArray(array))).
doOnNext(this::executeService).doOnError(ex -> handleError(ex, names)).retry(1).subscribe();
return Mono.just(jsonResponseObject); //Need help here
}

How to parse JSON with JAVA when there are random key names

How do I convert some JSON to a POJO when I don't know the name of a key?
This is my POJO:
public class Summoner {
private Details summonerDetails;
public Details getSummonerDetails() {
return summonerDetails;
}
public void setSummonerDetails(Details summonerDetails) {
this.summonerDetails = summonerDetails;
}
}
The Details class have variables like id, name, etc. -> No issues here
This is the line in my Main class where I try to map the JSON to a POJO:
Summoner test = new ObjectMapper().readValue(json, Summoner.class);
this is a JSON response example I receive:
{
"randomName":{
"id":22600348,
"name":"Ateuzz",
"profileIconId":546,
"summonerLevel":30,
"revisionDate":1378316614000
}
}
if my POJO Details member variable name is "randomName", above code will work. but when I get a response with a different name than "randomName", it doesn't. How do I make my code work for random names?
I'm using Jackson
I'm sorry I can't make a little more clear my issue.
I have solution using not only jackson API but with the use of org.json API also.
String str = "{\"randomName\":{\"id\":22600348,\"name\":\"Ateuzz\",\"profileIconId\":546,\"summonerLevel\":30,\"revisionDate\":1378316614000}}";
JSONObject json = new JSONObject(str);
Iterator<?> keys = json.keys();
while(keys.hasNext())
{
String key = (String)keys.next();
Details test = new ObjectMapper().readValue(json.getJSONObject(key).toString(), Details.class);
}
Here i have use another JAVA Json API to convert your string into jsonObject and than iterate it to get your first key value and map that to your class Details.
I assume that your json format is same as you have mention in your question.
May this will help you.
Using Jackson:
String json = "{\"randomName\":{\"id\":22600348,\"name\":\"Ateuzz\",\"profileIconId\":546,\"summonerLevel\":30,\"revisionDate\":1378316614000}}";
try
{
#SuppressWarnings("unchecked")
Map<String, Map<String, Object>> map = (Map) new ObjectMapper().readValue(json, Map.class);
for(String key : map.keySet())
{
Map<String, Object> submap = map.get(key);
System.out.println(key + ":");
for(String k : submap.keySet())
{
System.out.println("\t" + k + ": " + submap.get(k));
}
}
}
catch(IOException e)
{
e.printStackTrace();
}

How to convert Arraylist to Json in Java

I have an arraylist, the arraylist holds a bunch of Domain object. It's like below showed:
Domain [domainId=19, name=a, dnsName=a.com, type=0, flags=0]
Domain [domainId=20, name=b, dnsName=b.com, type=0, flags=12]
Domain [domainId=21, name=c, dnsName=c.com, type=0, flags=0]
Domain [domainId=22, name=d, dnsName=d.com, type=0, flags=0]
My question is how to convert the ArrayList to JSON? The data format should be:
{
"param":{
"domain":[
{
"domid":19,
"name":"a",
"dnsname":"a.com",
"type":0,
"flags":
},
...
]
}
Not sure if it's exactly what you need, but you can use the GSON library (Link) for ArrayList to JSON conversion.
ArrayList<String> list = new ArrayList<String>();
list.add("str1");
list.add("str2");
list.add("str3");
String json = new Gson().toJson(list);
Or in your case:
ArrayList<Domain> list = new ArrayList<Domain>();
list.add(new Domain());
list.add(new Domain());
list.add(new Domain());
String json = new Gson().toJson(list);
If for some reason you find it more convenient, you can also iterate through the ArrayList and build a JSON from individual Domain objects in the list
String toJSON(ArrayList<Domain> list) {
Gson gson = new Gson();
StringBuilder sb = new StringBuilder();
for(Domain d : list) {
sb.append(gson.toJson(d));
}
return sb.toString();
}

Convert JSON object with duplicate keys to JSON array

I have a JSON string that I get from a database which contains repeated keys. I want to remove the repeated keys by combining their values into an array.
For example
Input
{
"a":"b",
"c":"d",
"c":"e",
"f":"g"
}
Output
{
"a":"b",
"c":["d","e"],
"f":"g"
}
The actual data is a large file that may be nested. I will not know ahead of time what or how many pairs there are.
I need to use Java for this. org.json throws an exception because of the repeated keys, gson can parse the string but each repeated key overwrites the last one. I need to keep all the data.
If possible, I'd like to do this without editing any library code
As of today the org.json library version 20170516 provides accumulate() method that stores the duplicate key entries into JSONArray
JSONObject jsonObject = new JSONObject();
jsonObject.accumulate("a", "b");
jsonObject.accumulate("c", "d");
jsonObject.accumulate("c", "e");
jsonObject.accumulate("f", "g");
System.out.println(jsonObject);
Output:
{
"a":"b",
"c":["d","e"],
"f":"g"
}
I want to remove the repeated keys by combining their values into an array.
Think other than JSON parsing library. It's very simple Java Program using String.split() method that convert Json String into Map<String, List<String>> without using any library.
Sample code:
String jsonString = ...
// remove enclosing braces and double quotes
jsonString = jsonString.substring(2, jsonString.length() - 2);
Map<String, List<String>> map = new HashMap<String, List<String>>();
for (String values : jsonString.split("\",\"")) {
String[] keyValue = values.split("\":\"");
String key = keyValue[0];
String value = keyValue[1];
if (!map.containsKey(key)) {
map.put(key, new ArrayList<String>());
}
map.get(key).add(value);
}
output:
{
"f": ["g"],
"c": ["d","e"],
"a": ["b"]
}
In order to accomplish what you want, you need to create some sort of custom class since JSON cannot technically have 2 values at one key. Below is an example:
public class SomeClass {
Map<String, List<Object>> values = new HashMap<String, List<Object>>();
public void add(String key, Object o) {
List<Object> value = new ArrayList<Object>();
if (values.containsKey(key)) {
value = values.get(key);
}
value.add(o);
values.put(key, value);
}
public JSONObject toJson() throws JSONException {
JSONObject json = new JSONObject();
JSONArray tempArray = null;
for (Entry<String, List<Object>> en : values.entrySet()) {
tempArray = new JSONArray();
for (Object o : en.getValue()) {
tempArray.add(o);
}
json.put(en.getKey(), tempArray);
}
return json;
}
}
You can then retrieve the values from the database, call the .add(String key, Object o) function with the column name from the database, and the value (as the Object param). Then call .toJson() when you are finished.
Thanks to Mike Elofson and Braj for helping me in the right direction. I only wanted to have the keys with multiple values become arrays so I had to modify the code a bit. Eventually I want it to work for nested JSON as well, as it currently assumes it is flat. However, the following code works for what I need it for at the moment.
public static String repeatedKeysToArrays(String jsonIn) throws JSONException
{
//This assumes that the json is flat
String jsonString = jsonIn.substring(2, jsonIn.length() - 2);
JSONObject obj = new JSONObject();
for (String values : jsonString.split("\",\"")) {
String[] keyValue = values.split("\":\"");
String key = keyValue[0];
String value = "";
if (keyValue.length>1) value = keyValue[1];
if (!obj.has(key)) {
obj.put(key, value);
} else {
Object Oold = obj.get(key);
ArrayList<String> newlist = new ArrayList<String>();
//Try to cast as JSONArray. Otherwise, assume it is a String
if (Oold.getClass().equals(JSONArray.class)) {
JSONArray old = (JSONArray)Oold;
//Build replacement value
for (int i=0; i<old.length(); i++) {
newlist.add( old.getString(i) );
}
}
else if (Oold.getClass().equals(String.class)) newlist = new ArrayList<String>(Arrays.asList(new String[] {(String)Oold}));
newlist.add(value);
JSONArray newarr = new JSONArray( newlist );
obj.put(key,newarr);
}
}
return obj.toString();
}

Categories