我已经定义了JSON响应,我希望将其反序列化为Java Objects。我设法做到这一点"手动"使用树模型,但如果可能,我想使用数据绑定。问题是我需要为某些部分提供一些自定义逻辑。
JSON看起来像这样:
{
"resourcedescriptions": [
{
"path": "somePath",
"tag_pagetype": "default",
"tag_bookingcenter": [
"bc_ch",
"bc_de"
],
"resources": [
{
"path": "somePathDe.html",
"lang": "de",
"lastmodified": 1399020442914,
"mimetype": "text/html"
},
{
"path": "somePathEn.html",
"lang": "en",
"lastmodified": 1399907224208,
"mimetype": "text/html"
}
],
"lastmodified": 1399907224208
},
{
"path": "someOtherPath",
"tag_pagetype": "special",
"tag_bookingcenter": [
"bc_ch"
],
"resources": [
{
"path": "someOtherPathDe.html",
"lang": "de",
"lastmodified": 1399020442914,
"mimetype": "text/html"
},
{
"path": "someOtherPathEn.html",
"lang": "en",
"lastmodified": 1399907224208,
"mimetype": "text/html"
}
],
"lastmodified": 1399907224208
}
]
}
我的Java类将是:
public class ResourceDescription {
private String path;
private LocalDateTime lastModified;
private String chartConfig;
private final List<Tag> tags = new ArrayList<Tag>();
private final List<Resource> resources = new ArrayList<Resource>();
}
public class Resource {
private String lang;
private String path;
private String mimeType;
private LocalDateTime lastModified;
}
public class Tag {
private String namespace;
private String name;
}
即使在这里阅读了很多帖子,我仍然不能完全理解的第一个问题。如何将这个资源数组从JSON反序列化为我的ResourceDescription列表?
第二个也是最复杂的问题。 JSON属性前缀为&#34;标记_&#34;需要转换为Tag类,而属性名称表示命名空间,值(单个或数组)表示名称。因此,如果模式是&#34; namespace:name&#34;,则第一个ResourceDescription将具有以下标记:
&#34;&#34; lastmodified&#34;应该从Joda-Time转换为DateTime。
这是否可以通过数据绑定实现,还是应该坚持使用树模型?
答案 0 :(得分:1)
您需要为ResourceDescription创建自定义反序列化器,以便完成您需要执行的操作。为ResourceDescription指定自定义反序列化器的语法如下所示:
@JsonDeserialize(using=ResourceDescriptionDeserializer.class)
public class ResourceDescription { ... }
这个反序列化器必须遍历每个资源描述的每个键,以查看它是否以&#34; tag _&#34;开头,剥去前缀并使用剩余的名称空间并填充名称/值在将标记添加到正在创建的ResourceDescription的数组之前用于标记。
对于所有其他属性/类型,我认为您可以按照默认的反序列化并在各自的字段中设置这些属性。
然后,要反序列化ResourceDescriptions列表,可以指定TypeReference以避免为ResourceDescriptions编写自定义反序列化程序。代码看起来像这样:
Map<String, List<ResourceDescription>> resultMap =
objectMapper.readValue(JSON, new TypeReference<Map<String, List<ResourceDescription>>>() {});
List<ResourceDescription> descriptions = resultMap.get("resourcedescriptions");
这篇文章与你正在做的事情并不完全配对,但我认为这有助于提出一般性的想法:
Using Jackson to deserialize array nested within array in JSON object
答案 1 :(得分:1)
如何将这个资源数组从JSON反序列化为我的 ResourceDescription列表?
您必须创建包含root
属性的其他resourcedescriptions
类。例如:
class Root {
private List<ResourceDescription> resourcedescriptions;
public List<ResourceDescription> getResourcedescriptions() {
return resourcedescriptions;
}
public void setResourcedescriptions(List<ResourceDescription> resourcedescriptions) {
this.resourcedescriptions = resourcedescriptions;
}
@Override
public String toString() {
return String.valueOf(resourcedescriptions);
}
}
以&#34;标记_&#34;为前缀的JSON属性;需要转变成 Tag类,而属性名称表示命名空间 值(单个或数组)代表名称。
您可以使用@JsonAnySetter
注释处理此案例。您必须向ResourceDescription
类添加新方法,如下所示:
@JsonAnySetter
public void setAnyValues(String propertyName, Object value) {
if (propertyName.startsWith("tag_")) {
if (value instanceof String) {
tags.add(new Tag(propertyName, value.toString()));
} else if (value instanceof List) {
List<?> values = (List<?>) value;
for (Object v : values) {
tags.add(new Tag(propertyName, v.toString()));
}
}
// throw exception?
} else {
// handle another unknown properties
}
}
&#34;&#34; lastmodified&#34;应该转换为DateTime 约达时间。
您可以通过添加jackson-datatype-joda库来处理JodaTime
类型。添加后,您可以注册JodaModule
模块。
mapper.registerModule(new JodaModule());
其他问题是JSON
包含使用小写编写的属性,但您的POJO
属性是使用camel-case编写的。您可以更改JSON
或POJO
或使用@JsonProperty("property-name-from-JSON")
注释或实施自己的命名策略。例如:
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.PropertyNamingStrategyBase() {
@Override
public String translate(String propertyName) {
return propertyName.toLowerCase();
}
});
完整的Java示例如何反序列化JSON
:
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.datatype.joda.JodaModule;
public class JacksonProgram {
public static void main(String[] args) throws Exception {
String json = "{ ... }";
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
mapper.setPropertyNamingStrategy(new PropertyNamingStrategy.PropertyNamingStrategyBase() {
@Override
public String translate(String propertyName) {
return propertyName.toLowerCase();
}
});
System.out.println(mapper.readValue(json, Root.class));
}
}
class Root {
private List<ResourceDescription> resourcedescriptions;
public List<ResourceDescription> getResourcedescriptions() {
return resourcedescriptions;
}
public void setResourcedescriptions(List<ResourceDescription> resourcedescriptions) {
this.resourcedescriptions = resourcedescriptions;
}
@Override
public String toString() {
return String.valueOf(resourcedescriptions);
}
}
class ResourceDescription {
private String path;
private LocalDateTime lastModified;
private String chartConfig;
private final List<Tag> tags = new ArrayList<Tag>();
private final List<Resource> resources = new ArrayList<Resource>();
@JsonAnySetter
public void setAnyValues(String propertyName, Object value) {
if (propertyName.startsWith("tag_")) {
if (value instanceof String) {
tags.add(new Tag(propertyName, value.toString()));
} else if (value instanceof List) {
List<?> values = (List<?>) value;
for (Object v : values) {
tags.add(new Tag(propertyName, v.toString()));
}
}
// throw exception?
} else {
// handle another unknown properties
}
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public LocalDateTime getLastModified() {
return lastModified;
}
public void setLastModified(LocalDateTime lastModified) {
this.lastModified = lastModified;
}
public String getChartConfig() {
return chartConfig;
}
public void setChartConfig(String chartConfig) {
this.chartConfig = chartConfig;
}
public List<Tag> getTags() {
return tags;
}
public List<Resource> getResources() {
return resources;
}
@Override
public String toString() {
return "ResourceDescription [path=" + path + ", lastModified=" + lastModified
+ ", chartConfig=" + chartConfig + ", tags=" + tags + ", resources=" + resources
+ "]";
}
}
class Resource {
private String lang;
private String path;
private String mimeType;
private LocalDateTime lastModified;
public String getLang() {
return lang;
}
public void setLang(String lang) {
this.lang = lang;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public LocalDateTime getLastModified() {
return lastModified;
}
public void setLastModified(LocalDateTime lastModified) {
this.lastModified = lastModified;
}
@Override
public String toString() {
return "Resource [lang=" + lang + ", path=" + path + ", mimeType=" + mimeType
+ ", lastModified=" + lastModified + "]";
}
}
class Tag {
private String namespace;
private String name;
public Tag() {
}
public Tag(String namespace, String name) {
this.namespace = namespace;
this.name = name;
}
public String getNamespace() {
return namespace;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Tag [namespace=" + namespace + ", name=" + name + "]";
}
}
以上程序打印:
[ResourceDescription [path=somePath, lastModified=2014-05-12T17:07:04.208, chartConfig=null, tags=[Tag [namespace=tag_pagetype, name=default], Tag [namespace=tag_bookingcenter, name=bc_ch], Tag [namespace=tag_bookingcenter, name=bc_de]], resources=[Resource [lang=de, path=somePathDe.html, mimeType=text/html, lastModified=2014-05-02T10:47:22.914], Resource [lang=en, path=somePathEn.html, mimeType=text/html, lastModified=2014-05-12T17:07:04.208]]], ResourceDescription [path=someOtherPath, lastModified=2014-05-12T17:07:04.208, chartConfig=null, tags=[Tag [namespace=tag_pagetype, name=special], Tag [namespace=tag_bookingcenter, name=bc_ch]], resources=[Resource [lang=de, path=someOtherPathDe.html, mimeType=text/html, lastModified=2014-05-02T10:47:22.914], Resource [lang=en, path=someOtherPathEn.html, mimeType=text/html, lastModified=2014-05-12T17:07:04.208]]]]