Home > database >  getting null value from @Requestbody
getting null value from @Requestbody

Time:08-09

I am in the process of adding a DTO layer to a restful api. Before, the program used entity (Recipe and Ingredient) directly and now I added a new DTO layer in between (RecipeDTO IngredientDTO). However, the moment I made the change I started getting Null values from @RequestBody. Each recipe contains a list of Ingredients and it is the list of ingredients that are returning null values, the recipe by itself is returning fine.

The controller looks like this

package com.example.recipes.controller;
import com.example.recipes.DTO.RecipeDTO;
import com.example.recipes.Service.RecipeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/*...*/
    @PostMapping(path = "/post")
    public void postRecipes(@RequestBody RecipeDTO recipeDTO){
        recipeService.postRecipes(recipeDTO);
    }
/*...*/

Recipe Entity

package com.example.recipes.Entity;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;

@Data
@Entity
@Table(name = "recipe", schema = "public")
@AllArgsConstructor
@NoArgsConstructor
public class Recipe {
    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @Column(name = "id", updatable = false, nullable = false)
    private long id;
    @Column(name = "name")
    private String name;
    @Column(name = "instructions")
    private String instructions;
    @OneToMany(mappedBy = "recipe")
    private List<Ingredient> ingredients;
    @JsonProperty("date_added")
    private String dateAdded = String.valueOf(LocalDateTime.now());
    @JsonProperty("last_edited")
    private String lastEdited = String.valueOf(LocalDateTime.now());
}

RecipeDTO

package com.example.recipes.DTO;
import lombok.*;

import javax.persistence.OneToMany;
import java.time.LocalDateTime;
import java.util.List;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
public class RecipeDTO {
    private long id;
    private String name;
    private String instructions;
    private List<IngredientDTO> ingredientsDTO;
    private String dateAdded = String.valueOf(LocalDateTime.now());
    private String lastEdited = String.valueOf(LocalDateTime.now());

    public RecipeDTO(long id, String name, String instructions, String dateAdded, String lastEdited) {
        this.id = id;
        this.name = name;
        this.instructions = instructions;
        this.dateAdded = dateAdded;
        this.lastEdited = lastEdited;
    }
}

Ingredient Entity

package com.example.recipes.Entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
@Data
@Entity
@Table(name = "Ingredient")
@NoArgsConstructor
public class Ingredient {
    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @JsonProperty("ingredient_id")
    private long ingredient_ID;
    @JsonProperty("ingredient_name")
    private String ingredientName;
    @Column(name = "amount")
    private int amount;
    @Column(name = "unit")
    private String unit;
    @ManyToOne
    @JoinColumn(name = "recipe_id")
    @ToString.Exclude
    @JsonIgnore
    private Recipe recipe;
}

IngredientDTO

package com.example.recipes.DTO;
import lombok.*;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class IngredientDTO {
    private long ingredientID;
    private String ingredientName;
    private int amount;
    private String unit;
}

the json i sent

{
    "name":"unique2",
    "ingredients":[
        {
            "ingredient_name":"Atlantic",
            "amount":13, 
            "unit":"ton"
        },
        {
            "ingredient_name":"Pacific",
            "amount":15, 
            "unit":"boatload"
        },
        {
            "ingredient_name":"Indian",
            "amount":38, 
            "unit":"trucload"
        }
    ],
    "instructions":"easy on the salt"
}

and the @requestbody the ingredientsDTO is null

this is recipe: RecipeDTO(id=0, name=unique2, instructions=easy on the salt, ingredientsDTO=null, dateAdded=2022-08-08T15:04:10.678748100, lastEdited=2022-08-08T15:04:10.678748100)

Edit: I have just tried copying the code from the entity classes and pasting them in the DTO classes and it still returning null...

package com.example.recipes.DTO;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;

@Data
@Entity
@Table(name = "recipe", schema = "public")
@AllArgsConstructor
@NoArgsConstructor
public class RecipeDTO {
    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @Column(name = "id", updatable = false, nullable = false)
    private long id;
    @Column(name = "name")
    private String name;
    @Column(name = "instructions")
    private String instructions;
    @OneToMany(mappedBy = "recipeDTO")
    private List<IngredientDTO> ingredientDTOs;
    @JsonProperty("date_added")
    private String dateAdded = String.valueOf(LocalDateTime.now());
    @JsonProperty("last_edited")
    private String lastEdited = String.valueOf(LocalDateTime.now());

    public RecipeDTO(long id, String name, String instructions, String dateAdded, String lastEdited) {
        this.id = id;
        this.name = name;
        this.instructions = instructions;
        this.dateAdded = dateAdded;
        this.lastEdited = lastEdited;
    }
}

package com.example.recipes.DTO;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
@Data
@Entity
@Table(name = "Ingredient")
@NoArgsConstructor
public class IngredientDTO {
    @Id
    @GeneratedValue(
            strategy = GenerationType.IDENTITY
    )
    @JsonProperty("ingredient_id")
    private long ingredientID;
    @JsonProperty("ingredient_name")
    private String ingredientName;
    @Column(name = "amount")
    private int amount;
    @Column(name = "unit")
    private String unit;
    @ManyToOne
    @JoinColumn(name = "recipe_id")
    @ToString.Exclude
    @JsonIgnore
    private RecipeDTO recipeDTO;

    public IngredientDTO(long ingredientID, String ingredientName, int amount, String unit) {
        this.ingredientID = ingredientID;
        this.ingredientName = ingredientName;
        this.amount = amount;
        this.unit = unit;
    }
}

@RequestBody

this is recipe: RecipeDTO(id=0, name=unique2, instructions=easy on the salt, ingredientDTOs=null, dateAdded=2022-08-08T15:24:19.325806500, lastEdited=2022-08-08T15:24:19.325806500)
these are the ingredients: null
this is ingredientDTO: null
this is ingredientDTO: null

Edit2: I tried posting only the ingredientDTO and the @RequestBody was able to pick it up just fine

//this is fine
    public void testRecipePost(@RequestBody IngredientDTO ingredientDTO) {
        System.out.println("ingredientDTO: "   ingredientDTO);
    }

CodePudding user response:

You can replace

@OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;

to

@OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredients;

Or adding

@JsonProperty("ingredients")

Example:

@JsonProperty("ingredients")
@OneToMany(mappedBy = "recipeDTO")
private List<IngredientDTO> ingredientDTOs;

The reason for null is because Jackson doesn't know how to deserialise your fields properly with different names.

CodePudding user response:

In the json, the name is ingredients but, in the DTO, it is ingredientsDTO. Those 2 need to match.

CodePudding user response:

You request

{
    "name":"unique2",
    "ingredients":[...]

here the name of array you are passing in Json is different in the entity you are using.

Your DTO

 @OneToMany(mappedBy = "recipeDTO")
    private List<IngredientDTO> ingredientDTOs;

The name of fields in JSON request and Entity must match.

Change the name of field private List<IngredientDTO> ingredientDTOs; to ingredients.

  • Related