Java 是否可以使用非默认构造函数的Jackson自定义反序列化程序?
假设我有以下课程:Java 是否可以使用非默认构造函数的Jackson自定义反序列化程序?,java,deserialization,jackson,Java,Deserialization,Jackson,假设我有以下课程: public class Person { String name; Set<Department> departments; } public class Department { String code; String name; } 公共类人物{ 字符串名; 设置部门; } 公共课系{ 字符串代码; 字符串名; } 因此,我想编写一个自定义部门反序列化程序,以便在Person类中注释departments字段以使
public class Person {
String name;
Set<Department> departments;
}
public class Department {
String code;
String name;
}
公共类人物{
字符串名;
设置部门;
}
公共课系{
字符串代码;
字符串名;
}
因此,我想编写一个自定义部门反序列化程序,以便在Person类中注释departments字段以使用它。因为此自定义反序列化程序将仅用于反序列化Person对象内的部门对象。问题是,我的自定义部门反序列化程序将需要一个DepartmentRepository,该DepartmentRepository必须在反序列化程序的构造函数中传递。我该怎么做?这可能吗?我不想在对象映射器中注册反序列化器,因为它只能在Person类中的deparaments字段被反序列化时使用
更新:我需要的是,除了使用参数contentUsing=MyCustomDepartmentDeserializer.class用JsonDeserialize注释departments字段外,这是一种告诉Jackson在创建MyCustomDepartmentDeserializer对象时,它必须通过调用接收DepartmentRepository的构造函数来完成。反序列化程序可能如下所示:
public class MyCustomDepartmentDeserializer extends JsonDeserializer<Department> {
private final DepartmentRepository departmentRepository;
public MyCustomDepartmentDeserializer(DepartmentRepository departmentRepository) {
this.departmentRepository = departmentRepository;
}
@Override
public Department deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
//IMPLEMENTATION!
}
}
公共类MyCustomDepartmentDeserializer扩展JsonDeserializer{
私有最终部门存储库部门存储库;
公共MyCustomDepartmentDeserializer(DepartmentRepository DepartmentRepository){
this.departmentRepository=departmentRepository;
}
@凌驾
公共部门反序列化(JsonParser jp,反序列化上下文ctxt)
抛出IOException、JsonProcessingException{
//实施!
}
}
就在我的脑海里,我非常确定你可以使用Jackson中的注释来识别你想要暴露的属性。这是我刚刚写的一个反序列化程序。请注意使用非默认构造函数
public class SparseStringArrayVectorDeserializer extends JsonDeserializer<SparseStringArrayVector> {
@Override
public SparseStringArrayVector deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
/* This isn't the most efficient way to do this, since we're building a tree of nodes that we will discard.
* However, we need to change the order around, so something like this is hard to avoid.
*/
JsonNode tree = jp.readValueAsTree();
int tokenCount = tree.size();
int[] indexes = new int[tokenCount];
String[][] strings = new String[tokenCount][];
Iterator<Entry<String, JsonNode>> fieldNameIt = tree.getFields();
int slot = 0;
while (fieldNameIt.hasNext()) {
Entry<String, JsonNode> entry = fieldNameIt.next();
int index = Integer.parseInt(entry.getKey());
indexes[slot] = index;
String[] thisTokenStrings = new String[entry.getValue().size()];
for (int x = 0; x < thisTokenStrings.length; x++) {
thisTokenStrings[x] = entry.getValue().get(x).getTextValue();
}
strings[slot] = thisTokenStrings;
slot++;
}
return new SparseStringArrayVector(indexes, strings);
}
}
第一件事:指定可用于数组内容的反序列化程序
@JsonDeserialize(contentUsing=MyDeserializer.class)
Set<Department> departments;
这可能足以满足您的要求。您可以将自定义序列化程序/反序列化程序作为模块注册到您的
ObjectMapper
中,从而添加具有非默认构造函数的自定义序列化程序/反序列化程序
SimpleModule simpleModule = new SimpleModule();
JsonDeserializer<MyObject> customDeserializer = new CustomDeserializer("Blah");
testModule.addDeserializer(MyObject.class, customDeserializer);
mapper.registerModule(simpleModule);
SimpleModule SimpleModule=new SimpleModule();
JsonDeserializer customDeserializer=新的customDeserializer(“Blah”);
addDeserializer(MyObject.class,customDeserializer);
映射器注册表模块(simpleModule);
您还应该删除
MyObject
类中的注释(如果有)。否,在一开始,您可以不指定自定义反序列化器;Jackson只能在所有模型类都实现了Serializable
时才能检测嵌套字段并正确映射它们
因此,将
implements Serializable
添加到Department
和Person
,您将看到Jackson是开箱即用的。非默认构造函数用于反序列化程序,而不是用于正在反序列化的类“tree.getFields()”应该是“tree.fields()”,据我所知,我刚刚尝试在反序列化器构造函数中使用@JacksonInject,但它不起作用。它似乎只适用于将被反序列化的类。正确的,它并不适用于反序列化程序,因为反序列化程序从来没有被Jackson实例化过(注册是使用反序列化程序实例,而不是类)。但这是个问题吗?您可以将其注入反序列化器类的构造函数/工厂方法中,您可以根据需要在其中使用它?或者反序列化程序只是使用它来查找传递给构造函数的其他内容?据我所知,当您不在对象映射器中注册它们时,反序列化程序是由Jackson实例化的。当您仅仅使用@JsonDeserializer(contentUsing=MyCustomDeserializer.class)时,实例化是由Jackson完成的。啊,是的,忘记了这一部分,您是对的。有趣的是,这里可能有一个关于注入的特性请求。然而,一个问题是,反序列化程序被实例化一次,并被缓存;甚至是上下文的。嗯,这很奇怪。因为我正在使用Jersey+GoogleGuice开发一个带有RESTAPI的web服务,每次遇到需要反序列化部门的方法时,都会创建一个新的反序列化器。我目前正在使用一个提供存储库的静态帮助器类来解决这个问题。这个存储库是使用guice注入的。但这并不是最好的解决方案。另一方面,我需要在每个请求上创建反序列化器,因为存储库依赖于实体管理器,并且当您使用guice时,会为每个请求创建一个新的EM。
public class POJO {
@JsonCreator // can also be used for static factory methods
public POJO(@JacksonInject DepartmentRepository repo, @JsonProperty("value") int value) {
....
}
}
SimpleModule simpleModule = new SimpleModule();
JsonDeserializer<MyObject> customDeserializer = new CustomDeserializer("Blah");
testModule.addDeserializer(MyObject.class, customDeserializer);
mapper.registerModule(simpleModule);