I'm trying to dump a YAML object to String but I'm facing some problems. This is the original YAML info:
trace_enabled: false
error_gen_enabled: false
trace_info:
filter: "filter-12345"
status: 200
method: "PUT"
error_gen_info:
code: 500
rate: 0.35
content_type: 'application/problem+json'
content: '{"status":503,"title":"Internal Server Error","detail":"Too busy","cause":""}'
If I try to dump with fasterxml.jackson I try the following:
ObjectMapper mapper = new ObjectMapper(new YAMLFactory().disable(Feature.WRITE_DOC_START_MARKER));
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
try {
result = mapper.writeValueAsString(yamlObject);
} catch (JsonProcessingException e) {
log.warn("Error parsing YAML object to string. Message: {}. Cause: {}", e.getMessage(), e.getCause());
}
And results:
trace_enabled: false
error_gen_enabled: false
trace_info:
filter: "filter-12345"
status: 200
method: "PUT"
error_gen_info:
code: 500
rate: 0.35
content_type: "application/problem+json"
content: "{\"status\":503,\"title\":\"Internal Server Error\",\"detail\":\"Too busy\"\
,\"cause\":\"\"}"
So it can be seen in the original that "trace_info" String values are double quoted, and "error_gen_info" are single quoted. I'd like that "content_type" and "content" would be single quoted, as now is double quoted and the value json looks terrible.
Now if I try with snakeyaml I do:
Representer representer = new Representer();
representer.addClassTag(ErrorGenInfo.class, Tag.OMAP);
representer.setDefaultFlowStyle(FlowStyle.BLOCK);
TypeDescription errorGenInfoDesc = new TypeDescription(ErrorGenInfo.class);
errorGenInfoDesc.substituteProperty("content_type", String.class, "getContentType", "setContentType");
representer.addTypeDescription(errorGenInfoDesc);
errorGenInfoDesc.setExcludes("contentType");
Yaml yaml = new Yaml(representer);
result = yaml.dump(yamlObject);
And I get:
!!com.test.BasicTest$Config
errorGenEnabled: false
errorGenInfo:
code: 500
content: '{"status":503,"title":"Internal Server Error","detail":"Too busy","cause":""}'
contentType: application/problem+json
rate: 0.35
traceEnabled: false
traceInfo:
filter: filter-12345
method: PUT
status: 200
Here I get a different result:
Having done this, how could I get the same format in the output with any of these 2 ways of processing YAML? Thanks in advance.
From the source code of Jackson's YAMLGenerator
, it didn't look like it was possible to single quote strings at all. The closest I could get to your expected output is using SnakeYAML
directly. No String values were quoted except for content_type
field which was single quoted as expected. And the order of fields with the POJOs wasn't maintained. I did manage to remove the tag with the class name and also to rename the field names to be snake case.
Code:
import io.github.devatherock.domain.ErrorGenInfo;
import io.github.devatherock.domain.ResponseBody;
import io.github.devatherock.domain.TraceInfo;
import lombok.extern.slf4j.Slf4j;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.DumperOptions.FlowStyle;
import org.yaml.snakeyaml.TypeDescription;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;
import org.yaml.snakeyaml.representer.Representer;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@Slf4j
public class TestUtil {
public static String toYaml(ResponseBody yamlObject) {
DumperOptions dumperOptions = new DumperOptions();
dumperOptions.setDefaultFlowStyle(FlowStyle.BLOCK);
dumperOptions.setSplitLines(false);
Representer representer = new Representer(dumperOptions);
// To rename fields
addTypeDescription(
Collections.singletonList("content_type"), Collections.singletonList("getContentType"),
Collections.singletonList("setContentType"), new String[]{"contentType"},
Collections.singletonList(String.class), ErrorGenInfo.class, representer
);
addTypeDescription(
Arrays.asList("trace_enabled", "error_gen_enabled", "trace_info", "error_gen_info"),
Arrays.asList("isTraceEnabled", "isErrorGenEnabled", "getTraceInfo", "getErrorGenInfo"),
Arrays.asList("setTraceEnabled", "setErrorGenEnabled", "setTraceInfo", "setErrorGenInfo"),
new String[]{"traceEnabled", "errorGenEnabled", "traceInfo", "errorGenInfo"},
Arrays.asList(Boolean.class, Boolean.class, TraceInfo.class, ErrorGenInfo.class),
ResponseBody.class, representer
);
// To disable the tags with class name
representer.addClassTag(ResponseBody.class, Tag.MAP);
representer.addClassTag(ErrorGenInfo.class, Tag.MAP);
Yaml yaml = new Yaml(representer);
String result = yaml.dump(yamlObject);
LOGGER.info("Result: \n{}", result);
return result;
}
public static void addTypeDescription(
List<String> propertyNames, List<String> getterNames, List<String> setterNames,
String[] propertiesToExclude, List<Class<?>> propertyClasses,
Class<?> beanClass, Representer representer
) {
TypeDescription typeDescription = new TypeDescription(beanClass);
for (int index = 0; index < propertyNames.size(); index++) {
typeDescription.substituteProperty(
propertyNames.get(index), propertyClasses.get(index), getterNames.get(index), setterNames.get(index)
);
}
typeDescription.setExcludes(propertiesToExclude);
representer.addTypeDescription(typeDescription);
}
}
Output YAML:
trace_enabled: false
error_gen_enabled: false
trace_info:
filter: filter-12345
method: PUT
status: 200
error_gen_info:
content_type: application/problem+json
code: 500
content: '{"status":503,"title":"Internal Server Error","detail":"Too busy","cause":""}'
rate: 0.35