[SOLVED] Many-To-One : JSON parse error Cannot construct instance

Issue

I devleloping a REST API using spring boot
I have two entities with bidirectional OneToMany

Product class

public class Product {

    private Long productId;
    private String name;
    private String description;
    private List<ProductList> productList;


    public Product() {
    }


    public Product(Long productId, String name, String description, List<ProductList> productList) {
        this.productId = productId;
        this.name = name;
        this.description = description;
        this.productList = productList;
    }


    public Long getProductId() {
        return productId;
    }

    public void setProductId(Long productId) {
        this.productId = productId;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<ProductList> getProductList() {
        return productList;
    }

    public void setProductList(List<ProductList> productList) {

        this.productList = productList;
    }

ProductList class

public class ProductList {

    private Long productListId;
    private String productListName;
    private Product product;


    public ProductList(Long productListId, String productListName, Product product) {
        this.productListId = productListId;
        this.productListName = productListName;
        this.product = product;
    }


    public ProductList() {
    }


    public Long getProductListId() {
        return productListId;
    }

    public void setProductListId(Long productListId) {
        this.productListId = productListId;
    }

    public String getProductListName() {
        return productListName;
    }

    public void setProductListName(String productListName) {
        this.productListName = productListName;
    }

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }
}

ProductEntity class:

@Entity
@Data
@Table(name = "PRODUCT")

public class ProductEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer productId;

@Column
private String name;

@Column
private String description;

@OneToMany(cascade = CascadeType.ALL, mappedBy="product", fetch = 
FetchType.EAGER)
private List<ProductListEntity> productList;
// Getters,Setters,No-ArgCOnstructor, All-ArgConstructor

ProductListEntity class:

@Table
@Entity
@Data
public class ProductListEntity {


@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long productListId;
private String productListName;


@ManyToOne(fetch = FetchType.EAGER, targetEntity = ProductEntity.class)
@JoinColumn(name = "FK_Product", referencedColumnName = "productId")
private ProductEntity product;

Service to save data:

public void addProduct(Product product) {
    ProductEntity productEntity = new ProductEntity();
    BeanUtils.copyProperties(product, productEntity);
    productRepository.save(productEntity);
}

When i try to post I get this error:

"message": "JSON parse error: Cannot construct instance of
eteosf.hexagonal.domain.model.Product (although at least one Creator
exists): no String-argument constructor/factory method to deserialize
from String value (‘string’); nested exception is
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot
construct instance of eteosf.hexagonal.domain.model.Product
(although at least one Creator exists): no String-argument
constructor/factory method to deserialize from String value
(‘string’)\n at [Source: (PushbackInputStream); line: 9, column: 18]
(through reference chain:
eteosf.hexagonal.domain.model.Product["productList"]->java.util.ArrayList[0]->eteosf.hexagonal.domain.model.Product$ProductList["product"])",
"path": "/product"

JSON request body:

{
  "productId": 0,
  "name": "string",
  "description": "string",
  "productList": [
    {
      "productListId": 0,
      "productListName": "string",
      "product": "string"
    }
  ]
}

Solution

in your json_request, inside of productList you are sending "product" as a "string". But Deserializer can not turn that string into a Product object. It has to be sent as object {}. You can leave that object empty – just not send it if all it does is point at itself.

You basically have made a mistake of confusing different principles – the whole bidirectional relationship is only to be applied at persistence level. Json requests are being sent at controller/view level and therefore you can’t display the bidirectional nature in the same way. This is why you don’t use Entities as controller params but use DTOs.

In your case just don’t send the "product" field for the controller:

{
  "productId": 0,
  "name": "string",
  "description": "string",
  "productList": [
    {
      "productListId": 0,
      "productListName": "string",
    }
  ]
}

and just add it in the controller method right after receiving the parameter:

//the receiving controller method which got Parameter `ProductEntity product`
product.getProductList().forEach(productList -> productList.setProduct(product);

Like I said you shouldn’t use entities in Controller method, and it should be a DTO class in order to avoid exactly this kind of issues

Answered By – J Asgarov

Answer Checked By – Marilyn (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published.