Home > Software engineering >  @Requestbody mapping to inherited subclass
@Requestbody mapping to inherited subclass

Time:06-30

I have a class Vehicle in my Java Program. The class Cab inherits from Vehicle.

In my controller I have a post mapping for adding new cabs to the Vehicles array.

@PostMapping("/vehicles/add/cab")
public void addCab(@RequestBody Cab cab) {
    System.out.println(cab);
    cc.addVehicle(cab);
}

The contractor of Cab looks like this.

public Cab(String licensePlate, double basePricePerKm, double horsePower)

I tried printing the Object in the RequestBody to the console, it had all the properties of the constructor

{
"licensePlate": "GR-221CH",
"basePricePerKm": 3.0,
"horsePower": 25.5
}

However I get an error

JSON parse error: Cannot construct instance of com.example.demo3.Cab.Cab

How do I do it right/resolve this error?

CodePudding user response:

It sounds like your controller consumes application/json. So behind the scenes, by default Spring is attempting to use Jackson Databind to map fields into your Cab object. Databind has requirements for how the class is written to allow values to be bound to objects.

In the simplest case, you're writing a POJO:

  • Add a public default (no-arg) constructor. You can still have additional constructors if they suit your purposes, e.g. test fixturing.
  • Add public getters and setters. (Jackson can also bind to a public field.)

By default, Jackson will find setters from Cab and its Vehicle superclass (and any other classes above that). So if the three POJO properties you've listed really belong to Vehicle, they should get bound there, all without using your 3-arg constructor. Then you can add Cab-specific properties to Cab, also using property binding.

There are a bunch of annotations you can use to customize how values are bound, e.g. mapping differing JSON attribute names to your POJO properties, or ignoring certain properties.

See jackson-databind for details. There is even a way to map JSON values into a constructor, though I personally wouldn't use it -- yet another thing to maintain if the object model changes, especially when inheritance is a factor.

In the case that your body isn't JSON, Spring has several other HttpMessageConverter implementations, which of course are configurable. See Spring's Rest Message Conversion docs.

CodePudding user response:

You need to include the default constructor in your Cab class. Jackson requires this to construct the object using reflection.

public class Cab {

    // add this constructor
    public Cab() {}

}
  • Related