Java 为什么JsonDeserialize不能使用Lombok SuperBuilder构造类
我正在尝试创建一个对象模型,该模型表示嵌套设备位置的层次结构。例如,“甲板”包含一个“幻灯片托盘”,其中包含一个或多个“幻灯片”。我希望能够读入包含系统层次结构/配置的json文件。我想在我的类中使用Lombok构建器,以便在需要时安全地在代码中生成json文件。更常见的用例是在应用程序启动时读入json文件以创建pojo。使用构建器生成json文件非常有效。但是,我还没有将该文件反序列化回pojo 以下是我得到的错误: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
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
annotationbuilder
值将有助于解决此问题:
在甲板
子类中:
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开发团队的一次讨论对提出的解决方案充满希望,但最终可能会因为不可行而被放弃。