Reputation: 1399
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
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
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
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
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
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
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
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
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