如何在 Java 中将 YAML 转换为 JSON?

Posted

技术标签:

【中文标题】如何在 Java 中将 YAML 转换为 JSON?【英文标题】:How do I convert from YAML to JSON in Java? 【发布时间】:2014-07-07 19:05:09 【问题描述】:

我只想将一个包含 yaml 的字符串转换为另一个包含使用 Java 转换的对应 json 的字符串。

例如假设我有这个 yaml 的内容

---
paper:
   uuid: 8a8cbf60-e067-11e3-8b68-0800200c9a66
   name: On formally undecidable propositions of Principia Mathematica and related systems I.
   author: Kurt Gödel.
tags:
   - tag:
       uuid: 98fb0d90-e067-11e3-8b68-0800200c9a66
       name: Mathematics
   - tag:
       uuid: 3f25f680-e068-11e3-8b68-0800200c9a66
       name: Logic

在名为 yamlDoc 的字符串中:

String yamlDoc = "---\npaper:\n   uuid: 8a... etc...";

我想要一些可以将yaml字符串转换为另一个带有相应json的字符串的方法,即以下代码

String yamlDoc = "---\npaper:\n   uuid: 8a... etc...";
String json = convertToJson(yamlDoc); // I want this method
System.out.println(json);

应该打印:


    "paper": 
        "uuid": "8a8cbf60-e067-11e3-8b68-0800200c9a66",
        "name": "On formally undecidable propositions of Principia Mathematica and related systems I.",
        "author": "Kurt Gödel."
    ,
    "tags": [
        
            "tag": 
                "uuid": "98fb0d90-e067-11e3-8b68-0800200c9a66",
                "name": "Mathematics"
            
        ,
        
            "tag": 
                "uuid": "3f25f680-e068-11e3-8b68-0800200c9a66",
                "name": "Logic"
            
        
    ]

我想知道在这个例子中是否存在类似于 convertToJson() 方法的东西。

我尝试使用SnakeYAML 来实现这一点,所以这段代码

 Yaml yaml = new Yaml();
 Map<String,Object> map = (Map<String, Object>) yaml.load(yamlDoc);

构造一个包含已解析 YAML 结构的映射(使用嵌套映射)。那么如果有一个解析器可以将地图转换为json字符串,它将解决我的问题,但我也没有找到类似的东西。

我们将不胜感激。

【问题讨论】:

使用 POJO 将允许您使用现有库,并且可能会自动执行。否则给自己一个 YAML 解析器,手动检查它,然后手动创建转换后的 JSON。 您在寻找什么?阅读您的帖子,我只能看到您不想做的事情。你准备做什么?抱歉,-1 因为没有显示任何解决此问题的尝试。我看到的都是我的问题,请帮我解决。 我知道Jackson can read and write YAML。也许使用 new ObjectMapper(new YAMLFactory()) 将 YAML 读入映射结构,然后使用 new ObjectMapper() 编写 JSON? 感谢superEb的建议,不知道Jackson会读YAMLs 肯定有一些工具可以将 YAML 转换为地图和列表。一旦如此转换,生成相应的 JSON 就很简单了。 【参考方案1】:

感谢 HotLicks 提示(在问题 cmets 中)我终于以这种方式使用库 org.json 和 SnakeYAML 实现了转换:

private static String convertToJson(String yamlString) 
    Yaml yaml= new Yaml();
    Map<String,Object> map= (Map<String, Object>) yaml.load(yamlString);

    JSONObject jsonObject=new JSONObject(map);
    return jsonObject.toString();

我不知道这是否是最好的方法,但它对我有用。

【讨论】:

由于第 3 行的未经检查的强制转换,这不起作用。每次都会抛出 ClassCastException。 org.json 链接已损坏,但这里是获取库的 maven 依赖项:&lt;dependencies&gt; &lt;dependency&gt; &lt;groupId&gt;org.json&lt;/groupId&gt; &lt;artifactId&gt;json&lt;/artifactId&gt; &lt;version&gt;20160810&lt;/version&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;pl.droidsonroids.yaml&lt;/groupId&gt; &lt;artifactId&gt;snakeyaml&lt;/artifactId&gt; &lt;version&gt;1.18.2&lt;/version&gt; &lt;/dependency&gt; &lt;/dependencies&gt;【参考方案2】:

非常感谢 Miguel A. Carrasco,他实际上已经解决了这个问题。但他的版本是限制性的。如果 root 是列表或原始值,他的代码将失败。最通用的解决方案是:

private static String convertToJson(String yamlString) 
    Yaml yaml= new Yaml();
    Object obj = yaml.load(yamlString);

    return JSONValue.toJSONString(obj);

【讨论】:

JSONValue 从何而来? 我相信他们使用的是 json-simple (javadoc: alex-public-doc.s3.amazonaws.com/json_simple-1.1/index.html),但该项目几乎被放弃了。核心 javax 包将是要走的路。(docs.oracle.com/javaee/7/api/javax/json/JsonValue.html) 使用 javax.json 会将方法从 JSONValue.ToJsonString 更改为 JsonValue.toString【参考方案3】:

这是一个使用 Jackson 的实现:

String convertYamlToJson(String yaml) 
    ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
    Object obj = yamlReader.readValue(yaml, Object.class);

    ObjectMapper jsonWriter = new ObjectMapper();
    return jsonWriter.writeValueAsString(obj);

要求:

compile('com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.7.4')

【讨论】:

最佳答案,因为它只依赖于 Jackson,而不是两个不同的库。 对我有用的是:ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory()); Object obj = yamlReader.readValue(new File("src/main/resources/file.yaml"), Object.class); ObjectMapper jsonWriter = new ObjectMapper(); String json = jsonWriter.writeValueAsString(obj); System.out.println(json); 这对我不起作用,当我们有一个数组时它是覆盖元素【参考方案4】:

我发现该示例在将 Swagger (OpenAPI) YAML 转换为 JSON 时没有生成正确的值。我写了如下例程:

  private static Object _convertToJson(Object o) throws JSONException 
    if (o instanceof Map) 
      Map<Object, Object> map = (Map<Object, Object>) o;

      JSONObject result = new JSONObject();

      for (Map.Entry<Object, Object> stringObjectEntry : map.entrySet()) 
        String key = stringObjectEntry.getKey().toString();

        result.put(key, _convertToJson(stringObjectEntry.getValue()));
      

      return result;
     else if (o instanceof ArrayList) 
      ArrayList arrayList = (ArrayList) o;
      JSONArray result = new JSONArray();

      for (Object arrayObject : arrayList) 
        result.put(_convertToJson(arrayObject));
      

      return result;
     else if (o instanceof String) 
      return o;
     else if (o instanceof Boolean) 
      return o;
     else 
      log.error("Unsupported class [0]", o.getClass().getName());
      return o;
    
  

然后我可以使用 SnakeYAML 来加载和输出 JSON:

Yaml yaml= new Yaml();
Map<String,Object> map= (Map<String, Object>) yaml.load(yamlString);

JSONObject jsonObject = (JSONObject) _convertToJson(map);
System.out.println(jsonObject.toString(2));

【讨论】:

【参考方案5】:

在寻找同一问题的解决方案时,我被定向到了这个问题。

我还偶然发现了以下文章https://dzone.com/articles/read-yaml-in-java-with-jackson

Jackson JSON 库似乎有一个基于 SnakeYAML 的 YAML 扩展。 由于 Jackson 是事实上的 JSON 库之一,我认为我应该在这里链接它。

【讨论】:

【参考方案6】:

谢谢,米格尔!你的例子帮助很大。我不想使用“JSON-java”库。我更喜欢GSON。但是将逻辑从 JSON-java 转换为 GSON 的域模型并不难。一个函数就可以解决问题:

/**
 * Wraps the object returned by the Snake YAML parser into a GSON JsonElement 
 * representation.  This is similar to the logic in the wrap() function of:
 * 
 * https://github.com/stleary/JSON-java/blob/master/JSONObject.java
 */
public static JsonElement wrapSnakeObject(Object o) 

    //NULL => JsonNull
    if (o == null)
        return JsonNull.INSTANCE;

    // Collection => JsonArray
    if (o instanceof Collection) 
        JsonArray array = new JsonArray();
        for (Object childObj : (Collection<?>)o)
            array.add(wrapSnakeObject(childObj));
        return array;
    

    // Array => JsonArray
    if (o.getClass().isArray()) 
        JsonArray array = new JsonArray();

        int length = Array.getLength(array);
        for (int i=0; i<length; i++)
            array.add(wrapSnakeObject(Array.get(array, i)));

        return array;
    

    // Map => JsonObject
    if (o instanceof Map) 
        Map<?, ?> map = (Map<?, ?>)o;

        JsonObject jsonObject = new JsonObject();
        for (final Map.Entry<?, ?> entry : map.entrySet()) 
            final String name = String.valueOf(entry.getKey());
            final Object value = entry.getValue();
            jsonObject.add(name, wrapSnakeObject(value));
        

        return jsonObject;
    

    // everything else => JsonPrimitive
    if (o instanceof String)
        return new JsonPrimitive((String)o);
    if (o instanceof Number)
        return new JsonPrimitive((Number)o);
    if (o instanceof Character)
        return new JsonPrimitive((Character)o);
    if (o instanceof Boolean)
        return new JsonPrimitive((Boolean)o);

    // otherwise.. string is a good guess
    return new JsonPrimitive(String.valueOf(o));

然后您可以使用以下命令从 YAML 字符串中解析 JsonElement:

Yaml yaml = new Yaml();
Map<String, Object> yamlMap = yaml.load(yamlString);
JsonElement jsonElem = wrapSnakeObject(yamlMap);

然后打印出来:

Gson gson = new GsonBuilder().setPrettyPrinting().create();
System.out.println(gson.toJson(jsonElem));

【讨论】:

这太复杂了,使用 Gson 可以简单得多。【参考方案7】:

使用 Gson:

var yaml = new YAML();
var gson = new Gson();        
var reader = new FileReader(path.toFile());
var obj = yaml.load(reader);
var writer = new StringWriter();
gson.toJson(obj, writer);
String result = writer.toString();

【讨论】:

【参考方案8】:

使用 kotlin 进行 Spring Boot 以将 yaml 文件内容作为 json 数据返回

package br.com.sportplace.controller

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.io.InputStream


@RestController
@RequestMapping(value = ["resources/docs"])
class DocsController 


    @GetMapping(produces = ["application/json"])
    fun load(): ResponseEntity<Any> 
        return getResourceFileAsString()
    

    fun getResourceFileAsString(): ResponseEntity<Any> 
        val inputStream = getResourceFileAsInputStream("openapi/api.yaml")
        return if (inputStream != null) 
            val objectMapper = ObjectMapper(YAMLFactory())
            ResponseEntity.ok(objectMapper.readValue(inputStream, Any::class.java))
         else 
            ResponseEntity(ErrorResponse(), HttpStatus.INTERNAL_SERVER_ERROR)
        
    

    fun getResourceFileAsInputStream(fileName: String?): InputStream? 
        val classLoader = DocsController::class.java.classLoader
        return classLoader.getResourceAsStream(fileName)
    

    private data class ErrorResponse(
        val message: String = "Failed to load resource file",
        val success: Boolean = false,
        val timestamp: Long = System.currentTimeMillis()
    )



    

【讨论】:

以上是关于如何在 Java 中将 YAML 转换为 JSON?的主要内容,如果未能解决你的问题,请参考以下文章

YamlDotNet 在 C# 中将 YAML 转换为 JSON

ruby 在红宝石中将yaml转换为json

ruby 在红宝石中将yaml转换为json

如何在 Retrofit 库中将 YAML 响应正文解析为 POJO?

如何使用 Java 库将标记的 YAML 对象转换为 JSON 对象?

如何在groovy中将java.lang.String转换为json