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);