Java 为什么JsonDeserialize不能使用Lombok SuperBuilder构造类

Java 为什么JsonDeserialize不能使用Lombok SuperBuilder构造类,java,lombok,jackson-databind,Java,Lombok,Jackson Databind,我正在尝试创建一个对象模型,该模型表示嵌套设备位置的层次结构。例如,“甲板”包含一个“幻灯片托盘”,其中包含一个或多个“幻灯片”。我希望能够读入包含系统层次结构/配置的json文件。我想在我的类中使用Lombok构建器,以便在需要时安全地在代码中生成json文件。更常见的用例是在应用程序启动时读入json文件以创建pojo。使用构建器生成json文件非常有效。但是,我还没有将该文件反序列化回pojo 以下是我得到的错误: com.fasterxml.jackson.databind.exc.In

我正在尝试创建一个对象模型,该模型表示嵌套设备位置的层次结构。例如,“甲板”包含一个“幻灯片托盘”,其中包含一个或多个“幻灯片”。我希望能够读入包含系统层次结构/配置的json文件。我想在我的类中使用Lombok构建器,以便在需要时安全地在代码中生成json文件。更常见的用例是在应用程序启动时读入json文件以创建pojo。使用构建器生成json文件非常有效。但是,我还没有将该文件反序列化回pojo

以下是我得到的错误:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `my.org.Deck$DeckBuilder` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (String)"{"type":"Deck","locNumber":1,
顶级超级类是:

package my.org;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.Getter;
import lombok.Singular;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

import java.awt.geom.Point2D;
import java.util.List;


@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
        @JsonSubTypes.Type(value = Deck.class, name = "Deck"),
        @JsonSubTypes.Type(value = SlideTray.class, name = "SlideTray"),
        @JsonSubTypes.Type(value = Slide.class, name = "Slide"),
        @JsonSubTypes.Type(value = NullLoc.class, name = "null"),
})
@SuperBuilder
@Getter
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = BaseLocationType.BaseLocationTypeBuilder.class)
public class BaseLocationType<T extends BaseLocationType> {

    @JsonProperty("locNumber")
    private int locNumber;

    @JsonProperty("posRelativeToParent")
    private Point2D.Double positionRelativeToParent;

    @Singular
    @JsonProperty("childLocs")
    private List<T> childLocs;

}
注意:我在stackoverflow中没有看到上传演示项目zip文件的选项。。。但如果需要的话,我们可以想出一个分享的方法。
谢谢

我认为根本问题与跨三个主要子类定义的
@JsonDeserialize
注释
builder
值有关,因为它们似乎是
抽象的
引用。这也解释了你收到的错误信息

Lombok
@SuperBuilder
文档中:

为了确保类型安全,@SuperBuilder为每个注释类生成两个内部生成器类,一个抽象类和一个具体类,分别命名为FoobarBuilder和FoobarBuilderImpl(其中Foobar是注释类的名称)

我相信,更新以下
@JsonDeserialize
annotation
builder
值将有助于解决此问题:

甲板
子类中:

package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Deck.DeckBuilder.class)
public class Deck extends BaseLocationType<SlideTray> {

    private String deckField1;

    private String deckField2;


}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilder.class)
public class SlideTray extends BaseLocationType<Slide> {

    private String slideTrayField1;

}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Slide.SlideBuilder.class)
public class Slide extends BaseLocationType<NullLoc> {

    private String slideField1;

}
@JsonDeserialize(builder = Deck.DeckBuilderImpl.class)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilderImpl.class)
@JsonDeserialize(builder = Slide.SlideBuilderImpl.class)
幻灯片中
子类:

package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Deck.DeckBuilder.class)
public class Deck extends BaseLocationType<SlideTray> {

    private String deckField1;

    private String deckField2;


}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilder.class)
public class SlideTray extends BaseLocationType<Slide> {

    private String slideTrayField1;

}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Slide.SlideBuilder.class)
public class Slide extends BaseLocationType<NullLoc> {

    private String slideField1;

}
@JsonDeserialize(builder = Deck.DeckBuilderImpl.class)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilderImpl.class)
@JsonDeserialize(builder = Slide.SlideBuilderImpl.class)
幻灯片中
子类:

package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Deck.DeckBuilder.class)
public class Deck extends BaseLocationType<SlideTray> {

    private String deckField1;

    private String deckField2;


}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilder.class)
public class SlideTray extends BaseLocationType<Slide> {

    private String slideTrayField1;

}
package my.org;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.experimental.SuperBuilder;

@SuperBuilder
@Getter
@EqualsAndHashCode(callSuper = true)
@Accessors(fluent = true, chain = true)
@JsonDeserialize(builder = Slide.SlideBuilder.class)
public class Slide extends BaseLocationType<NullLoc> {

    private String slideField1;

}
@JsonDeserialize(builder = Deck.DeckBuilderImpl.class)
@JsonDeserialize(builder = SlideTray.SlideTrayBuilderImpl.class)
@JsonDeserialize(builder = Slide.SlideBuilderImpl.class)

有关
BuilderImpl
手动更新的附加说明:
@SuperBuilder
文档包含与此主题相关的以下支持信息:

自定义@SuperBuilder生成的代码仅限于向生成器类添加新方法或注释,并提供“set”、builder()和build()方法的自定义实现。您必须确保生成器类声明头与lombok生成的那些头匹配。由于大量泛型的使用,我们强烈建议从未加密的delomboke代码中复制builder类定义头


嗨,肖恩,谢谢你的回答。使用impl类,代码无法编译,因为它们是作为私有静态类生成的。因此,我对它们进行了简化,并将impl类包私有化,这样就成功了。注意:我必须删除基类上的@JsonProperty(“locNumber”),因此在集成jackson时似乎出现了一些问题。必须去lombok不是这里的预期用途,对吗?但是我没有找到任何方法来解决这个问题。我的错-我想提醒你关于次要可见性的问题。我突然想到了这一点,但后来我集中精力阅读了你的代码,完全忘记了。但是你已经加入了我忘记在我的答案中包含的修复,所以这就解决了。关于你遇到的与Jackson相关的问题,根本原因可能是Jackson默认处理要求生成器mutator方法包含一个“With”前缀,而Lombok使用基本字段名。如果这就是问题所在,那么将注释添加到混凝土生成器impl类(与您的delombok相同,只是为了清楚起见)中:
@JsonPOJOBuilder(withPrefix=”“)
应该可以解决问题。接下来,关于您的delombok疑虑,我清楚地听到您的声音。但这种(丑陋的)解决办法是我找到的唯一解决办法,所以我把它归为较轻的邪恶类别,并承受它。我已经有一段时间没有检查过了,但我记得Lombok开发团队的一次讨论对提出的解决方案充满希望,但最终可能会因为不可行而被放弃。