是否可以使用非默认构造函数的Jackson自定义反序列化器?

时间:2011-10-15 22:53:34

标签: java deserialization jackson

假设我有以下课程:

public class Person {

    String name;
    Set<Department> departments;

}

public class Department {

    String code;
    String name;

}

所以我想编写一个自定义的部门反序列化器,以便在Person类中注释deparments字段以使用它。因为此自定义反序列化器仅用于反序列化Person对象内的Department对象。问题是我的自定义部门反序列化器需要有一个必须在反序列化器的构造函数中传递的DepartmentRepository。我怎样才能做到这一点?这可能吗?我不想在对象映射器中注册反序列化器,因为它只能在Person类的deparatments字段被反序列化时使用。

更新:我需要的是,除了使用参数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!
    }

}

5 个答案:

答案 0 :(得分:1)

首先要做的事情是:指定用于可以使用的数组内容的反序列化器

@JsonDeserialize(contentUsing=MyDeserializer.class)
Set<Department> departments;

指定用于相关集合内容的反序列化程序。

至于使用非默认构造函数的能力,@ JsonCreator允许这样做。 但是要传递一个上下文对象,你需要Jackson 1.9可能是你的朋友(参见“Jackson 1.9 overview”),它允许“注入”JSON之外的对象。 然后,您可以混合和匹配可注入值和JSON属性,例如:

public class POJO {
  @JsonCreator // can also be used for static factory methods
  public POJO(@JacksonInject DepartmentRepository repo, @JsonProperty("value") int value) {
      ....
  }
}

这可能足以满足您的要求。

答案 1 :(得分:1)

您可以将自定义序列化程序/反序列化程序与非ObjectMapper一起注册为模块,从而添加非默认构造函数。

SimpleModule simpleModule = new SimpleModule();
JsonDeserializer<MyObject> customDeserializer = new CustomDeserializer("Blah");
testModule.addDeserializer(MyObject.class, customDeserializer);
mapper.registerModule(simpleModule);

您还应该删除MyObject课程中的注释。

答案 2 :(得分:0)

这是我刚写的解串器。注意使用非默认构造函数。

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

与以下内容一起使用。请注意,在创建反序列化器并将其添加到模块时,您可以使用任何构造函数模式。

 ObjectMapper mapper = new ObjectMapper();
    SimpleModule module = new SimpleModule("ResultAccess", new Version(7, 4, 0, null));
    module.addDeserializer(SparseStringArrayVector.class, new SparseStringArrayVectorDeserializer());
    module.addDeserializer(AbstractResultAccess.class, new ProxyAbstractResultAccessDeserializer());
    mapper.registerModule(module);

答案 3 :(得分:0)

不,一开始,您无需指定自定义解串器即可;仅当所有模型类都实现Serializable 时,Jackson才能检测到嵌套字段并正确映射它们。

因此,将implements Serializable添加到DepartmentPerson中,您将看到Jackson开箱即用。

答案 4 :(得分:-2)

在我的脑海中,我很确定你可以使用杰克逊的注释来识别你想要曝光的属性。