Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch parent-id in a bidirectional hibernate mapping

I have a spring rest application with two entities with a bidirectional relationshop (one-to-many, many to one). To overcome nested fetching issues, @JsonManagedReference/@JsonBackReference has been used for a perent/child relationship between entities.

The entites look as this:

@Entity
@Table(name = "Parent")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Parent implements java.io.Serializable {

    private Integer id;
    private List<Child> childList;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "ID", unique = true, nullable = false)
    public Integer getId() {
        return this.id;
    }
    public void setId(Integer id) {
        this.id = id;
    }

    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    @JsonManagedReference
    public List<Child> getChildList() {
        return childList;
    }

    public void setChildListe(List<Child> childListe) {
            this.childList = childList;
        }

    }


@Entity
@Table(name = "Child")
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Child implements java.io.Serializable {


    private Integer id;
    private Parent parent;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "ID", unique = true, nullable = false)
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ParentID")
    @JsonBackReference
    public Parent getParent() {
        return parent;
    }

    public void setParent(Parent parent) {
        this.parent = parent;
    }


}

This works fine when fetching the Parent element, the childset is then fetched alongside and displayed as an json-array.

However, there is no reference to parent in the child element due to the usage of jsonbackreferance.

I would like to either get the parent object attached to the child-elemens in the json response, or at least fetch the parent id, when requesting for a singlle child element through rest.

All feedback will be appriciated :)

like image 593
user878980 Avatar asked Nov 07 '22 21:11

user878980


1 Answers

I had a similar issue and I solved it by using custom serializer/deserializer

This is how I procedeed (please adapt it to your own code):

ChildSerializer

public class ChildSerializer extends StdSerializer<Child> {

    private static final long serialVersionUID = -265706839304575646L;
    public ChildSerializer(Class<Child> t) {
        super(t);
    }
    public ChildSerializer() {
        this(null);
    }
    @Override
    public void serialize(Child child, JsonGenerator jg, SerializerProvider sp)
            throws IOException, JsonGenerationException {

        jg.writeStartObject();
        jg.writeStringField("name", child.getName());
        jg.writeStringField("surname", child.getSurname());
        Parent parent = child.getParent();
        jg.writeObjectFieldStart("parent");
        jg.writeStringField("name", parent.getName());
        jg.writeStringField("surname", parent.getSurname());
        jg.writeEndObject();
    }
}

Child

@JsonSerialize(using = ChildSerializer.class)
public class Child implements Serializable {

    private static final long serialVersionUID = 7902561110976676934L;
    private String name;
    private String surname;
    private Parent parent;

    public Child(String name, String surname, Parent parent) {
        this(name, surname);
        this.parent = parent;
    }
    public Child(String name, String surname) {
        this();
        this.name = name;
        this.surname = surname;
    }
    public Child() {
        super();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSurname() {
        return surname;
    }
    public void setSurname(String surname) {
        this.surname = surname;
    }
    public Parent getParent() {
        return parent;
    }
    public void setParent(Parent parent) {
        this.parent = parent;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + ((parent == null) ? 0 : parent.hashCode());
        result = prime * result + ((surname == null) ? 0 : surname.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Child other = (Child) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (parent == null) {
            if (other.parent != null)
                return false;
        } else if (!parent.equals(other.parent))
            return false;
        if (surname == null) {
            if (other.surname != null)
                return false;
        } else if (!surname.equals(other.surname))
            return false;
        return true;
    }
}

Parent

public class Parent implements Serializable {

    private static final long serialVersionUID = -5604725691780073247L;
    private String name;
    private String surname;
    private List<Child> childs;

    public Parent(String name, String surname) {
        this();
        this.name = name;
        this.surname = surname;
    }
    public Parent(String name, String surname, List<Child> childs) {
        this(name, surname);

        this.childs = childs;
    }
    public Parent() {
        super();
        childs = new ArrayList<Child>();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSurname() {
        return surname;
    }
    public void setSurname(String surname) {
        this.surname = surname;
    }
    public void addChild( Child child )
    {
        if( !childs.contains(child) )
        {
            child.setParent(this);
            childs.add(child);
        }
    }
    public List<Child> getChilds() {
        return childs;
    }
    public void setChilds(List<Child> childs) {
        this.childs = childs;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((childs == null) ? 0 : childs.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + ((surname == null) ? 0 : surname.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Parent other = (Parent) obj;
        if (childs == null) {
            if (other.childs != null)
                return false;
        } else if (!childs.equals(other.childs))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (surname == null) {
            if (other.surname != null)
                return false;
        } else if (!surname.equals(other.surname))
            return false;
        return true;
    }

}

My test method:

@Test
public void testJson()
{
    try 
    {
        Parent p = new Parent(UUID.randomUUID().toString(), UUID.randomUUID().toString());
        for (int i = 0; i < 10; i++) {
            p.addChild(new Child(UUID.randomUUID().toString(), UUID.randomUUID().toString()));
        }
        ObjectMapper om = new ObjectMapper();
        String childJson = om.writeValueAsString(p.getChilds().get(0));
        System.out.println(childJson);
    } catch (Exception e) 
    {
        e.printStackTrace();
    }
}

The final output was:

{"name":"b86eab86-9858-4536-9c5c-d44d22810fc1","surname":"9a6249f0-58df-44e5-a1b9-31fbad6e9f49","parent":{"name":"74b0cd97-64a1-4547-ab22-4e4eedd0759b","surname":"a33c79f3-6f26-478b-9e24-7df96b3b1f68"}}

Sadly annotation are powerfull but not always they allow to you to obtain what you need and so you have to do it "by yourself"

I hope this can be usefull

like image 106
Angelo Immediata Avatar answered Nov 15 '22 06:11

Angelo Immediata