Search code examples
javapostgresqleclipselinkjsonbconverters

Java object to postgres jsonb conversion


I'm trying to persist java object into jsonb column into Postgres database using eclipselink, but I am stuck at the moment on writing an appropriate converter. Can anyone help me or give me a good example of persisting jsonb types in java with eclipselink?

Here is model code:

@Entity
@Table(name = TABLE_NAME)
public class SystemEventModel implements Serializable {

   public static final String TABLE_NAME = "system_event";

   @Id
   @Column(name = "id")
   private Long id;

   @Lob
   @Column(name = "event_data", columnDefinition = "jsonb")
   private JsonObject eventData;

   public SystemEventModel(JsonObject eventData) {
        this.eventData = eventData;
    }       
}

Currently, I just get the error "ERROR: column "event_data" is of type jsonb but the expression is of type bytea" when I try to persist this object. I'm aware why it is but I don't know how to write a converter since I don't understand in what type should I convert the JsonObject type for it to get passed like jsonb.

Here is what I mean in this converter sample:

@Converter(autoApply = true)
public class AppAttributeTypeAttributeConverter implements AttributeConverter<JsonObject, ???> {

    @Override
    public ??? convertToDatabaseColumn(JsonObject eventData) {
        return ???;
    }

    @Override
    public JsonObject convertToEntityAttribute(??? eventData) {
        return ???;
    }
}

And here is snippet for persisting:

    String details = "{ \"pressed\": \"yes\", \"isDefault\": \"true\", \"type\": \"BUTTON\"}";
    JsonReader jsonReader = Json.createReader(new StringReader(details));
    JsonObject jsonObject = jsonReader.readObject();
    jsonReader.close();
    SystemEventModel eventModel = new SystemEventModel(jsonObject);
    em.persist(eventModel);

Thanks in advance!


Solution

  • Here is what you can do that may work:

    Change

     @Lob
     @Column(name = "event_data", columnDefinition = "jsonb")
     private JsonObject eventData;
    

    to

     @Lob
     @Type(type = "jsonb")
     @Column(name = "event_data", columnDefinition = "jsonb")
     private String eventData;
    
     public SystemEventModel(String eventData) {
        this.eventData = eventData;
     }
    

    Then persist by using this:

    String details = "{ \"pressed\": \"yes\", \"isDefault\": \"true\", \"type\": \"BUTTON\"}";
    SystemEventModel eventModal = new SystemEventModel(details); // or you can use setter method.
    em.persist(eventModel);
    
    

    I hope it helps!!

    Refer How to map a String JPA property to a JSON column using Hibernate

    Thanks...

    EDIT:-

      @Override
      public Object convertToDatabaseColumn(JsonObject eventData) {
        try {
          PGobject out = new PGobject();
          out.setType("json");
          out.setValue(eventData.toString());
          return out;
        } catch (Exception e) {
          throw new IllegalArgumentException("Unable to serialize to json field ", e);
        }
      }
    
      @Override
      public JsonObject convertToEntityAttribute(Object eventData) {
        try {
          if (eventData instanceof PGobject && ((PGobject) eventData).getType().equals("json")) {
            return mapper.reader(new TypeReference<JsonObject>() {
            }).readValue(((PGobject) eventData).getValue());
          }
          return Json.createObjectBuilder().build();
        } catch (IOException e) {
          throw new IllegalArgumentException("Unable to deserialize to json field ", e);
        }
      }
    

    This is the Solution I found for JPA not specifically for hibernate or eclipselink.