杰克逊Ser / Deser:使用不同的密钥将对象导入/导出id

时间:2011-09-01 01:37:56

标签: java json deserialization jackson

提前道歉。这似乎是一个简单的任务,但几个小时后谷歌和猜/检查,我仍然无法弄明白。

我正在为我公司提供的API编写Java便捷包装器库。其中一个类看起来像这样:

class View extends Model<View>
{
    List<Column> columns;
    Column primaryColumn;
}

但是,我们的API实际上需要primaryColumnId整数,而不是实际的Column对象。我想在库中维护强类型getPrimaryColumn()setPrimaryColumn(Column)以减少开发人员错误,但是我在我们需要ser /的getter / setter之间编写某种转换时遇到了很大困难来自/来自JSON。

我正在使用标准的Bean序列化策略。我想避免使用完全自定义的方法,因为实际上View有几十个字段。这是我到目前为止所发现的。

(尚未测试)我只需创建一个类似于以下内容的自定义JsonSerializer即可处理序列化案例。

public static class ColumnIdSerializer extends JsonSerializer<Column>
    {
        @Override
        public void serialize(Column column, JsonGenerator jsonGenerator,
                              SerializerProvider serializerProvider) throws IOException {
            jsonGenerator.writeFieldName("primaryColumnId");
            jsonGenerator.writeNumber(column.id);
        }
    }

然后将注释分配到适当的位置:

@JsonSerialize(using = Column.ColumnIdSerializer.class)
public Column getPrimaryColumn() { /* ... */ }

这允许我序列化id而不是整个班级,并将密钥从primaryColumn重命名为primaryColumnId

现在,我们进入反序列化。在这里,我遇到了三个问题。

首先,为了从id成功反序列化列,我们必须先得到列的列表。这可以使用@JsonPropertyOrder在类上解决。好的,已经完成了。

第二个是我需要告诉杰克逊在primaryColumnId而不是primaryColumn下查看价值。我不知道该怎么做;在找到密钥后,JsonDeserializer似乎会启动,因此修改它为时已晚。 JsonSchema看起来可能有用,但我找不到任何关于如何使用的文档或网络聊天。

第三个是来自自定义JsonDeserializer课程,我必须能够引用要反序列化的View才能要求Column以换取我的id getPrimaryColumnId() int。似乎没有办法做到这一点。

我是否应该沉迷并添加公开setPrimaryColumnId(Integer)和{{1}},还是有办法克服这些障碍?

2 个答案:

答案 0 :(得分:1)

所以我建议这样的事情:

class CustomView
{
    private final View parent;
    public CustomView(View view){
        parent = view;
    }

    // Jackson needs a no-arg constructor
    public CustomView(){
        parent = new View();
    }

    // ...
    public List<Columns> getColumns(){ ... }
    public void setColumns(List<Columns> columns){ ... }

    public int getPrimaryColumn(){
        return parent.getPrimaryColumn().getColumnId();
    }
    public void setPrimaryColumn(int column){
        parent.getPrimaryColumn().setColumnId(column);
    }
    //...

    // don't use `get` in the method name here to avoid serialization
    public View rawView(){
        return parent;
    }
}

如果需要,可以编写此文件以扩展View,但请注意在适当的时候屏蔽方法。

答案 1 :(得分:0)

事实证明,由于杰克逊做了讨厌的反思,它可以通过private方法看到。所以,这个伎俩最终只是按照以下方式:

private void setPrimaryColumnId(Integer id) {...}

private Integer getPrimaryColumnId() {...}

public void setPrimaryColumn(Column column) {...}

@JsonIgnore
public Column getPrimaryColumn() {...}