Miguel A. Carrasco
Miguel A. Carrasco

Reputation: 1399

How do I convert from YAML to JSON in Java?

I just want to convert a string that contains a yaml into another string that contains the corrseponding converted json using Java.

For example supose that I have the content of this 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

in a String called yamlDoc:

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

I want some method that can convert the yaml String into another String with the corresponding json, i.e. the following code

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

should print:

{
    "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"
            }
        }
    ]
}

I want to know if exists something similar to the convertToJson() method in this example.

I tried to achieve this using SnakeYAML, so this code

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

constructs a map that contain the parsed YAML structure (using nested Maps). Then if there is a parser that can convert a map into a json String it will solve my problem, but I didn't find something like that neither.

Any response will be greatly appreciated.

Upvotes: 44

Views: 78515

Answers (8)

Elias Meireles
Elias Meireles

Reputation: 1058

Spring boot with kotlin to return a yaml file content as json data

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()
    )
}


    

Upvotes: 0

Alexander Oh
Alexander Oh

Reputation: 25641

Using 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();

Upvotes: 2

Cory Klein
Cory Klein

Reputation: 55690

Here is an implementation that uses 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);
}

Requires:

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

Upvotes: 92

Dan R.
Dan R.

Reputation: 11

Thanks, Miguel! Your example helped a lot. I didn't want to use the 'JSON-java' library. I prefer GSON. But it wasn't hard to translate the logic from JSON-java over to GSON's domain model. A single function can do the trick:

/**
 * 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));
}

Then you can parse a JsonElement from a YAML String with:

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

and print it out with:

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

Upvotes: 1

MarkAddison
MarkAddison

Reputation: 565

I was directed to this question when searching for a solution to the same issue.

I also stumbled upon the following article https://dzone.com/articles/read-yaml-in-java-with-jackson

It seems Jackson JSON library has a YAML extension based upon SnakeYAML. As Jackson is one of the de facto libraries for JSON I thought that I should link this here.

Upvotes: 1

JonathanT
JonathanT

Reputation: 366

I found the example did not produce correct values when converting Swagger (OpenAPI) YAML to JSON. I wrote the following routine:

  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;
    }
  }

Then I could use SnakeYAML to load and output the JSON with the following:

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));

Upvotes: 3

Todor Kisov
Todor Kisov

Reputation: 51

Big thanks to Miguel A. Carrasco he infact has solved the issue. But his version is restrictive. His code fails if root is list or primitive value. Most general solution is:

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

    return JSONValue.toJSONString(obj);
}

Upvotes: 5

Miguel A. Carrasco
Miguel A. Carrasco

Reputation: 1399

Thanks to HotLicks tip (in the question comments) I finally achieve the conversion using the libraries org.json and SnakeYAML in this way:

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();
}

I don't know if it's the best way to do it, but it works for me.

Upvotes: 15

Related Questions