当前位置: 首页 > 知识库问答 >
问题:

如何使用自定义Jackson反序列化器解析对象引用

商同
2023-03-14
{
    "name": "test",
    "columns": [
        {
            "name": "a",
            "type": "TEXT"
        },
        {
            "name": "b",
            "type": "TEXT"
        }
    ],
    "rules": [
        {
            "production": {
                "a": "[b]"
            },
            "filters": {
                "a": [
                    "",
                    "ALL",
                    false
                ]
            },
            "refcolumns": [
                "b"
            ]
        }
    ]
}

JSON文档有一个属性columns,其中包含一组Column对象(也可以是使用属性名称作为键的映射)。这是唯一一个在JSON中完全序列化columns对象的地方。在其他任何地方,列都使用唯一的name属性进行引用

引用可用于映射键和值

我想将此文档反序列化并:

  • 解析属性中对应对象的引用
  • 使用相同的java对象实例(列类是不可变的),而不是每次都创建一个新的。(我想减少对象的数量)

JsonIdtyInfoesnt不适用于地图键。所以我使用定制序列化程序

下面是如何序列化规则类的,JsonPolinKeySerializer只返回列的"name"属性

class Rule {
    @JsonSerialize(keyUsing = Column.JsonColumnKeySerializer.class) 
    private HashMap<Column, RuleFormula> productions = new HashMap<>();
    @JsonSerialize(keyUsing = Column.JsonColumnKeySerializer.class) 
    private Map<Column, RuleFilter> filters = new LinkedHashMap<>();
    @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "name")
    @JsonIdentityReference(alwaysAsId=true) // for testing purposes...
    private Set<Column> refcolumns = new HashSet<>();
}

共有1个答案

宋飞文
2023-03-14

我想杰克逊应该能帮你,但我不知道怎么做。作为一种解决方法,您可以编写自定义反序列化程序,在其中可以按名称属性缓存结果:

public class CachingColumnDeserializer extends JsonDeserializer<Column> {

  private static final Map<String, Column> MAP = new HashMap<>();

  @Override
  public Column deserialize(JsonParser parser, DeserializationContext context) throws IOException, JacksonException {
    JsonNode node = parser.getCodec().readTree(parser);
    String name = node.get("name").asText();
    return MAP.computeIfAbsent(name, nameKey -> new Column(nameKey, node.get("type").asText()));
  }

  public static Map<String, Column> getMap() {
    return Collections.unmodifiableMap(MAP);
  }
}

我们需要映射的静态实例,以便与KeyDeserializer共享它,getMap()返回不可修改的映射,因此我们不能错误地更改它。然后您的KeyDeserializer将使用该映射获取现有实例。

public class CachedColumnKeyDeserializer extends KeyDeserializer {

  private final Map<String, Column> map;

  public CachedColumnKeyDeserializer() {
    this.map = CachingColumnDeserializer.getMap();
  }

  @Override
  public Object deserializeKey(String key, DeserializationContext context) throws IOException {
    Column column = this.map.get(key);
    if (column == null) {
      return new Column(key, null);
    }
    return column;
  }
}

指定如何反序列化

@JsonDeserialize(using = CachingColumnDeserializer.class, keyUsing = CachedColumnKeyDeserializer.class)

为了安全起见,您可以指定需要在其他属性之前反序列化列

@JsonPropertyOrder({"name", "columns", ...})
 类似资料:
  • 我有下面的JSON,我正试图使用Jackson API反序列化它 我基本上需要一个附件类,它有一个AttachmentFile对象列表,如下所示: 如何使用自定义反序列化器实现这一点? 谢谢

  • 如何基于json中指定的类类型,在Jackson中实现从json到Java对象的转换。 Java类型示例:

  • 问题内容: 我有以下课程: 当我执行以下代码时: 产生的json字符串如下所示: 我的问题是让上面的json字符串反序列化回一个 宾语。 我的反序列化代码如下所示: 它使用正确的键反序列化为HashMap,但不会为这些值创建Theme对象。我不知道在readValue()方法中要指定什么而不是“ HashMap.class”。 任何帮助,将不胜感激。 问题答案: 你应该创建特定的Map类型并将其提

  • 我得到了。了解调用相同的反序列化器。是否有一种方法可以在custome反序列化器中使用或?

  • 问题内容: 我正在使用Flickr API 。调用该方法时,默认的JSON结果为: 我想将此响应解析为Java对象: JSON属性应按以下方式映射: 不幸的是,我无法找到一种使用Annotations做到这一点的好方法。到目前为止,我的方法是将JSON字符串读入a 并从中获取值。 但是我认为,这是有史以来最不优雅的方式。有没有简单的方法,可以使用注释还是自定义反序列化器? 这对我来说将是很明显的,

  • 在一个项目中,我需要用自定义类加载器扩展标准类加载器。这样做的主要动机是在运行时扩展类路径。(有关此问题的解决方案,请参阅:https://stackoverflow.com/a/51584718/231397 ). 通过 工作正常,同时通过反序列化对象 失败,出现异常。原因是调用了标准类加载器,它不知道自定义类加载器。 问:使用自定义类加载器反序列化对象的正确方法是什么?