【问题标题】:InvalidDefinitionException: Cannot construct instance of `com.vehicle.datatransferobject.VehicleDTO`InvalidDefinitionException:无法构造“com.vehicle.datatransferobject.VehicleDTO”的实例
【发布时间】:2018-12-24 08:56:34
【问题描述】:

在我在 Spring Boot 中构建的 REST 端点中,我试图将我的 vehicleDTO 传递给我的控制器。但在它到达我的控制器之前,出现了错误。

InvalidDefinitionException:无法构造实例 com.vehicle.datatransferobject.VehicleDTO(没有创作者,默认 构造,存在):不能从对象值反序列化(没有委托- 或基于属性的创建者)

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);
        }

    }

}

我的 DTO 有一个名为 EngineType 的枚举类型

public enum EngineType {
    ELECTRIC, DIESEL
}

我的控制器是这样的

@PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public VehicleDTO addvehicle(@Valid @RequestBody VehicleDTO vehicleDTO) 
    {
        VehicleDO vehicleDO = Mapper.VehicleDO(vehicleDTO);
        return Mapper.makeVehicleDTO(Service.addvehicle(vehicleDO));
    }

【问题讨论】:

  • 您是否尝试过向 VehicleDTO 添加默认构造函数?

标签: rest spring-boot jackson spring-restcontroller


【解决方案1】:

这个例外:

InvalidDefinitionException:无法构造实例 com.vehicle.datatransferobject.VehicleDTO(无创作者,如默认 构造,存在):不能从对象值反序列化(没有委托- 或基于属性的创建者)

意味着 Jackson 没有找到实例化 VehicleDTO 的方法,即默认构造函数(无 arg 构造函数)或 JsonCreator
当您使用构建器模式时,您将配置 VehicleDTO 类以使 Jackson 使用 VehicleDTOBuilder 实例化 VehicleDTO,例如:

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

并使用JsonPOJOBuilder 将您的构建器注释为:

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

根据 javadoc,JsonPOJOBuilder 是:

用于配置 Builder 类的详细信息:其实例是 用作反序列化 POJO 值的构建器,而不是 POJO 使用构造函数或工厂方法实例化。请注意,这 注解不用于定义 POJO 的 Builder 类: 相反,这是由 JsonDeserialize.builder() 的属性确定的 JsonDeserialize。

【讨论】:

  • 感谢这项工作。所以如果我有一个公共构造函数,那么我就不会遇到这个问题了是吗?
  • 没错。你可以测试一下!几年前,您会添加一个无参数构造函数或工厂方法,但 Jackson 改进了实例化对象的方式。
  • 那么构建器方法是创建我的 DTO 以作为响应发送的正确方法吗?这是标准吗?还是我应该更改我的代码?
  • 我想您使用构建器使您的 DTO 不可变并具有一致的状态。如果是这种情况,您希望保持这种方式。 Jackson 刚刚调整了它的工作方式,以涵盖实例化对象的不同方式。
  • 你能在这里再看一期吗[link]stackoverflow.com/questions/51383872/…
【解决方案2】:

当我在用于连接到 API(用于消费或提供响应)的 POJO 类上同时使用 Lombok 的 @Builder@Data 注释时遇到此错误

我删除了@Builder 注释,然后它工作正常

【讨论】:

    【解决方案3】:

    就我而言:

    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)
    

    对于上述异常,我只写了Default Constructor,它实例化了类并解决了问题。

    默认构造函数:

    public VehicleDTO() {
            super();
            // TODO Auto-generated constructor stub
        }
    

    【讨论】:

      【解决方案4】:

      除了davidxxx的回答。我用过龙目岛。就我而言,它看起来像这样:

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

      【讨论】:

      • 谢谢,这是这里唯一适用于 lombok 的解决方案。 (在类中添加空的静态构建器类)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-09-26
      • 2021-07-17
      • 2014-08-28
      • 2020-09-27
      • 2020-03-08
      • 2020-05-07
      相关资源
      最近更新 更多