使用 Jackson 数据绑定跳过嵌套字段?
Skipping nested field with Jackson data binding?
我必须如何将以下 json 片段绑定(双向)到 Jackson 下方的 Java 对象?
我希望 key/value 对 Json 时事通讯节点最终出现在时事通讯字段的地图中。
绑定这个的 Jackson 配置(注释和其他)必须是什么?
抱歉,我不知道如何:((使用最新版本的 Jackson)。
下面的Json格式是固定的,我从第三方rest服务那里得到的(我不能改变它)。我可以更改 java 代码,但更喜欢下面的设置。
JSON:
{
"newsletter": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
Java对象:
class Preferences {
private NewsLetter newsLetter;
// getter/setter for field newsLetter.
}
class NewsLettter {
private Map<String, String> properties;
// getter/setter for field properties.
}
以下是 JSON 到 Java 转换的工作原理
第一步是创建 Java class 来保存 JSON 数据。你已经有一个了。看看json。您创建一个 Preferences
对象来保存
整个 json。 json 包含一个 newsletter
元素。你
在 Preferences
对象中创建类型为 Newsletter
的 Java 对象。
创建 org.codehaus.jackson.map.ObjectMapper
class 的实例。这是 class
将 JSON 映射到 Java 对象。
ObjectMapper mapper = new ObjectMapper();
然后使用ObjectMapper
的readValue
方法进行读取。此方法有多个版本,您可以使用接受一个
String
。但是,有些方法可以从 URL
、File
、InputStream
、String
或 ByteArray
.
读取
ObjectMapper
缓存序列化器和反序列化器,因此将一个 ObjectMapper
实例重用于多个实例是个好主意
转换
如果您有一个 String
然后将它传递给 Jackson 以将其转换为 Java Object.
String str = "
{ \"newsletter\":
{
\"properties\": {
\"key1\" : \"value1\",
\"key2\" : \"value2\",
\"key3\" : \"value3\"
}
}
}";
//read json
Preferences preferences = mapper.readValue(str, Preferences.class);
//write json
mapper.writeValue(str, preferences);
您可以使用将 json 转义为 java 字符串的工具:http://www.freeformatter.com/java-dotnet-escape.html
此工具产生以下结果
{ \"newsletter\":\r\n {\r\n \"properties\": {\r\n \"key1\" : \"value1\",\r\n \"key2\" : \"value2\",\r\n \"key3\" : \"value3\"\r\n }\r\n }\r\n }
如果你能得到一个道具JSON,像这样:
{
"newsletter": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
(注意 ,
作为分隔符而不是 ;
)
然后您可以使用以下 class 来保存您的 JSON 数据:
class Preferences {
@JsonProperty("newsletter")
private Map<String, String> newsLetter;
@Override
public String toString() {
return "Preferences{" + "newsLetter=" + newsLetter + '}';
}
}
在这里,您不再使用 NewsLetter
class,因为您需要一个嵌套键,就像 Roman C 在他的回答中所说的那样。只需将 Map
字段直接添加到您的 Preferences
class 即可。
您可以这样阅读您的 JSON:
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper();
System.out.println(om.readValue(new File("example.json"), Preferences.class));
}
它将打印:
Preferences{newsLetter={key1=value1, key2=value2, key3=value3}}
我想我成功了。
我用
- @JsonValue 创建时事通讯的 JSON 部分。
- @JsonCreator 使用地图创建 NewsLetter 实例
包含 key/value 对。
- @JsonTypeInfo 指示使用哪个实现来创建
NewsLetter 实例。
使用上面的 json 代码段,测试 运行 双向都很好。
在代码中(首选项 class 与原始问题中列出的相同):
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXISTING_PROPERTY, defaultImpl = NewsLetterPreferencesDefault.class)
public interface NewsLetterPreferences {
}
public final class NewsLetterPreferencesDefault {
private Map<String, String> properties;
@JsonCreator
public NewsLetterPreferencesDefault(final Map<String, String> properties) {
this.properties = properties.
}
@JsonValue
public Map<String, String> getAllProperties() {
return this.properties;
}
}
有办法吗?我以前从未使用过@JsonTypeInfo,所以我希望它是正确的。我会 google 一些更多的例子。感谢所有反馈。
您可以简单地使用 @JsonAnySetter
进行反序列化
Marker annotation that can be used to define a non-static, two-argument method (first argument name of property, second value to set), to be used as a "fallback" handler for all otherwise unrecognized properties found from JSON content.
和@JsonAnyGetter
用于序列化。
Marker annotation that can be used to define a non-static, no-argument method or member field as something of a reverse of JsonAnySetter
method; basically being used like a getter but such that contents of the returned Map (type must be Map
) are serialized as if they were actual properties of the bean that contains method/field with this annotations
public class Newsletter {
private final Map<String, String> properties = new HashMap<>();
@JsonAnySetter
public void addProperty(String name, String value) {
properties.put(name, value);
}
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
这对于您的用例来说应该可以正常工作。
测试
public class Main {
public static void main(String[] args) throws Exception {
String json
= "{\n"
+ " \"newsletter\": {\n"
+ " \"key1\": \"value1\",\n"
+ " \"key2\": \"value2\",\n"
+ " \"key3\": \"value3\"\n"
+ " }\n"
+ "}";
ObjectMapper mapper = new ObjectMapper();
Preferences prefs = mapper.readValue(json, Preferences.class);
Map<String, String> properties = prefs.getNewsletter().getProperties();
for (Map.Entry<String, String> prop: properties.entrySet()) {
System.out.println(prop.getKey() + ":" + prop.getValue());
}
}
}
另请参阅:
我必须如何将以下 json 片段绑定(双向)到 Jackson 下方的 Java 对象?
我希望 key/value 对 Json 时事通讯节点最终出现在时事通讯字段的地图中。 绑定这个的 Jackson 配置(注释和其他)必须是什么? 抱歉,我不知道如何:((使用最新版本的 Jackson)。
下面的Json格式是固定的,我从第三方rest服务那里得到的(我不能改变它)。我可以更改 java 代码,但更喜欢下面的设置。
JSON:
{
"newsletter": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
}
}
Java对象:
class Preferences {
private NewsLetter newsLetter;
// getter/setter for field newsLetter.
}
class NewsLettter {
private Map<String, String> properties;
// getter/setter for field properties.
}
以下是 JSON 到 Java 转换的工作原理
第一步是创建 Java class 来保存 JSON 数据。你已经有一个了。看看json。您创建一个 Preferences
对象来保存
整个 json。 json 包含一个 newsletter
元素。你
在 Preferences
对象中创建类型为 Newsletter
的 Java 对象。
创建 org.codehaus.jackson.map.ObjectMapper
class 的实例。这是 class
将 JSON 映射到 Java 对象。
ObjectMapper mapper = new ObjectMapper();
然后使用ObjectMapper
的readValue
方法进行读取。此方法有多个版本,您可以使用接受一个
String
。但是,有些方法可以从 URL
、File
、InputStream
、String
或 ByteArray
.
ObjectMapper
缓存序列化器和反序列化器,因此将一个 ObjectMapper
实例重用于多个实例是个好主意
转换
如果您有一个 String
然后将它传递给 Jackson 以将其转换为 Java Object.
String str = "
{ \"newsletter\":
{
\"properties\": {
\"key1\" : \"value1\",
\"key2\" : \"value2\",
\"key3\" : \"value3\"
}
}
}";
//read json
Preferences preferences = mapper.readValue(str, Preferences.class);
//write json
mapper.writeValue(str, preferences);
您可以使用将 json 转义为 java 字符串的工具:http://www.freeformatter.com/java-dotnet-escape.html
此工具产生以下结果
{ \"newsletter\":\r\n {\r\n \"properties\": {\r\n \"key1\" : \"value1\",\r\n \"key2\" : \"value2\",\r\n \"key3\" : \"value3\"\r\n }\r\n }\r\n }
如果你能得到一个道具JSON,像这样:
{ "newsletter": { "key1": "value1", "key2": "value2", "key3": "value3" } }
(注意 ,
作为分隔符而不是 ;
)
然后您可以使用以下 class 来保存您的 JSON 数据:
class Preferences {
@JsonProperty("newsletter")
private Map<String, String> newsLetter;
@Override
public String toString() {
return "Preferences{" + "newsLetter=" + newsLetter + '}';
}
}
在这里,您不再使用 NewsLetter
class,因为您需要一个嵌套键,就像 Roman C 在他的回答中所说的那样。只需将 Map
字段直接添加到您的 Preferences
class 即可。
您可以这样阅读您的 JSON:
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper();
System.out.println(om.readValue(new File("example.json"), Preferences.class));
}
它将打印:
Preferences{newsLetter={key1=value1, key2=value2, key3=value3}}
我想我成功了。 我用
- @JsonValue 创建时事通讯的 JSON 部分。
- @JsonCreator 使用地图创建 NewsLetter 实例 包含 key/value 对。
- @JsonTypeInfo 指示使用哪个实现来创建 NewsLetter 实例。
使用上面的 json 代码段,测试 运行 双向都很好。 在代码中(首选项 class 与原始问题中列出的相同):
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = JsonTypeInfo.As.EXISTING_PROPERTY, defaultImpl = NewsLetterPreferencesDefault.class)
public interface NewsLetterPreferences {
}
public final class NewsLetterPreferencesDefault {
private Map<String, String> properties;
@JsonCreator
public NewsLetterPreferencesDefault(final Map<String, String> properties) {
this.properties = properties.
}
@JsonValue
public Map<String, String> getAllProperties() {
return this.properties;
}
}
有办法吗?我以前从未使用过@JsonTypeInfo,所以我希望它是正确的。我会 google 一些更多的例子。感谢所有反馈。
您可以简单地使用 @JsonAnySetter
进行反序列化
Marker annotation that can be used to define a non-static, two-argument method (first argument name of property, second value to set), to be used as a "fallback" handler for all otherwise unrecognized properties found from JSON content.
和@JsonAnyGetter
用于序列化。
Marker annotation that can be used to define a non-static, no-argument method or member field as something of a reverse of
JsonAnySetter
method; basically being used like a getter but such that contents of the returned Map (type must beMap
) are serialized as if they were actual properties of the bean that contains method/field with this annotations
public class Newsletter {
private final Map<String, String> properties = new HashMap<>();
@JsonAnySetter
public void addProperty(String name, String value) {
properties.put(name, value);
}
@JsonAnyGetter
public Map<String, String> getProperties() {
return properties;
}
}
这对于您的用例来说应该可以正常工作。
测试
public class Main {
public static void main(String[] args) throws Exception {
String json
= "{\n"
+ " \"newsletter\": {\n"
+ " \"key1\": \"value1\",\n"
+ " \"key2\": \"value2\",\n"
+ " \"key3\": \"value3\"\n"
+ " }\n"
+ "}";
ObjectMapper mapper = new ObjectMapper();
Preferences prefs = mapper.readValue(json, Preferences.class);
Map<String, String> properties = prefs.getNewsletter().getProperties();
for (Map.Entry<String, String> prop: properties.entrySet()) {
System.out.println(prop.getKey() + ":" + prop.getValue());
}
}
}
另请参阅: