11

In the REST endpoint I'm building in Spring Boot, I'm trying to pass my vehicleDTO to my controller. But before it reaches my controller, there is an error.

InvalidDefinitionException: Cannot construct instance of com.vehicle.datatransferobject.VehicleDTO (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

vehicleDTO

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.myvehicle.EngineType;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class VehicleDTO {

    @JsonIgnore
    private Long id;

    @NotNull(message = "vehiclenumber can not be null!")
    private String vehiclenumber;

    @Min(2)
    @NotNull(message = "Seat count can not be less than 2!")
    private Integer vehicleseatcount;

    @NotNull(message = "Engine Type can not be null!")
    private EngineType enginetype;

    @Max(5)
    private Integer vehiclerating;



    private VehicleDTO(Long id, String vehiclenumber, Integer vehicleseatcount, EngineType enginetype,Integer vehiclerating){
        this.vehiclenumber=vehiclenumber;
        this.vehicleseatcount=vehicleseatcount;
        this.enginetype=enginetype;
        this.vehiclerating=vehiclerating;
        this.id=id;
    }

    public static VehicleDTOBuilder newBuilder()
    {
        return new VehicleDTOBuilder();
    }

    @JsonProperty
    public Long getId() {
        return id;
    }


    public String getvehiclenumber() {
        return vehiclenumber;
    }


    public Integer getvehicleseatcount() {
        return vehicleseatcount;
    }


    public EngineType getEnginetype() {
        return enginetype;
    }



    public Integer getvehiclerating() {
        return vehiclerating;
    }




    public static class VehicleDTOBuilder{

        private Long id;
        private String vehiclenumber;
        private Integer vehicleseatcount;
        private EngineType enginetype;
        private Integer vehiclerating;

        public VehicleDTOBuilder setId(Long id) {
            this.id = id;
            return this;
        }
        public VehicleDTOBuilder setvehiclenumber(String vehiclenumber) {
            this.vehiclenumber = vehiclenumber;
            return this;
        }
        public VehicleDTOBuilder setvehicleseatcount(Integer vehicleseatcount) {
            this.vehicleseatcount = vehicleseatcount;
            return this;
        }
        public VehicleDTOBuilder setEnginetype(EngineType enginetype) {
            this.enginetype = enginetype;
            return this;
        }
        public VehicleDTOBuilder setvehiclerating(Integer vehiclerating) {
            this.vehiclerating = vehiclerating;
            return this;
        }


        public VehicleDTO createVehicleDTO()
        {
            return new VehicleDTO(id, vehiclenumber, vehicleseatcount, enginetype,vehiclerating);
        }

    }

}

My DTO has an Enum type called EngineType

public enum EngineType {
    ELECTRIC, DIESEL
}

My controller looks like this

@PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public VehicleDTO addvehicle(@Valid @RequestBody VehicleDTO vehicleDTO) 
    {
        VehicleDO vehicleDO = Mapper.VehicleDO(vehicleDTO);
        return Mapper.makeVehicleDTO(Service.addvehicle(vehicleDO));
    }
Pavindu
  • 2,684
  • 6
  • 44
  • 77
RK3
  • 1,221
  • 9
  • 26
  • 37

5 Answers5

15

This exception :

InvalidDefinitionException: Cannot construct instance of com.vehicle.datatransferobject.VehicleDTO (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

means that Jackson didn't find a way to instantiate VehicleDTO that is the default constructor (no arg constructor) or a JsonCreator.
As you use a builder pattern you will configure the VehicleDTO class to make Jackson to instantiate VehicleDTO with the VehicleDTOBuilder such as :

@JsonDeserialize(builder = VehicleDTO.VehicleDTOBuilder.class)
public class VehicleDTO {
      ...         
}

And annotate your builder with JsonPOJOBuilder as :

@JsonPOJOBuilder(buildMethodName = "createVehicleDTO", withPrefix = "set")
public static class VehicleDTOBuilder{ 
   ...
}

According to the javadoc, JsonPOJOBuilder is :

used to configure details of a Builder class: instances of which are used as Builders for deserialized POJO values, instead of POJOs being instantiated using constructors or factory methods. Note that this annotation is NOT used to define what is the Builder class for a POJO: rather, this is determined by JsonDeserialize.builder() property of JsonDeserialize.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • thanks this worked. So if i had a public constructor then i wouldn't have faced this issue is it? – RK3 Jul 16 '18 at 18:48
  • 1
    Exactly. You can test it ! Few years early you would have added a no arg constructor or a factory method but Jackson improves the way to instantiate the objects. – davidxxx Jul 16 '18 at 18:51
  • So builder method is the right way to create my DTO to send as response? is it the standard? Or should i change my code? – RK3 Jul 16 '18 at 18:53
  • I suppose that you use a builder to make your DTO immutable and with a consistent state. If it is the case you want to keep this way. Jackson just adapted its way to work to cover different ways to instantiate an object. – davidxxx Jul 16 '18 at 18:55
  • can you look at one more issue here [link]https://stackoverflow.com/questions/51383872/spring-boot-dto-is-null-at-controller?noredirect=1#comment89740063_51383872 – RK3 Jul 17 '18 at 14:48
11

I faced this error when I used Lombok's @Builder and @Data annotations together on a POJO class that is used for connecting to an API (either for consuming or for providing response)

I removed the @Builder annotation and then it is working fine

firstpostcommenter
  • 2,328
  • 4
  • 30
  • 59
7

In my case:

InvalidDefinitionException: Cannot construct instance of com.vehicle.datatransferobject.VehicleDTO (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

for the above exception, I just write Default Constructor which instantiates class and solved the problem.

Default Constructor:

public VehicleDTO() {
        super();
        // TODO Auto-generated constructor stub
    }
Ravi Mengar
  • 1,181
  • 1
  • 11
  • 18
3

If you are using Lombok - the best thing is to add these annotations to your DTO:

@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Builder (optional)
1

In addition to davidxxx`s answer. I used Lombok. And in my case it looked like this:

@Data
@JsonDeserialize(builder = SomeClass.SomeClassBuilder.class)
@Builder(builderClassName = "SomeClassBuilder")
public class SomeClass {
    // ...

    @JsonPOJOBuilder(withPrefix = "")
    public static class SomeClassBuilder {
    }
}
  • Thanks, this is the only solution here that worked with lombok. (adding the empty static builder class in the class) – user3761308 Jul 28 '21 at 16:32