Jackson 2中的java.beans.ConstructorProperty
My domain对象使用增强,它为不可变对象的构造函数生成java.beans注释 现在,在我的前端工件中,我想使用将这些对象序列化为JSON。 对于Jackson 1,这可以通过使用。《杰克逊2》也有这样的解决方案吗?还是我必须自己写 我的主要问题是我想保持我的域对象前端不可知,所以我不想用Jackson注释污染它们Jackson 2中的java.beans.ConstructorProperty,java,jackson,javabeans,lombok,Java,Jackson,Javabeans,Lombok,My domain对象使用增强,它为不可变对象的构造函数生成java.beans注释 现在,在我的前端工件中,我想使用将这些对象序列化为JSON。 对于Jackson 1,这可以通过使用。《杰克逊2》也有这样的解决方案吗?还是我必须自己写 我的主要问题是我想保持我的域对象前端不可知,所以我不想用Jackson注释污染它们 否:这不是一个选项,因为我目前仍在使用Java7 恐怕您必须自己为Jackson2编写一个类似的包装。肖恩·帕特里克·弗洛伊德(Sean Patrick Floyd)已经编写了
否:这不是一个选项,因为我目前仍在使用Java7 恐怕您必须自己为Jackson2编写一个类似的包装。肖恩·帕特里克·弗洛伊德(Sean Patrick Floyd)已经编写了一个解决方案,但我发布了我的解决方案,因为他的解决方案是专有的。这是一个Jackson模块,它使用AnnotationIntrospector将带有@ConstructorProperties注释的构造函数设置为Jackson@JsonCreator
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.json.PackageVersion;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor;
import com.fasterxml.jackson.databind.introspect.NopAnnotationIntrospector;
import com.fasterxml.jackson.databind.module.SimpleModule;
import java.beans.ConstructorProperties;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
public class ConstructorPropertiesModule extends SimpleModule {
public ConstructorPropertiesModule() {
super(PackageVersion.VERSION);
}
@Override
public void setupModule(Module.SetupContext context) {
super.setupModule(context);
context.insertAnnotationIntrospector(new ConstructorPropertiesAnnotationIntrospector());
}
public static class ConstructorPropertiesAnnotationIntrospector extends NopAnnotationIntrospector {
@Override
public boolean hasCreatorAnnotation(Annotated a) {
if (!(a instanceof AnnotatedConstructor)) {
return false;
}
AnnotatedConstructor ac = (AnnotatedConstructor) a;
Constructor<?> c = ac.getAnnotated();
ConstructorProperties properties = c.getAnnotation(ConstructorProperties.class);
if (properties == null) {
return false;
}
for (int i = 0; i < ac.getParameterCount(); i++) {
final String name = properties.value()[i];
final int index = i;
JsonProperty jsonProperty = new JsonProperty() {
@Override
public String value() {
return name;
}
@Override
public boolean required() {
return false;
}
@Override
public Class<? extends Annotation> annotationType() {
return JsonProperty.class;
}
@Override
public int index() {
return index;
}
};
ac.getParameter(i).addOrOverride(jsonProperty);
}
return true;
}
}
}
这个问题最终在Jackson 2.7中得到了解决,
@constructorproperty
现在得到了开箱即用的支持
正如其他人所说,Jackson现在支持
@constructorproperty——不幸的是。因为它把事情搞砸了
杰克逊采用的逻辑是非常不幸的。如果存在多个@constructorproperty
带注释的构造函数,它将通过参数最多的构造函数创建对象。行动计划。这是一个问题,尤其是Lombok,它用@constructorproperty
注释所有构造函数。但无论如何,这个注释并不是专门为杰克逊写的。为可能使用此信息的任何代码检查工具注释每个构造函数是有意义的。龙目山就在这里
想象以下对象:
@Data
@Builder
@NoArgsConstructor // for Jackson
@AllArgsConstructor // for builder
public class MyDto {
private Type1 value1 = Type1.NONE;
private Type2 value2;
}
这里Jackson将始终使用all args构造函数,因为它使用@ConstructorProperties
进行注释,并且具有大多数参数
这也意味着,如果在JSON对象中仅设置value2
,则value1
将变为null
。不是你所期望的
结论:当前行为(与Lombok一起使用或注释多个构造函数时)不允许使用easy类级别的默认值
解决方法:@allargsconstuctor(suppressConstructorProperties=true)
-但这被认为是不推荐的,因为它的出现只是为了java 1.5的兼容性目的。^^这是我的同事取笑我(*sniff*)我现在确实写了那个包装,但不幸的是它是专有的,Jackson 2.7增加了对构造函数属性的支持:@Thomas你为什么不写这个作为答案呢?它值得更多的关注,因为它的价值:我不再使用Lombok,因为它在几乎所有方面都优于Lombok。但是谢谢你的回答,这对剩下的龙目岛用户来说是一个有效的贡献。
@Data
@Builder
@NoArgsConstructor // for Jackson
@AllArgsConstructor // for builder
public class MyDto {
private Type1 value1 = Type1.NONE;
private Type2 value2;
}