Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot entity many to one mappping in embaded object

I am building a simple spring boot blog app. This app has two entities user and post. The user table holds user data and has the primary key as Id and the post table holds content information with user information as a foreign key "postedBy" which refers to the id of user table. One User can have many posts.

Based on this I have designed Entity class like below.

enter image description here

@Entity
@Table
public class User {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String name;
    private String email;
}


@Entity
@Table
public class Post {
    @Id
    @GeneratedValue(generator="system-uuid")
    @GenericGenerator(name="system-uuid", strategy = "uuid")
    private String id;
    private String title;
    @ManyToOne
    @JoinColumn(name = "id" , insertable = false,updatable = false)
    private User postedBy;
    private String content;
}

As a user can have multiple posts I have user @ManyToOne annotation which maps to id of user via @JoinColumn

I am using the JpaRepository interface which is then exposed via rest controller.

But when I send the body to insert post like below

{
    "title":"The Graphql way of design",
    "postedBy":"402880ee73aa45570173aa462ea00001",
    "content":" The content of blog "
}

It throws below error

Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.graphql.blog.model.User` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('402880ee73aa45570173aa462ea00001')
 at [Source: (PushbackInputStream); line: 3, column: 13] (through reference chain: com.graphql.blog.model.Post["postedBy"])]

I was expecting postedBy column will store "402880ee73aa45570173aa462ea00001" as the user already exists and in response, it will send with user details automatically fetching user details for that post.

like image 438
Sumeet Kumar Yadav Avatar asked Aug 01 '20 14:08

Sumeet Kumar Yadav


3 Answers

You are getting the error because a string field can not deserialize into object of User.

I was expecting postedBy column will store "402880ee73aa45570173aa462ea00001" as the user already exists and in response, it will send with user details automatically fetching user details for that post.

No, spring can't do that automatically. To do it first properly deserialize the id by using json like this.

{
    "title":"The Graphql way of design",
    "postedBy":{
                  "id": "402880ee73aa45570173aa462ea00001"
               },
    "content":" The content of blog "
}

Then fetch the User by id first and set in Post, Ex:

Optional<User> user = userRepository.findById(post.getPostedBy.getId());
post.setUser(user.get());

And use @JoinColumn for the field you want to store foreign key for user in post table.

@ManyToOne
@JoinColumn(name = "postedBy")
private User postedBy;
like image 160
Eklavya Avatar answered Oct 06 '22 22:10

Eklavya


As per your requirement, you should put the following code:

In the class, User:

@OneToMany(mappedBy = "postedBy", cascade = CascadeType.DETACH)
private List<Post> posts;

In the class, Post:

@ManyToOne
@JsonIgnore
private User postedBy;
like image 35
Arvind Kumar Avinash Avatar answered Oct 06 '22 23:10

Arvind Kumar Avinash


Add the @JsonIdentityInfo annotation to the User class:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")

Annotation used for indicating that values of annotated type or property should be serializing so that instances either contain additional object identifier (in addition actual object properties), or as a reference that consists of an object id that refers to a full serialization.

like image 1
Nikolas Charalambidis Avatar answered Oct 06 '22 21:10

Nikolas Charalambidis