英文:
Jackson deserialization of a Lombok @Builder class using a mixin is not working
问题
这是我的类:
@Builder
@Value
public class A {
int id;
String name;
@NonNull String lastName;
}
Lombok的 @Builder
会添加所有参数的构造函数。
我需要将一个字符串反序列化为一个POJO对象。
我创建了以下包含所有三个属性的Jackson mixin:
public abstract class AMixin {
public AMixin(@JsonProperty("name") String name,
@JsonProperty("id") int id,
@JsonProperty("lastName") String lastName) {
}
@JsonProperty("name")
abstract String getName();
@JsonProperty("id")
abstract int getId();
@JsonProperty("lastName")
abstract String getLastName();
}
我这样反序列化:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(A.class, AMixin.class);
String ss = "{\"id\":1,\"name\":\"some name\",\"lastName\":\"some name\"}\n";
A c = mapper.readValue(ss, A.class);
}
但我得到了这个错误:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.bla.test.A` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"id":1,"name":"some name","lastName":"some name"}
"; line: 1, column: 2]
英文:
This is my class:
@Builder
@Value
public class A {
int id;
String name;
@NonNull String lastName;
}
The Lombok @Builder
will add the all args constructor.
I need to deserialise a string into a POJO object.
I created the following Jackson mixin containing all three properties:
public abstract class AMixin {
public AMixin(@JsonProperty("name") String name,
@JsonProperty("id") int id,
@JsonProperty("lastName") String lastName) {
}
@JsonProperty("name")
abstract String getName();
@JsonProperty("id")
abstract int getId();
@JsonProperty("lastName")
abstract String getLastName();
}
I deserialise like this:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
mapper.addMixIn(A.class, AMixin.class);
String ss = "{\"id\":1,\"name\":\"some name\",\"lastName\":\"some name\"}\n";
A c = mapper.readValue(ss, A.class);
}
but I get this error:
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.bla.test.A` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"id":1,"name":"some name","lastName":"some name"}
"; line: 1, column: 2]
答案1
得分: 2
我找到了答案。
添加带有以下内容的 lombok.config 文件:
lombok.anyConstructor.addConstructorProperties=true
英文:
I found the answer.
Add lombok.config file with content:
lombok.anyConstructor.addConstructorProperties=true
答案2
得分: 2
问题在于Jackson期望一个无参数构造函数或其他已配置的方式来创建对象。然而,由于A
上的@Builder
注解,没有无参数构造函数,只有由Lombok生成的全参数构造函数A(int id, String name, String lastName)
。
从Lombok v1.18.14开始,可以在带有@Builder
注解的类上添加@Jacksonized
注解,这将自动配置用于Jackson反序列化的生成构建器。
@Jacksonized
@Builder
@Value
public class A {
int id;
String name;
@NonNull String lastName;
}
Lombok的文档对@Jacksonized
注解进行了更详细的描述:
> @Jacksonized
注解是@Builder
和@SuperBuilder
的附加注解。它会自动配置生成的构建器类,以供Jackson的反序列化使用。只有在存在@Builder
或@SuperBuilder
的上下文中才会产生影响;否则会发出警告。
>
> [...]
>
> 具体而言,该注解执行以下操作:
>
> * 使用@JsonDeserialize(builder=_Foobar_._Foobar_Builder[Impl].class))
在类上配置Jackson以使用构建器进行反序列化(其中_Foobar_是带注解的类的名称,Impl
是为了@SuperBuilder
而添加的)。如果已存在这样的注解,将会发出错误。
> * 从类中复制Jackson相关的配置注解(如@JsonIgnoreProperties
)到构建器类。这是必要的,以便Jackson在使用构建器时识别它们。
> * 在生成的构建器类上插入@JsonPOJOBuilder(withPrefix="")
,以覆盖Jackson的默认前缀“with”。如果您在lombok中使用了setterPrefix
配置了不同的前缀,则将使用该值。如果使用buildMethodName
更改了build()
方法的名称,Jackson也会知道。
> * 对于@SuperBuilder
,使构建器实现类包私有。
注意:这个问题与使用mixin没有关系,可以通过将Jackson配置从mixin移到类本身并观察到问题仍然存在来进行验证。
英文:
The issue here is that Jackson expects a no-argument constructor or some other configured way of creating the object. However, because of the @Builder
annotation on A
, the no-argument constructor is not present, only the Lombok-generated all-argument constructor A(int id, String name, String lastName)
.
As of Lombok v1.18.14, the @Jacksonized
annotation can be added to the class with the @Builder
annotation, which automatically configures the builder to be used for Jackson deserialization.
@Jacksonized
@Builder
@Value
public class A {
int id;
String name;
@NonNull String lastName;
}
The Lombok documentation for @Jacksonized
describes this annotation in more detail:
> The @Jacksonized
annotation is an add-on annotation for @Builder
and @SuperBuilder
. It automatically configures the generated builder class to be used by Jackson's deserialization. It only has an effect if present at a context where there is also a @Builder
or a @SuperBuilder
; a warning is emitted otherwise.
>
> [...]
>
> In particular, the annotation does the following:
>
> * Configure Jackson to use the builder for deserialization using @JsonDeserialize(builder=_Foobar_._Foobar_Builder[Impl].class))
on the class (where Foobar is the name of the annotated class, and Impl
is added for @SuperBuilder
). (An error is emitted if such an annotation already exists.)
> * Copy Jackson-related configuration annotations (like @JsonIgnoreProperties
) from the class to the builder class. This is necessary so that Jackson recognizes them when using the builder.
> * Insert @JsonPOJOBuilder(withPrefix="")
on the generated builder class to override Jackson's default prefix "with". If you configured a different prefix in lombok using setterPrefix
, this value is used. If you changed the name of the build()
method using using buildMethodName
, this is also made known to Jackson.
> * For @SuperBuilder
, make the builder implementation class package-private.
Note: This issue has nothing to do with the usage of a mixin, which can be verified by moving Jackson configuration from the mixin to the class itself and observing that the issue is still present.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论