Open In App

Spring Boot – 415 Unsupported Media Type Error for Post Request for @ManyToMany Relation

Last Updated : 14 May, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Spring Boot is a widely used Java-based framework that simplifies the process of building enterprise applications by providing an opinionated and flexible approach to development. It offers features such as auto-configuration, embedded servers, and a wide range of tools and libraries for building various types of applications. Spring Boot supports different database technologies and easy integration with other popular frameworks and libraries. It is trusted by large tech companies worldwide due to its scalability, efficiency, and ability to meet modern business requirements.

Spring Boot provides convention over configuration, which not only makes development easy but also makes life easy. Spring Data JPA simplifies JPA-based repositories in the Spring Framework, removing the need for manual database queries. It has an inbuilt ORM feature that is handled by Hibernate by default.

In some cases, it’s necessary to map data in a database to achieve a more structured and normalized form. Normalization is a technique used to organize data in a database, which can improve data consistency and reduce data redundancy. By mapping data in a structured manner, it becomes easier to manage and retrieve data from the database. This can be useful for large and complex systems where data needs to be organized efficiently for efficient storage, retrieval, and maintenance.

So to achieve this we are provided with annotations which will basically help us map the tables in the database with the help of our code. Those annotations are as follows:

  1. @OneToOne
  2. @OneToMany
  3. @ManyToOne
  4. @ManyToMany

Bidirectional mappings 1-to-1, 1-to-many, and many-to-1 can be easily saved to a database using Spring Data JPA’s bidirectional mapping support. When working with bidirectional mappings, it’s important to avoid infinite recursion by using the @JsonManagedReference and @JsonBackReference annotations. These annotations help to serialize and deserialize the object graph correctly without causing any issues with the mapping. This makes it easy to work with complex object graphs and ensures that data is saved to the database correctly.

But for the case of Many-Many, if we try to save the data without Jackson bidirectional mapping support we will be able to save the data perfectly, but if we add the support we will be unable to save the data directly and we will encounter some problem like:
(415 Unsupported Media Type)

JSON Response:

{
    "timestamp": "2023-04-09T12:29:59.611+00:00",
    "status": 415,
    "error": "Unsupported Media Type",
    "path": "/save"
}

When using the @ManyToMany annotation in both entities, the serialization and deserialization process can cause problems with bidirectional mapping. In this case, using the @JsonIgnore annotation instead of @JsonBackReference can help prevent issues with serialization, as it tells the system to ignore the property. This way, the entity data can be fetched without any recursion problem. Let’s understand this with an example.

Example

Suppose we have a Student entity and a Course entity, and they are mapped with @ManyToMany as we can have one student for multiple courses and one course can have multiple students,

Student Entity:

Java




@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Student {
  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
  
    private String name;
  
    @Transient private List<Long> cids;
  
    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(name = "stundent_course",
               joinColumns =
                   @JoinColumn(name = "student_id",
                               referencedColumnName = "id"),
               inverseJoinColumns
               = @JoinColumn(name = "course_id",
                             referencedColumnName = "cId"))
    
    @JsonManagedReference
    private List<Course> courses
        = new ArrayList<>();
}


Course Entity:

Java




@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class Course {
  
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long cId;
  
    private String cname;
  
    private Double fee;
  
    @ManyToMany(mappedBy = "courses",
                cascade = CascadeType.ALL)
    @JsonIgnore
    private List<Student> students = new ArrayList<>();
}


Consider this example where a Course entity has a @ManyToMany relationship with a Student entity. When trying to save the Course data, serialization and deserialization can cause issues due to the bidirectional mapping.

To prevent these issues, the @JsonIgnore annotation can be used to ignore the students’ serialization during the process. This means that while saving the Course data, the serialization process will simply ignore the students’ data and avoid any potential recursion problems. After doing this we can directly save the data and fetch the data from students like this:

Controller Code:

Java




@RestController
public class StudentRestController {
  
    // We have used JpaRepository 
    // for database operations
    @Autowired
    private StudentRepository repo; 
  
    @PostMapping("/save")
    public ResponseEntity<?>
    save(@RequestBody Student student)
    {
  
        student = repo.save(student);
        return new ResponseEntity<>(student,
                                    HttpStatus.CREATED);
    }
  
    @GetMapping("/findAll") public List<Student> findAll()
    {
        return repo.findAll();
    }
}


This will work.



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads