Search code examples
javajsonjpagson

Parsing JSON data with GSON into a model with JPA persistence


I need to parse JSON data received from an external API and persist it using JPA annotations. I used GSON as the parser, along with a TypeAdapter, because the model has the following simplified structure:

test.json:

{
"workID": 12355,
"contributors":
[
    {
      "fullName": "UNKNOWN 1",
      "workContributorID": 1100933315,
      "workID": 12355
    },
    {
      "fullName": "UNKNOWN 2",
      "workContributorID": 1100933314,
      "workID": 12355
    }
]
}

Contributor.java:

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name = "contributor")
public class Contributor {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long workContributorID;

    private String fullName;

    @ManyToOne
    @JoinColumn(name = "work_id", referencedColumnName = "id")
    private WorkSP workID;
}

WorkSP.java:

import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;

@Getter
@Setter
@Entity
@Table(name = "work_sp")
public class WorkSP {
    @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private long workID;
    private ArrayList<Contributor> contributors;


    public WorkSP(long asLong) {
        this.workID = asLong;
    }
}

The test class:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializer;
import com.google.gson.stream.JsonReader;

import java.io.FileNotFoundException;
import java.io.FileReader;

public class App 
{
    public static void main( String[] args ) throws FileNotFoundException {
        JsonReader readerTest = new JsonReader(new FileReader("test.json"));
        Gson gSonInstance = new GsonBuilder().
                registerTypeAdapter(WorkSP.class, (JsonDeserializer<WorkSP>) (json, type, jsonDeserializationContext) -> {
                return new WorkSP(json.getAsJsonObject().getAsLong());
                }).
                create();
        WorkSP work = gSonInstance.fromJson(readerTest, WorkSP.class);


    }
}

the followinf outpur is obtained:

Exception in thread "main" java.lang.UnsupportedOperationException: JsonObject
    at com.google.gson.JsonElement.getAsLong(JsonElement.java:294)
    at org.example.App.lambda$main$0(App.java:21)
    at com.google.gson.internal.bind.TreeTypeAdapter.read(TreeTypeAdapter.java:95)
    at com.google.gson.Gson.fromJson(Gson.java:1361)
    at com.google.gson.Gson.fromJson(Gson.java:1306)
    at org.example.App.main(App.java:24)

I suppose that jsonDeserializationContext from JsonDeserializer might be able to parse WorkSP objects based on whether they belong to Contributor.class or WorkSP.class, but I'm not sure how to do it.


Solution

  • The error you are getting is because - new WorkSP(json.getAsJsonObject().getAsLong()) this line will try convert the WorkSP JsonObject itself to long. You should instead first get workID from WorkSP by doing json.getAsJsonObject().get("workID").getAsLong().

    Following changes in the code should convert the whole Json in the WorkSP Object.

    1. Create @AllArgsConstructor in the Contributor class.

    public static void main(String[] args) throws FileNotFoundException {
        JsonReader readerTest = new JsonReader(new FileReader("test.json"));
        Gson gSonInstance = new GsonBuilder().
                registerTypeAdapter(WorkSP.class, (JsonDeserializer<WorkSP>) (json, type, jsonDeserializationContext) -> {
                    JsonObject workSPJson = json.getAsJsonObject();
                    long workID = workSPJson.get("workID").getAsLong();
                    WorkSP workSP = new WorkSP(workID);
                    List<Contributor> contributors = new ArrayList<>();
                    for(JsonElement contributor: workSPJson.getAsJsonArray("contributors")){
                        JsonObject contributorJson = contributor.getAsJsonObject();
                        String fullName = contributorJson.get("fullName").getAsString();
                        long workContributorID = contributorJson.get("workContributorID").getAsLong();
                        contributors.add(new Contributor(workContributorID, fullName, workSP));
                    }
                    workSP.setContributors(contributors);
                    return workSP;
                }).
                create();
        WorkSP work = gSonInstance.fromJson(readerTest, WorkSP.class);
    }