javajsonmongodbjacksonmorphia

How to convert JSON of JSONs to array of JSONs in Java?


I've been running into some issues on a personal project of mine. I fetch the data field from the url: http://ddragon.leagueoflegends.com/cdn/13.15.1/data/en_US/champion.json with the following code:

import DataHandlers.ChampionsJson;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.util.concurrent.ExecutionException;


public class ChampionsDataScheduler extends Thread{
    @Override
    public void run(){
        while(true){

            try {
                var client = HttpClient.newHttpClient();

                var request = HttpRequest.newBuilder(
                                URI.create("http://ddragon.leagueoflegends.com/cdn/13.15.1/data/en_US/champion.json"))
                        .header("accept", "application/json")
                        .build();

                var responseFuture = client.sendAsync(request, new JsonBodyHandler<>(ChampionsJson.class));
                var response = responseFuture.get();
                var data = response.body().get().championsData;

                System.out.println(data);
                Thread.sleep(1000);

            } catch (InterruptedException | ExecutionException e) {
                throw new RuntimeException(e);
            }


        }
    }
}

Using this class:

package DataHandlers;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;

import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ChampionsJson {
    public final JsonNode championsData;

    @JsonIgnoreProperties(ignoreUnknown = true)
    public ChampionsJson(@JsonProperty("data") JsonNode championsData) {
        this.championsData = championsData;
    }
}

I'm trying to inject each champion (each value in the received json) to the following object and create an array of it:

package DataHandlers;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public class ChampionsData {
    public final String id;
    public final String name;
    public final String blurb;
    public final List image;
    public final String title;

    @JsonIgnoreProperties(ignoreUnknown = true)
    public ChampionsData(@JsonProperty("id") String id,
                @JsonProperty("name") String name,
                @JsonProperty("blurb") String blurb,
                @JsonProperty("image") List image,
                @JsonProperty("title") String title) {
        this.id = id;
        this.name = name;
        this.title = title;
        this.blurb = blurb;
        this.image = image;
    }


}

but I fail to do so because I get the JSON as a string of JSONs, and I haven't figured out a way to parse it correctly. Any idea how to do that? Is there maybe a better way to do so?

If you want to get more context on it, my final goal is to convert the ChampionsData object array to a morphia object array and insert it into Mongo.


Solution

  • The data at http://ddragon.leagueoflegends.com/cdn/13.15.1/data/en_US/champion.json is a single JSON object with a single key data. data is an object with approx 164 subfields, each of which appears to be the name of a champion. There are no arrays; you must iterate over the data field.

    If the goal is to insert this data into MongoDB, then I recommend making each champion a separate document. The subfields carry a lot of identifying information like name,key, and id so let's keep that and let MongoDB client side driver invent the _id.

    The OQ code attempts to take image and store it as a list. image from the JSON is not a list; it is an object (a substructure). In the code below, we will copy over the whole image object into the Document to be inserted.

    // The OQ code to fetch the JSON is directionally correct.   It results in 
    // the JSON string being stored in variable `data` and sort of trapped in
    // the thread but the approach is fine.  The details of organizing the
    // code to schedule and fetch the data are not relevant to the question.
    
    ObjectMapper mapper = new ObjectMapper(); 
    
    //  OP has JSON string somewhere in the mix of @championsData; not sure
    //  how it is wired together but the goal is the same: to parse the
    //  JSON into a Java Map object using mapper.  As a proxy, we show
    //  readValue() from a file here:
    Map<String,Object> content = mapper.readValue(new File(fileName), Map.class);
    
    String host = "mongodb://your_connection_uri";
    MongoClient client = MongoClients.create(host);
    MongoDatabase db = client.getDatabase("testX");
    MongoCollection<Document> coll = db.getCollection("foo", Document.class);
    
    java.util.Map data = (java.util.Map) content.get("data");
          
    data.forEach(
                 (key, value)
                 -> {
                     //  Use this to deep copy all fields for each champion:             
                     //Document dd = new Document((Map)value);                           
    
                     // .. or this to only pick up select items:                         
                     Document dd = new Document();
                     Map m = (Map)value;
                     for(String k2 : new String[]{"name","blurb","title","image"}) {
                         dd.put(k2, m.get(k2));
                     }
                     coll.insertOne(dd);
                 });