Search code examples
javahibernatejacksonquarkusquarkus-panache

Jackson Hibernate relationship by id


Note: I unfortunately don't really have an idea of what library my problem concerns, if you need any further information please just write a comment!

I have two hibernate panache entity classes declared like this:

@Entity
public class FirstObj extends PanacheEntity {
  @ManyToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "secondobj_id", referencedColumnName = "id")
  public SecondObj secondObj;
  public String name;
}

@Entity
public class SecondObj extends PanacheEntity {
  public String name;
  public int weight;
}

And I want to be able to deserialize this object with this json (deserialized by jackson, assuming there's an entry in the SecondObj table with the id 1):

{
  "name": "hello",
  "secondObj": 1
}

Is this possible? I don't want it to automatically create a new SecondObj entity on requests.


Solution

  • I recommend achieving this using the DTO pattern. When applied to your example, in addition to

    @Entity
    public class FirstObj extends PanacheEntity {
      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "secondobj_id", referencedColumnName = "id")
      public SecondObj secondObj;
      public String name;
    }
    

    You will have another class -

    public class FirstObjDTO extends PanacheDTO {
      public String name;
      public long secondObjId;
    }
    

    From that point you can use a mapping library or a mapping function to map FirstObj.secondObj.id to FirstObjDTO.secondObjId prior to serialization.

    Example mapping function:

    FirstObjDTO toFirstObjDto(FirstObj from) {
      FirstObjDTO dto = new FirstObjDTO();
      dto.setName(from.getName());
      if (from.getSecondObj() != null) {
        dto.setSecondObjId(from.getSecondObj().getId());
      }
      return dto;
    }
    

    You can also use a mapping library, one such library is ShapeShift. (Disclaimer: I am a contributor to ShapeShift)

    Mapping example

    @Entity
    public class FirstObj extends PanacheEntity {
      @MappedField(target = FirstObjDTO.class, mapFrom = "id", mapTo = "secondObjId")
      @ManyToOne(cascade = CascadeType.ALL)
      @JoinColumn(name = "secondobj_id", referencedColumnName = "id")
      public SecondObj secondObj;
    
      @MappedField(target = FirstObjDTO.class)
      public String name;
    }
    

    Then wherever you intend to perform this mapping:

    ShapeShift shapeShift = ShapeShift();
    FirstObjDTO firstObjDTO = shapeShift.map(firstObj, FirstObjDTO.class);