我正在尝试将 JSON 反序列化为我无法修改的自定义 POJO。该 POJO 具有来自我无法使用的不同自定义内部序列化框架的注释。如何创建一个尊重这些注释的自定义反序列化器?
这是一个示例 POJO:
public class ExampleClass {
@Property(name = "id")
public String id;
@Property(name = "time_windows")
@NotNull
public List<TimeWindow> timeWindows = new ArrayList<>();
public static class TimeWindow {
@Property(name = "start")
public Long start;
@Property(name = "end")
public Long end;
}
}
所以在这种情况下,反序列化器会在 JSON 中查找与 Property
相对应的字段。注释,并使用该注释中的值来决定要抓取的字段。如果属性没有 Property
注释,它应该被忽略。我一直在浏览 Jackson 文档,但无法准确找到我需要的东西。这是一个
AnnotationIntrospector
的地方吗?会有用吗?或者可能是 ContextualDeserializer
?任何指向正确方向的指针将不胜感激!
更新:我尝试实现评论中的建议,但没有成功。
这是我对自省(introspection)器的初始实现:
class CustomAnnotationInspector : JacksonAnnotationIntrospector () {
override fun hasIgnoreMarker(m: AnnotatedMember?): Boolean {
val property = m?.getAnnotation(Property::class.java)
return property == null
}
override fun findNameForDeserialization(a: Annotated?): PropertyName {
val property = a?.getAnnotation(Property::class.java)
return if (property == null) {
super.findNameForDeserialization(a)
} else {
PropertyName(property.name)
}
}
}
这是我实际使用它的地方:// Create an empty instance of the request object.
val paramInstance = nonPathParams?.type?.getDeclaredConstructor()?.newInstance()
// Create new object mapper that will write values from
// JSON into the empty object.
val mapper = ObjectMapper()
// Tells the mapper to respect custom annotations.
mapper.setAnnotationIntrospector(CustomAnnotationInspector())
// Write the contents of the request body into the StringWriter
// (this is required for the mapper.writeValue method
val sw = StringWriter()
sw.write(context.bodyAsString)
// Deserialize the contents of the StringWriter
// into the empty POJO.
mapper.writeValue(sw, paramInstance)
不幸的是,findNameForDeserialization
永远不会被调用,并且没有任何 JSON 值被写入 paramInstance
.谁能发现我哪里出错了?谢谢!
更新 2:我稍微更改了代码,我现在能够识别属性名称,但 jackson 未能创建对象的实例。
这是我的新代码:
val mapper = ObjectMapper()
// Tells the mapper to respect CoreNg annotations.
val introspector = CustomAnnotationInspector()
mapper.setAnnotationIntrospector(introspector)
val paramInstance = mapper.readValue(context.bodyAsString,nonPathParams?.type)
我在自定义注释内省(introspection)中的断点被击中。但我得到以下异常:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `app.employee.api.employee.BOUpsertEmployeeRequest` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
这是我试图反序列化的 POJO:public class BOUpsertEmployeeRequest {
public BOUpsertEmployeeRequest () { }
@NotNull
@Property(name = "xref_code")
public String xrefCode;
@Property(name = "first_name")
public String firstName;
@Property(name = "last_name")
public String lastName;
@Property(name = "email_address")
public String emailAddress;
@Property(name = "phone")
public String phone;
@Property(name = "address")
public List<String> address;
@Property(name = "employment_status")
public String employmentStatus;
@Property(name = "pay_type")
public String payType;
@Property(name = "position")
public String position;
@Property(name = "skills")
public List<String> skills;
@Property(name = "gender")
public String gender;
}
据我所知,它有一个默认构造函数。有人知道问题是什么吗?谢谢!
最佳答案
方法hasIgnoreMarker不仅为字段调用,还为构造函数调用,包括虚拟的:
Method called to check whether given property is marked to be ignored. This is used to determine whether to ignore properties, on per-property basis, usually combining annotations from multiple accessors (getters, setters, fields, constructor parameters).
在这种情况下,您应该只忽略未正确标记的字段:
static class CustomAnnotationIntrospector extends JacksonAnnotationIntrospector {
@Override
public PropertyName findNameForDeserialization(Annotated a) {
Property property = a.getAnnotation(Property.class);
if (property == null) {
return PropertyName.USE_DEFAULT;
} else {
return PropertyName.construct(property.name());
}
}
@Override
public boolean hasIgnoreMarker(AnnotatedMember m) {
return m instanceof AnnotatedField
&& m.getAnnotation(Property.class) == null;
}
}
示例:
class Pojo {
// @Property(name = "id")
Integer id;
// @Property(name = "number")
Integer number;
@Property(name = "assure")
Boolean assure;
@Property(name = "person")
Map<String, String> person;
}
String json =
"{\"id\" : 1, \"number\" : 12345, \"assure\" : true," +
" \"person\" : {\"name\" : \"John\", \"age\" : 23}}";
ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new CustomAnnotationIntrospector());
Pojo pojo = mapper.readValue(json, Pojo.class);
System.out.println(pojo);
Pojo{id=null, number=null, assure=true, person={name=John, age=23}}
注:定制
Property
注释应该有 RetentionPolicy.RUNTIME (与 JsonProperty 注释相同):@Retention(RetentionPolicy.RUNTIME)
public @interface Property {
String name();
}
关于java - 如何使用尊重自定义注释的 jackson 执行自定义 JSON 反序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63362602/