skip to Main Content

I am getting a type error on a POST controller when I try to send data to it. The error seems to be clear but the solution is escaping me:

Enviroment

Spring Boot 3.1
Java 18
MySQL8

Entity

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@ToString
@Entity
@SequenceGenerator(name = "bird_seq", sequenceName = "BIRD_SEQ", initialValue = 100, allocationSize = 50)
@Table(name = "bird")
public class Bird {

@Id
@GeneratedValue(strategy = SEQUENCE, generator = "bird_seq")
private Long id;
@Column(unique = true)
@NotEmpty
private String name;
@Enumerated(EnumType.STRING)
private Sex sex;

@OneToOne(optional = true)
@Fetch(FetchMode.JOIN)
@JoinColumn(name = "current_transmitter_id", nullable = true)
private Transmitter currentTransmitter;

@JsonBackReference
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
private List<ChickTimer> listChickTimer = new ArrayList<>();

// other fields trimmed

// single property constructor to support testing 

    public Bird(String name) {
    this.name = name;
}

Controller

@RestController
@RequestMapping("/birds")
@RequiredArgsConstructor
public class KiwiController {

    @Autowired
    private final BirdServiceImpl birdService;

    // tried with and without the consumes/produces
    // also tried consumes = "application/json"
    @PostMapping(value = "/testpost/", consumes = (MediaType.APPLICATION_JSON_VALUE), produces = (MediaType.APPLICATION_JSON_VALUE) )
    ResponseEntity<Bird> BirdCreate(@RequestBody Bird newBird) {
    Bird bird = birdService.save(newBird);
    return new ResponseEntity<>(bird, HttpStatus.CREATED);
}

Unsupported Media Type – Error

{
"timestamp": "2023-09-11T18:29:23.830+00:00",
"status": 415,
"error": "Unsupported Media Type",
"trace": "org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type 'application/json;charset=UTF-8' is not supportedrntat org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodArgumentResolver.readWithMessageConverters(AbstractMessageConverterMethodArgumentResolver.java:209)rntat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.readWithMessageConverters(RequestResponseBodyMethodProcessor.java:163)rntat org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:136)rntat org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:122)rntat org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:179)rntat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:146)rntat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)rntat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:884)rntat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)rntat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)rntat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1081)rntat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:974)rntat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1011)rntat org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914)rntat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:590)rntat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)rntat jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:205)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)rntat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)rntat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)rntat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)rntat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)rntat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)rntat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:174)rntat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:149)rntat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:166)rntat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)rntat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:482)rntat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)rntat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)rntat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)rntat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:341)rntat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:391)rntat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)rntat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:894)rntat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1740)rntat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)rntat org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)rntat org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)rntat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)rntat java.base/java.lang.Thread.run(Thread.java:833)rn",
"message": "Content-Type 'application/json;charset=UTF-8' is not supported.",
"path": "/birds/testpost/"

}

Postman

enter image description here
enter image description here

Steps Taken So Far

  1. I have another controller on same project working fine (it doesnt even specify media type)

  2. Tried with @PostMapping(value = "/testpost/", consumes = (MediaType.APPLICATION_JSON_VALUE), produces = (MediaType.APPLICATION_JSON_VALUE) ) and consumes = "application/json"

  3. Changed the controller to use another Class I have for Testing – it worked with the test Class

  4. Tried to set a breakpoint on the controller on this line Bird bird = birdService.save(newBird); but it never gets reached

  5. Tried manually addding "Accept":"application/json" to postman instead of */*

  6. Tried curl :

    curl -X POST http://localhost:8080/birds/testpost/ –header "Content-Type:application/json" -d ‘{"name":"bob"}’
    {"timestamp":"2023-09-11T09:58:02.903+00:00","status":415,"error":"Unsupported Media Type","trace":"org.springframework.web.HttpMediaTypeNotSupportedException: Content-Type ‘application/json;charset=UTF-8’ is not supported

The controller that does work is as simple as:

    @PostMapping(value = "/")
ResponseEntity<Pit> newPIT(@RequestBody PitDto pitDto) {
    Pit createdPit = pitMapper.toEntity(pitDto);
     // some service layer stuff
    Pit savedPit = pitService.savePIT(createdPit);
    return ResponseEntity.ok().body(savedPit);
}

I don’t even set the application type in that controller (however it does use Dto).

I am out of idea’s but suspect something on the entity since the test entity works in that controller.

Update

After creating a new branch to create a Minimal, Reproducible Example the controller worked. So I changed back to master, last commit, and began to remove the properties.

The field causing a issue is HealthCheck – here is that class:

@NoArgsConstructor
@ToString
@Entity
@Data
@JsonIgnoreProperties({"hibernateLazyInitalizer", "handler"})
@SequenceGenerator(name = "health_check_seq", sequenceName = "HEALTH_CHECK_SEQ", initialValue = 100, allocationSize = 50)
@Table(name = "health_check")
public class HealthCheck {

@Id
@GeneratedValue(strategy = SEQUENCE, generator = "health_check_seq")
private Long id;

@ManyToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "bird_id")
private Bird bird;

@JsonFormat(pattern = "yyyy-MM-dd HH:mm")
private LocalDateTime catchDateTime;

3

Answers


  1. Chosen as BEST ANSWER

    The answer in this case was to do with related/nested entities and the annotations on them for serialization/deserialization (Jackson).

    On the bird class there was:

    @JsonBackReference
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
    private List<ChickTimer> listChickTimer = new ArrayList<>();
    
    @JsonBackReference
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
    private List<Otherclass> listOtherclass = new ArrayList<>();
    

    In order to fix two properties with @JsonBackReference I named them:

    @JsonBackReference(value = "bird-chicktimer")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
    private List<ChickTimer> listChickTimer = new ArrayList<>();
    
    @JsonBackReference(value = "bird-otherclass")
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "bird")
    private List<Otherclass> listOtherclass = new ArrayList<>();
    

    I also had a BackReference on the Many side on one of the classes which I changed to @JsonManagedReference.

    The application/json error message was a red herring.


  2. Remove all MediaType.APPLICATION_JSON_VALUE because it is a A String equivalent of APPLICATION_JSON, according to documentation or if you dont want to remove it just replace it to MediaType.APPLICATION_JSON. Why so ? because i can see in postman you do request to controller with json object not json as string

    And also be sure that you dont do request with Content-Type 'application/json;charset=UTF-8 just do it without utf-8

    Also update i see that you also have in one entity mappedBy = "bird" two time on different fields, can you change one with another name something like mappedBy = "secondBird"

    Login or Signup to reply.
  3. Your Bird class doesn’t have default constructor without parameters. I think Sprig has trouble deserializing your JSON to Bird class because of it. It is a guess, but worth trying. Add

    public Bird() {
    }
    

    To your class Bird or just remove your constructor

        public Bird(String name) {
        this.name = name;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search