Jackson/GSON: 将 Map 应用到 POJO
Jackson/GSON: Apply Map to POJO
假设我有一个包含很多字段的 POJO。我还有一个地图,其中包含许多可以很好地映射到 POJO 中的字段的属性。现在我想将映射中的属性应用到我的 POJO。我该怎么做?
Jackson 提供了方法 new ObjectMapper().convertValue()
,但它创建了一个新的 POJO 实例。我真的必须做这样的事情吗?
om = new ObjectMapper();
pojoMap = om.convertValue(pojo, Map.class);
pojoMap.putAll(properties);
pojo = om.convertValue(pojoMap, Pojo.class);
有没有更简单的方法?
由于我没有使用 GSON 的经验,而且我们这里也有它,我该如何使用 GSON 呢?
是的,您可以使用 ObjectMapper
的 readerForUpdating
方法创建一个 ObjectReader,它将从根 JSON 对象更新现有实例,而不是实例化一个新实例:
@Test
public void apply_json_to_existing_object() throws Exception {
ExampleRecord record = new ExampleRecord();
ObjectReader reader = mapper.readerForUpdating(record)
.with(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
reader.readValue("{ firstProperty: 'foo' }");
reader.readValue("{ secondProperty: 'bar' }");
assertThat(record.firstProperty, equalTo("foo"));
assertThat(record.secondProperty, equalTo("bar"));
}
public static class ExampleRecord {
public String firstProperty;
public String secondProperty;
}
您还可以从现有 ObjectReader
创建值更新 reader。以下声明似乎是等效的:
ObjectReader reader = mapper.reader(ExampleRecord.class)
.withValueToUpdate(record)
.with(/* features etc */);
加法
不过,以上内容并未真正回答您的问题。
由于您没有想要对 JSON 记录进行的更改,而是作为地图进行的更改,因此您必须弄虚作假,以便 Jackson 阅读您的地图。您不能直接执行此操作,但可以将 "JSON" 写入令牌缓冲区,然后再读回:
@Test
public void apply_map_to_existing_object_via_json() throws Exception {
ExampleRecord record = new ExampleRecord();
Map<String, Object> properties = ImmutableMap.of("firstProperty", "foo", "secondProperty", "bar");
TokenBuffer buffer = new TokenBuffer(mapper, false);
mapper.writeValue(buffer, properties);
mapper.readerForUpdating(record).readValue(buffer.asParser());
assertThat(record.firstProperty, equalTo("foo"));
assertThat(record.secondProperty, equalTo("bar"));
}
(顺便说一句,如果这看起来很费力,序列化到令牌缓冲区并再次反序列化实际上是 ObjectMapper.convertValue
的实现方式,所以它在功能上没有太大变化)
假设我有一个包含很多字段的 POJO。我还有一个地图,其中包含许多可以很好地映射到 POJO 中的字段的属性。现在我想将映射中的属性应用到我的 POJO。我该怎么做?
Jackson 提供了方法 new ObjectMapper().convertValue()
,但它创建了一个新的 POJO 实例。我真的必须做这样的事情吗?
om = new ObjectMapper();
pojoMap = om.convertValue(pojo, Map.class);
pojoMap.putAll(properties);
pojo = om.convertValue(pojoMap, Pojo.class);
有没有更简单的方法?
由于我没有使用 GSON 的经验,而且我们这里也有它,我该如何使用 GSON 呢?
是的,您可以使用 ObjectMapper
的 readerForUpdating
方法创建一个 ObjectReader,它将从根 JSON 对象更新现有实例,而不是实例化一个新实例:
@Test
public void apply_json_to_existing_object() throws Exception {
ExampleRecord record = new ExampleRecord();
ObjectReader reader = mapper.readerForUpdating(record)
.with(JsonParser.Feature.ALLOW_SINGLE_QUOTES)
.with(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES);
reader.readValue("{ firstProperty: 'foo' }");
reader.readValue("{ secondProperty: 'bar' }");
assertThat(record.firstProperty, equalTo("foo"));
assertThat(record.secondProperty, equalTo("bar"));
}
public static class ExampleRecord {
public String firstProperty;
public String secondProperty;
}
您还可以从现有 ObjectReader
创建值更新 reader。以下声明似乎是等效的:
ObjectReader reader = mapper.reader(ExampleRecord.class)
.withValueToUpdate(record)
.with(/* features etc */);
加法
不过,以上内容并未真正回答您的问题。
由于您没有想要对 JSON 记录进行的更改,而是作为地图进行的更改,因此您必须弄虚作假,以便 Jackson 阅读您的地图。您不能直接执行此操作,但可以将 "JSON" 写入令牌缓冲区,然后再读回:
@Test
public void apply_map_to_existing_object_via_json() throws Exception {
ExampleRecord record = new ExampleRecord();
Map<String, Object> properties = ImmutableMap.of("firstProperty", "foo", "secondProperty", "bar");
TokenBuffer buffer = new TokenBuffer(mapper, false);
mapper.writeValue(buffer, properties);
mapper.readerForUpdating(record).readValue(buffer.asParser());
assertThat(record.firstProperty, equalTo("foo"));
assertThat(record.secondProperty, equalTo("bar"));
}
(顺便说一句,如果这看起来很费力,序列化到令牌缓冲区并再次反序列化实际上是 ObjectMapper.convertValue
的实现方式,所以它在功能上没有太大变化)