将 YAML 转储到字符串

问题描述 投票:0回答:1

我正在尝试将 YAML 对象转储到 String,但遇到了一些问题。这是原始的 YAML 信息:

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":""}'

如果我尝试使用 fastxml.jackson 进行转储,我会尝试以下操作:

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

结果:

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\":\"\"}"

所以在原文中可以看出,“trace_info”字符串值是双引号的,“error_gen_info”是单引号的。我希望“content_type”和“content”用单引号引起来,因为现在是双引号,并且值 json 看起来很糟糕。

现在如果我尝试使用snakeyaml,我会:

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

我得到:

!!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

这里我得到了不同的结果:

  1. 为什么我在课堂上排在第一行?有什么办法可以避免吗?
  2. 它不保持顺序,但这并不是那么重要。
  3. “内容”按我想要的方式处理,但没有引用任何字符串值。有没有办法说“traceInfo”中的字符串值必须用双引号引起来,而“errorGenInfo”中的字符串值必须用单引号引起来?
  4. 重要提示:尽管我添加了一些在其他帖子中看到的代码(使用“content-type”测试 TypeDescription.substituteProperty(...) ),但键名不是用下划线分隔的。好像不行。

完成此操作后,如何使用这两种处理 YAML 的方法在输出中获得相同的格式? 预先感谢。

java jackson yaml fasterxml snakeyaml
1个回答
0
投票

从 Jackson 的

YAMLGenerator
的源代码来看,看起来根本不可能使用单引号字符串。我能得到的最接近您预期的输出是直接使用
SnakeYAML
。除了按预期单引号引用的
content_type
字段之外,没有引用任何字符串值。并且 POJO 的字段顺序没有得到维护。我确实设法删除了带有类名的标签,并将字段名称重命名为蛇形大小写。

代码:

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

输出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
© www.soinside.com 2019 - 2024. All rights reserved.