Jackson 将 YAML 文件反序列化为 Map(没有自定义反序列化器)

Posted

技术标签:

【中文标题】Jackson 将 YAML 文件反序列化为 Map(没有自定义反序列化器)【英文标题】:Jackson deserialization of YAML file into Map (with no custom deserializer) 【发布时间】:2019-02-08 17:17:23 【问题描述】:

我正在尝试将 YAML 文件加载到 Map 的实例中。有没有办法在不定义自定义反序列化器的情况下加载它(例如使用注释?)?

这是我的 YAML 文件的示例:

- site: First Site
  url: some_url
  username: some_name
  password: some_password
- site: Second Site
  url: its_url
  username: its_name
  password: its_password

这是将一个“站点配置”反序列化为(由http://www.jsonschema2pojo.org/ 生成)的 java bean 类:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import org.apache.commons.lang3.builder.ToStringBuilder;

@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder(
        "site",
        "url",
        "username",
        "password"
)
public class SiteConfiguration 

    @JsonProperty("site")
    private String site;
    @JsonProperty("url")
    private String url;
    @JsonProperty("username")
    private String username;
    @JsonProperty("password")
    private String password;

    /**
     * No args constructor for use in serialization
     *
     */
    public SiteConfiguration() 
    

    /**
     *
     * @param site
     * @param username
     * @param password
     * @param url
     */
    public SiteConfiguration(String site, String url, String username, String password) 
        super();
        this.site = site;
        this.url = url;
        this.username = username;
        this.password = password;
    

    @JsonProperty("site")
    public String getSite() 
        return site;
    

    @JsonProperty("site")
    public void setSite(String site) 
        this.site = site;
    

    @JsonProperty("url")
    public String getUrl() 
        return url;
    

    @JsonProperty("url")
    public void setUrl(String url) 
        this.url = url;
    

    @JsonProperty("username")
    public String getUsername() 
        return username;
    

    @JsonProperty("username")
    public void setUsername(String username) 
        this.username = username;
    

    @JsonProperty("password")
    public String getPassword() 
        return password;
    

    @JsonProperty("password")
    public void setPassword(String password) 
        this.password = password;
    

    @Override
    public String toString() 
        return new ToStringBuilder(this).append("site", site).append("url", url).append("username", username).append("password", password).toString();
    


最后,这是将上面的 YAML 反序列化为 Map 的代码。

    private static Map<String,SiteConfiguration> sites;
    public static SiteConfiguration getSiteConfiguration(String key) 
        if (sites == null) 
            ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
            try 
//          todo this finishes on: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.LinkedHashMap` out of START_ARRAY token
//                sites = mapper.readValue(YamlReader.class.getClass().getResource("/site-configuration.yaml"), new TypeReference<Map<String,SiteConfiguration>>() );
                SiteConfiguration[] sitesArray = mapper.readValue(YamlReader.class.getClass().getResource("/site-configuration.yaml"), SiteConfiguration[].class);
                sites = new HashMap<>();
                for (SiteConfiguration site : sitesArray)   //todo is there Jackson built-in deserialization?
                    sites.put(site.getSite(), site);
                
             catch (Exception e) 
                throw new RuntimeException(e);
            
        
        return sites.get(key);
    

如您所见,我分两步完成。首先我将文件反序列化为SiteConfiguration 实例的数组,然后将它们放入Map 其中site 字段代表映射键。

有没有办法在省略SiteConfiguration 实例的数组时做同样的事情?是使用自定义反序列化器的唯一方法吗?

【问题讨论】:

【参考方案1】:

更改 YAML 的结构。如果要将数据反序列化为地图,则需要在 YAML 文件中以地图的形式开始。您的示例中有一系列映射,但您需要映射的映射。

https://yaml.org/spec/1.2/spec.html#id2759963

示例 2.4。映射序列 (球员统计)

-
  name: Mark McGwire
  hr:   65
  avg:  0.278
-
  name: Sammy Sosa
  hr:   63
  avg:  0.288

示例 10.1。 !!地图示例

Block style: !!map
  Clark : Evans
  Ingy  : döt Net
  Oren  : Ben-Kiki

试试这个:

First Site:
  site: First Site
  url: some_url
  username: some_name
  password: some_password
Second Site:
  site: Second Site
  url: its_url
  username: its_name
  password: its_password

此结构适用于没有自定义反序列化器的 Jackson 2.9.9。

【讨论】:

以上是关于Jackson 将 YAML 文件反序列化为 Map(没有自定义反序列化器)的主要内容,如果未能解决你的问题,请参考以下文章

ruby 将YAML配置文件反序列化为单例实例

Jackson - 将内部对象列表反序列化为更高级别的列表

在Jackson的单个文件中反序列化来自多个YAML文档的POJO

Jackson:将枚举值序列化和反序列化为整数

Jackson 将日期字符串反序列化为 Long

Jackson 将额外字段反序列化为 Map