1. <!-- yaml -->
  2. <dependency>
  3. <groupId>com.amihaiemil.web</groupId>
  4. <artifactId>eo-yaml</artifactId>
  5. <version>${eo-yaml.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.yaml</groupId>
  9. <artifactId>snakeyaml</artifactId>
  10. <version>${snakeyaml.version}</version>
  11. </dependency>
  1. import com.alibaba.fastjson.JSON;
  2. import com.amihaiemil.eoyaml.*;
  3. import com.amihaiemil.eoyaml.exceptions.YamlIndentationException;
  4. import com.isyscore.os.config.pojo.enumeration.ConfigValueTypeEnum;
  5. import lombok.Data;
  6. import lombok.experimental.UtilityClass;
  7. import lombok.extern.slf4j.Slf4j;
  8. import org.yaml.snakeyaml.DumperOptions;
  9. import java.util.*;
  10. import java.util.concurrent.ConcurrentHashMap;
  11. import java.util.function.BiFunction;
  12. import java.util.function.Function;
  13. import java.util.regex.Matcher;
  14. import java.util.regex.Pattern;
  15. import java.util.stream.Collectors;
  16. /**
  17. * yaml与其他各种格式之间互转
  18. * <p>
  19. * <ul>
  20. * <li>1.yaml <> properties</li>
  21. * <li>2.yaml <> json</li>
  22. * <li>3.yaml <> map</li>
  23. * <li>4.yaml <> list</li>
  24. * <li>5.yaml <> kvList</li>
  25. * </ul>
  26. *
  27. * @author shizi
  28. * @since 2020/9/14 3:17 下午
  29. */
  30. @Slf4j
  31. @SuppressWarnings("all")
  32. @UtilityClass
  33. public class YamlUtil {
  34. /**
  35. * 换行符
  36. */
  37. private final String NEW_LINE = "\n";
  38. /**
  39. * 注释标识
  40. */
  41. private final String REMARK_PRE = "# ";
  42. /**
  43. * 缩进空格
  44. */
  45. private final String INDENT_BLANKS = " ";
  46. /**
  47. * 分号连接符
  48. */
  49. private final String SIGN_SEMICOLON = ":";
  50. /**
  51. * 等号连接符
  52. */
  53. private final String SIGN_EQUAL = "=";
  54. /**
  55. * 点
  56. */
  57. private final String DOT = ".";
  58. /**
  59. * 数组缩进
  60. */
  61. private final String ARRAY_BLANKS = "- ";
  62. /**
  63. * yaml的value换行符
  64. */
  65. private final String yaml_NEW_LINE_DOM = "|\n";
  66. private final Pattern rangePattern = Pattern.compile("^(.*)\\[(\\d*)\\]$");
  67. /**
  68. * 格式转换的缓存
  69. */
  70. private final Map<String, Object> typeContentMap = new ConcurrentHashMap<>();
  71. /**
  72. * 判断类型是否是yaml类型
  73. *
  74. * @param content yaml 内容
  75. * @return true:是yaml,false:不是
  76. */
  77. public boolean isYaml(String content) {
  78. if (isEmpty(content)) {
  79. return false;
  80. }
  81. return cacheCompute("isYaml", content, () -> {
  82. if (!content.contains(":") && !content.contains("-")) {
  83. return false;
  84. }
  85. try {
  86. checkYaml(content);
  87. return true;
  88. } catch (ValueCheckException e) {
  89. return false;
  90. }
  91. });
  92. }
  93. /**
  94. * 判断是否是yaml类型
  95. *
  96. * @param content 内容
  97. * @throws ValueCheckException 核查异常
  98. */
  99. public void checkYaml(String content) {
  100. if (isEmpty(content)) {
  101. throw new ValueCheckException("yaml内容为空");
  102. }
  103. if (!content.contains(":") && !content.contains("-")) {
  104. throw new ValueCheckException("yaml内容不包含\":\"也不包含\"-\"");
  105. }
  106. if (content.contains("---\n")) {
  107. throw new ValueCheckException("yaml内容不支持 --- 的导入");
  108. }
  109. try {
  110. yamlToProperties(content);
  111. } catch (ValueChangeException e) {
  112. throw new ValueCheckException("内容不是严格yaml类型;" + e.getMessage());
  113. }
  114. }
  115. /**
  116. * 判断是否是properties类型
  117. *
  118. * @param content 内容
  119. * @return true:是properties类型,false:不是properties类型
  120. */
  121. public boolean isProperties(String content) {
  122. if (isEmpty(content)) {
  123. return false;
  124. }
  125. return cacheCompute("isProperties", content, () -> {
  126. if (!content.contains("=")) {
  127. return false;
  128. }
  129. try {
  130. checkProperties(content);
  131. return true;
  132. } catch (ValueCheckException e) {
  133. return false;
  134. }
  135. });
  136. }
  137. /**
  138. * 判断是否是properties类型
  139. *
  140. * @param content 内容
  141. * @throws ValueCheckException 核查异常
  142. */
  143. public void checkProperties(String content) {
  144. if (isEmpty(content)) {
  145. throw new ValueCheckException("properties内容为空");
  146. }
  147. if (!content.contains("=")) {
  148. throw new ValueCheckException("properties内容不包含\"=\"");
  149. }
  150. try {
  151. checkYaml(propertiesToYaml(content));
  152. } catch (Throwable e) {
  153. throw new ValueCheckException("内容不是严格properties类型;" + e.getMessage());
  154. }
  155. }
  156. /**
  157. * 判断是否是json类型
  158. *
  159. * @param content 内容
  160. * @return true:是json类型,false:不是json类型
  161. */
  162. public boolean isJson(String content) {
  163. if (isEmpty(content)) {
  164. return false;
  165. }
  166. return cacheCompute("isJson", content, () -> {
  167. if (!content.startsWith("{") && !content.startsWith("[")) {
  168. return false;
  169. }
  170. try {
  171. checkJson(content);
  172. return true;
  173. } catch (ValueCheckException e) {
  174. return false;
  175. }
  176. });
  177. }
  178. /**
  179. * 判断是否是json对象类型
  180. *
  181. * @param content 内容
  182. * @return true:是json对象类型,false:不是json对象类型
  183. */
  184. public boolean isJsonObject(String content) {
  185. if (isEmpty(content)) {
  186. return false;
  187. }
  188. return cacheCompute("isJsonObject", content, () -> {
  189. try {
  190. checkJsonObject(content);
  191. return true;
  192. } catch (ValueCheckException e) {
  193. return false;
  194. }
  195. });
  196. }
  197. /**
  198. * 判断是否是json数组类型
  199. *
  200. * @param content 内容
  201. * @return true:是json数组类型,false:不是json数组类型
  202. */
  203. public boolean isJsonArray(String content) {
  204. if (isEmpty(content)) {
  205. return false;
  206. }
  207. return cacheCompute("isJsonArray", content, () -> {
  208. try {
  209. checkJsonArray(content);
  210. return true;
  211. } catch (ValueCheckException e) {
  212. return false;
  213. }
  214. });
  215. }
  216. /**
  217. * 判断是否是json类型
  218. *
  219. * @param content 内容
  220. * @throws ValueCheckException 核查异常
  221. */
  222. public void checkJson(String content) {
  223. if (isEmpty(content)) {
  224. throw new ValueCheckException("json内容不是严格json类型,因为内容为空");
  225. }
  226. // 先核查是否是object
  227. if (content.startsWith("{")) {
  228. try {
  229. JSON.parseObject(content);
  230. } catch (Throwable e) {
  231. throw new ValueCheckException("json内容不是严格json对象类型;" + e.getMessage());
  232. }
  233. } else if (content.startsWith("[")) {
  234. try {
  235. JSON.parseArray(content);
  236. } catch (Throwable e) {
  237. throw new ValueCheckException("json内容不是严格json数组类型;" + e.getMessage());
  238. }
  239. } else {
  240. throw new ValueCheckException("json内容不是json类型,因为没有\"{\"也没有\"[\"开头");
  241. }
  242. }
  243. /**
  244. * 判断是否是json对象类型
  245. *
  246. * @param content 内容
  247. * @throws ValueCheckException 核查异常
  248. */
  249. public void checkJsonObject(String content) {
  250. if (isEmpty(content)) {
  251. throw new ValueCheckException("json内容不是严格json对象类型,因为内容为空");
  252. }
  253. try {
  254. JSON.parseObject(content);
  255. } catch (Throwable e) {
  256. throw new ValueCheckException("内容不是严格json对象类型;" + e.getMessage());
  257. }
  258. }
  259. /**
  260. * 判断是否是json数组类型
  261. *
  262. * @param content 内容
  263. * @throws ValueCheckException 核查异常
  264. */
  265. public void checkJsonArray(String content) {
  266. if (isEmpty(content)) {
  267. throw new ValueCheckException("json内容不是严格json数组类型,因为内容为空");
  268. }
  269. try {
  270. JSON.parseArray(content);
  271. } catch (Throwable e) {
  272. throw new ValueCheckException("内容不是严格json对象类型;" + e.getMessage());
  273. }
  274. }
  275. /**
  276. * yaml格式转properties
  277. *
  278. * @param key key
  279. * @param content 对应的yaml内容
  280. * @return properties内容
  281. * @throws ValueChangeException 转换异常
  282. */
  283. public String yamlToProperties(String key, String content) {
  284. if (isEmpty(content)) {
  285. return null;
  286. }
  287. return cacheCompute("yamlToProperties", key, content, () -> {
  288. try {
  289. if (!content.contains(":") && !content.contains("-")) {
  290. return null;
  291. }
  292. if (content.trim().startsWith("-")) {
  293. Map<String, Object> dataMap = new HashMap<>();
  294. dataMap.put(key, yamlToList(content));
  295. return yamlToProperties(mapToYaml(dataMap));
  296. }
  297. return propertiesAppendPrefixKey(key, yamlToProperties(content));
  298. } catch (Throwable e) {
  299. throw new ValueChangeException("yaml 转换到 properties异常:" + e.getMessage());
  300. }
  301. });
  302. }
  303. /**
  304. * yaml格式转换到properties
  305. *
  306. * @param content yaml内容
  307. * @return properties内容
  308. * @throws ValueChangeException 转换异常
  309. */
  310. public String yamlToProperties(String content) {
  311. if (isEmpty(content)) {
  312. return null;
  313. }
  314. return cacheCompute("yamlToProperties", content, () -> {
  315. try {
  316. if (!content.contains(":") && !content.contains("-")) {
  317. return null;
  318. }
  319. if (content.trim().startsWith("-")) {
  320. throw new ValueChangeException("不支持数组的yaml转properties");
  321. }
  322. List<String> propertiesList = new ArrayList<>();
  323. Map<String, String> remarkMap = new LinkedHashMap<>();
  324. Map<String, Object> valueMap = yamlToMap(content);
  325. // 读取yaml的注释
  326. yamlToRemarkMap(remarkMap, Yaml.createYamlInput(content).readYamlMapping(), "");
  327. formatYamlToProperties(propertiesList, remarkMap, valueMap, "");
  328. return propertiesList.stream().filter(e -> null != e && !"".equals(e)).reduce((a, b) -> a + NEW_LINE + b).orElse("");
  329. } catch (Throwable e) {
  330. throw new ValueChangeException(e);
  331. }
  332. });
  333. }
  334. public Properties yamlToPropertiesValue(String content) {
  335. if (isEmpty(content)) {
  336. return null;
  337. }
  338. return cacheCompute("yamlToProperties", content, () -> {
  339. try {
  340. if (!content.contains(":") && !content.contains("-")) {
  341. return null;
  342. }
  343. if (content.trim().startsWith("-")) {
  344. return null;
  345. }
  346. Properties properties = new Properties();
  347. Map<String, String> remarkMap = new LinkedHashMap<>();
  348. Map<String, Object> valueMap = yamlToMap(content);
  349. // 读取yaml的注释
  350. yamlToRemarkMap(remarkMap, Yaml.createYamlInput(content).readYamlMapping(), "");
  351. formatYamlToPropertiesValue(properties, remarkMap, valueMap, "");
  352. return properties;
  353. } catch (Throwable e) {
  354. throw new ValueChangeException(e);
  355. }
  356. });
  357. }
  358. /**
  359. * properties 转换到 yaml
  360. *
  361. * @param properties properties内容
  362. * @return yaml内容
  363. * @throws ValueChangeException 转换异常
  364. */
  365. public String propertiesToYaml(Properties properties) {
  366. if (properties.isEmpty()) {
  367. return null;
  368. }
  369. return cacheCompute("propertiesToYaml", properties, () -> {
  370. StringBuilder stringBuilder = new StringBuilder();
  371. properties.forEach((k, v) -> stringBuilder.append(k).append("=").append(v).append(NEW_LINE));
  372. return propertiesToYaml(stringBuilder.toString());
  373. });
  374. }
  375. /**
  376. * properties类型转换到json
  377. *
  378. * @param properties properties 内容
  379. * @return json内容
  380. * @throws ValueChangeException 转换异常
  381. */
  382. public String propertiesToJson(Properties properties) {
  383. return yamlToJson(propertiesToYaml(properties));
  384. }
  385. /**
  386. * properties内容转换到json
  387. *
  388. * @param content properties内容
  389. * @return json内容
  390. * @throws ValueChangeException 转换异常
  391. */
  392. public String propertiesToJson(String content) {
  393. return yamlToJson(propertiesToYaml(content));
  394. }
  395. /**
  396. * properties内容转换到map
  397. *
  398. * @param content properties内容
  399. * @return map内容
  400. * @throws ValueChangeException 转换异常
  401. */
  402. public Map<String, Object> propertiesToMap(String content) {
  403. if (isEmpty(content)) {
  404. return null;
  405. }
  406. return cacheCompute("propertiesToMap", content, () -> {
  407. if (!content.contains("=")) {
  408. return null;
  409. }
  410. Map<String, Object> resultMap = new HashMap<>();
  411. List<String> propertiesLineWordList = getPropertiesItemLineList(content);
  412. for (String line : propertiesLineWordList) {
  413. String lineTem = line.trim();
  414. if (!"".equals(lineTem)) {
  415. int index = lineTem.indexOf("=");
  416. if (index > -1) {
  417. String key = lineTem.substring(0, index);
  418. String value = lineTem.substring(index + 1);
  419. // 对于yaml中换行的添加|用于保留换行
  420. if (value.contains("\n")) {
  421. value = yaml_NEW_LINE_DOM + value;
  422. }
  423. resultMap.put(key, value);
  424. }
  425. }
  426. }
  427. return resultMap;
  428. });
  429. }
  430. /**
  431. * properties 转换到 yaml
  432. *
  433. * @param content properties内容
  434. * @return yaml内容
  435. * @throws ValueChangeException 转换异常
  436. */
  437. public String propertiesToYaml(String content) {
  438. if (isEmpty(content)) {
  439. return null;
  440. }
  441. return cacheCompute("propertiesToYaml", content, () -> {
  442. if (!content.contains("=")) {
  443. return null;
  444. }
  445. try {
  446. List<String> yamlLineList = new ArrayList<>();
  447. List<String> propertiesLineWordList = getPropertiesItemLineList(content);
  448. List<YamlNode> YamlNodes = new ArrayList<>();
  449. StringBuilder projectRemark = new StringBuilder();
  450. StringBuilder remark = new StringBuilder();
  451. for (String line : propertiesLineWordList) {
  452. String lineTem = line.trim();
  453. if (!"".equals(lineTem)) {
  454. if (lineTem.startsWith("#")) {
  455. if (0 != remark.length()) {
  456. projectRemark.append(remark.toString());
  457. remark.delete(0, remark.length());
  458. }
  459. remark.append(lineTem);
  460. continue;
  461. }
  462. int index = lineTem.indexOf("=");
  463. if (index > -1) {
  464. String key = lineTem.substring(0, index);
  465. String value = lineTem.substring(index + 1);
  466. // 对于yaml中换行的添加|用于保留换行
  467. if (value.contains("\n")) {
  468. value = yaml_NEW_LINE_DOM + value;
  469. }
  470. final List<String> lineWordList = new ArrayList<>(Arrays.asList(key.split("\\.")));
  471. wordToNode(lineWordList, YamlNodes, null, false, null, appendSpaceForArrayValue(value), projectRemark.toString(), remark.toString());
  472. }
  473. // 删除本地保留
  474. remark.delete(0, remark.length());
  475. projectRemark.delete(0, projectRemark.length());
  476. }
  477. }
  478. formatPropertiesToYaml(yamlLineList, YamlNodes, false, "");
  479. return yamlLineList.stream().reduce((a, b) -> a + "\n" + b).orElse("") + "\n";
  480. } catch (Throwable e) {
  481. throw new ValueChangeException("properties 转换到 yaml异常:" + e.getMessage());
  482. }
  483. });
  484. }
  485. /**
  486. * yaml 转换到 对象
  487. *
  488. * @param content properties内容
  489. * @return yaml内容
  490. * @throws ValueChangeException 转换异常
  491. */
  492. public Object yamlToObject(String content) {
  493. if (isEmpty(content)) {
  494. return null;
  495. }
  496. return cacheCompute("yamlToObject", content, () -> {
  497. if (!content.contains(":") && !content.contains("-")) {
  498. return null;
  499. }
  500. if (content.trim().startsWith("-")) {
  501. return yamlToList(content);
  502. }
  503. return yamlToMap(content);
  504. });
  505. }
  506. /**
  507. * yaml 转 map
  508. *
  509. * 由于eo-yaml对map转换支持会默认将一些key添加字符,这里就用snakeyaml工具做
  510. * @return map 对象
  511. * @throws ValueChangeException 转换异常
  512. */
  513. @SuppressWarnings({"unchecked", "rawtypes"})
  514. public Map<String, Object> yamlToMap(String content) {
  515. if (isEmpty(content)) {
  516. return null;
  517. }
  518. return cacheCompute("yamlToMap", content, () -> {
  519. if (!content.contains(":") && !content.contains("-")) {
  520. return null;
  521. }
  522. try {
  523. Map<String, Object> resultMap = new HashMap<>();
  524. org.yaml.snakeyaml.Yaml yml = new org.yaml.snakeyaml.Yaml();
  525. Map result = yml.loadAs(content, Map.class);
  526. Set<Map.Entry<?, ?>> entrySet = result.entrySet();
  527. for (Map.Entry<?, ?> entry : entrySet) {
  528. resultMap.put(String.valueOf(entry.getKey()), entry.getValue());
  529. }
  530. return resultMap;
  531. } catch (Throwable e) {
  532. throw new ValueChangeException("yml 转换到 map 异常:" + e.getMessage());
  533. }
  534. });
  535. }
  536. /**
  537. * yaml 转 map
  538. *
  539. * @param content yaml内容
  540. * @return 集合内容
  541. * @throws ValueChangeException 转换异常
  542. */
  543. public List<Object> yamlToList(String content) {
  544. if (isEmpty(content)) {
  545. return null;
  546. }
  547. return cacheCompute("yamlToList", content, () -> {
  548. if (!content.trim().startsWith("-")) {
  549. return null;
  550. }
  551. try {
  552. org.yaml.snakeyaml.Yaml yml = new org.yaml.snakeyaml.Yaml();
  553. return yml.load(content);
  554. } catch (Throwable e) {
  555. throw new ValueChangeException("yml 转换到 map 异常:" + e.getMessage());
  556. }
  557. });
  558. }
  559. /**
  560. * map 转 yaml
  561. *
  562. * @param contentMap map内容
  563. * @return yaml内容
  564. * @throws ValueChangeException 转换异常
  565. */
  566. public String mapToYaml(Map<String, Object> contentMap) {
  567. if (isEmpty(contentMap)) {
  568. return null;
  569. }
  570. return cacheCompute("yamlToList", contentMap, () -> {
  571. try {
  572. org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml();
  573. String originalYaml = yaml.dumpAsMap(contentMap);
  574. // 由于snakeyaml对数组缩进支持不够好,这里做一层缩进
  575. return yamlFormatForMap(originalYaml);
  576. } catch (Throwable e) {
  577. throw new ValueChangeException("map 转换到 yml 异常:" + e.getMessage());
  578. }
  579. });
  580. }
  581. /**
  582. * 集合内容转yaml
  583. *
  584. * @param contentList 集合内容
  585. * @return yaml内容
  586. * @throws ValueChangeException 转换异常
  587. */
  588. public String listToYaml(List<Object> contentList) {
  589. if (isEmpty(contentList)) {
  590. return null;
  591. }
  592. return cacheCompute("listToYaml", contentList, () -> {
  593. try {
  594. org.yaml.snakeyaml.Yaml yaml = new org.yaml.snakeyaml.Yaml();
  595. return yaml.dumpAs(contentList, null, DumperOptions.FlowStyle.BLOCK);
  596. } catch (Throwable e) {
  597. throw new ValueChangeException("map 转换到 yml 异常:" + e.getMessage());
  598. }
  599. });
  600. }
  601. /**
  602. * yaml 转 json
  603. *
  604. * @param content yaml内容
  605. * @return json内容
  606. * @throws ValueChangeException 转换异常
  607. */
  608. public String yamlToJson(String content) {
  609. if (isEmpty(content)) {
  610. return null;
  611. }
  612. return cacheCompute("yamlToJson", content, () -> {
  613. if (!content.contains(":") && !content.contains("-")) {
  614. return null;
  615. }
  616. try {
  617. return JSON.toJSONString(yamlToObject(content));
  618. } catch (Throwable e) {
  619. throw new ValueChangeException("yaml 转换到 json 异常:" + e.getMessage());
  620. }
  621. });
  622. }
  623. /**
  624. * json 转 对象
  625. *
  626. * @param content json内容
  627. * @return object内容
  628. * @throws ValueChangeException 转换异常
  629. */
  630. public Object jsonToObject(String content) {
  631. if (isEmpty(content)) {
  632. return null;
  633. }
  634. return cacheCompute("jsonToObject", content, () -> {
  635. if (!content.startsWith("{") && !content.startsWith("[")) {
  636. return null;
  637. }
  638. try {
  639. if (isJsonObject(content)) {
  640. return JSON.parseObject(content);
  641. } else if (isJsonArray(content)) {
  642. return JSON.parseArray(content);
  643. }
  644. throw new ValueChangeException("content 不是json类型");
  645. } catch (Throwable e) {
  646. throw new ValueChangeException("json 转换到 yaml 异常:" + e.getMessage());
  647. }
  648. });
  649. }
  650. /**
  651. * json 转 yaml
  652. *
  653. * @param content json内容
  654. * @return yaml内容
  655. * @throws ValueChangeException 转换异常
  656. */
  657. public String jsonToYaml(String content) {
  658. if (isEmpty(content)) {
  659. return null;
  660. }
  661. return cacheCompute("jsonToYaml", content, () -> {
  662. if (!content.startsWith("{") && !content.startsWith("[")) {
  663. return null;
  664. }
  665. try {
  666. if (isJsonObject(content)) {
  667. return mapToYaml(JSON.parseObject(content));
  668. } else if (isJsonArray(content)) {
  669. return listToYaml(JSON.parseArray(content));
  670. }
  671. throw new ValueChangeException("content 不是json类型");
  672. } catch (Throwable e) {
  673. throw new ValueChangeException("json 转换到 yaml 异常:" + e.getMessage());
  674. }
  675. });
  676. }
  677. /**
  678. * yaml类型转换为 k-v的集合
  679. *
  680. * @param content yaml内容
  681. * @return kv集合
  682. * @throws ValueChangeException 转换异常
  683. */
  684. public List<Map.Entry<String, String>> yamlToKVList(String content) {
  685. if (isEmpty(content)) {
  686. return null;
  687. }
  688. return cacheCompute("yamlToKVList", content, () -> {
  689. if (!content.contains(":") && !content.contains("-")) {
  690. return null;
  691. }
  692. try {
  693. String propertiesContent = yamlToProperties(content);
  694. return getPropertiesItemLineList(propertiesContent).stream().map(e -> {
  695. int index = e.indexOf("=");
  696. String key = e.substring(0, index);
  697. String value = e.substring(index + 1);
  698. return new AbstractMap.SimpleEntry<>(key, value);
  699. }).collect(Collectors.toList());
  700. } catch (Throwable e) {
  701. throw new ValueChangeException("yaml 转换到 kv-list 异常:" + e.getMessage());
  702. }
  703. });
  704. }
  705. /**
  706. * k-v的集合类型转yaml
  707. *
  708. * @param kvStringList kv集合
  709. * @return yaml内容
  710. * @throws ValueChangeException 转换异常
  711. */
  712. public String kvListToYaml(List<Map.Entry<String, Object>> kvStringList) {
  713. if (isEmpty(kvStringList)) {
  714. return null;
  715. }
  716. return cacheCompute("kvListToYaml", kvStringList, () -> {
  717. try {
  718. String propertiesContent = kvStringList.stream().map(e -> e.getKey() + "=" + e.getValue()).reduce((a, b) -> a + "\n" + b).orElse("");
  719. return propertiesToYaml(propertiesContent);
  720. } catch (Throwable e) {
  721. throw new ValueChangeException("kv-list 转换到 yaml 异常:" + e.getMessage());
  722. }
  723. });
  724. }
  725. public String kvToYaml(String key, String value, ConfigValueTypeEnum valueTypeEnum) {
  726. if (isEmpty(key)) {
  727. return null;
  728. }
  729. return cacheCompute("kvToYaml", key, value, () -> {
  730. try {
  731. return propertiesToYaml(kvToProperties(key, value, valueTypeEnum));
  732. } catch (Throwable e) {
  733. throw new ValueChangeException("kv 转换到 yaml 异常:" + e.getMessage());
  734. }
  735. });
  736. }
  737. public Map<String, Object> kvToMap(String key, String value, ConfigValueTypeEnum valueTypeEnum) {
  738. if (isEmpty(key)) {
  739. return null;
  740. }
  741. return cacheCompute("kvToMap", key, value, () -> propertiesToMap(kvToProperties(key, value, valueTypeEnum)));
  742. }
  743. public String kvToProperties(String key, String value, ConfigValueTypeEnum valueTypeEnum) {
  744. return cacheCompute("kvToProperties", key, value, () -> kvToProperties(key, value, null, valueTypeEnum));
  745. }
  746. /**
  747. * k-v的String类型转properties
  748. *
  749. * <p>其中key可能是a.b.c这种,而value可能是各种各样的类型,我们这里通过valueType进行区分
  750. *
  751. * @param key 主键
  752. * @param value 待转换的值
  753. * @param desc 注释
  754. * @param valueTypeEnum 值的类型,0:yaml,1:properties,2:json,3:string
  755. * @return 转换之后的yaml类型
  756. * @throws ValueChangeException 转换异常
  757. */
  758. public String kvToProperties(String key, String value, String desc, ConfigValueTypeEnum valueTypeEnum) {
  759. if (isEmpty(key)) {
  760. return null;
  761. }
  762. return cacheCompute("kvToProperties", key, value, desc, () -> {
  763. try {
  764. // 将value对应的值先转换为properties类型,然后对key进行拼接,最后再统一转化为yaml格式
  765. StringBuilder propertiesResult = new StringBuilder();
  766. if (null != desc && !"".equals(desc)) {
  767. propertiesResult.append("# ").append(desc).append("\n");
  768. }
  769. String propertiesContent;
  770. switch (valueTypeEnum) {
  771. case YAML:
  772. propertiesContent = yamlToProperties(key, value);
  773. if (!isEmpty(propertiesContent)) {
  774. propertiesResult.append(propertiesContent);
  775. }
  776. return propertiesResult.toString();
  777. case JSON:
  778. propertiesContent = yamlToProperties(key, jsonToYaml(value));
  779. if (!isEmpty(propertiesContent)) {
  780. propertiesResult.append(propertiesContent);
  781. }
  782. return propertiesResult.toString();
  783. case PROPERTIES:
  784. propertiesContent = propertiesAppendPrefixKey(key, value);
  785. if (!isEmpty(propertiesContent)) {
  786. propertiesResult.append(propertiesContent);
  787. }
  788. return propertiesResult.toString();
  789. case STRING:
  790. propertiesResult.append(key).append("=").append(appendSpaceForArrayValue(value));
  791. return propertiesResult.toString();
  792. default:
  793. break;
  794. }
  795. return propertiesResult.toString();
  796. } catch (Throwable e) {
  797. throw new ValueChangeException("kv 转换到 properties 异常: " + e.getMessage());
  798. }
  799. });
  800. }
  801. public List<String> getPropertiesItemLineList(String content) {
  802. if (isEmpty(content)) {
  803. return Collections.emptyList();
  804. }
  805. return cacheCompute("getPropertiesItemLineList", content, () -> {
  806. if (!content.contains("=")) {
  807. return Collections.emptyList();
  808. }
  809. String[] lineList = content.split(NEW_LINE);
  810. List<String> itemLineList = new ArrayList<>();
  811. StringBuilder stringBuilder = new StringBuilder();
  812. for (String line : lineList) {
  813. // 处理多行数据
  814. if (line.endsWith("\\")) {
  815. stringBuilder.append(line).append("\n");
  816. } else {
  817. stringBuilder.append(line);
  818. itemLineList.add(stringBuilder.toString());
  819. stringBuilder.delete(0, stringBuilder.length());
  820. }
  821. }
  822. return itemLineList;
  823. });
  824. }
  825. private String propertiesAppendPrefixKey(String key, String propertiesContent) {
  826. return getPropertiesItemLineList(propertiesContent).stream().filter(e -> e.contains("=")).map(e -> {
  827. int index = e.indexOf("=");
  828. if (index > -1) {
  829. String keyTem = e.substring(0, index).trim();
  830. String valueTem = e.substring(index + 1).trim();
  831. return key + DOT + keyTem + "=" + valueTem;
  832. }
  833. return null;
  834. }).filter(Objects::nonNull).reduce((a, b) -> a + NEW_LINE + b).orElse(null);
  835. }
  836. /**
  837. * 针对有些yaml格式不严格,这里做不严格向严格的eo-yaml解析的转换
  838. * <p>
  839. * 对{@code
  840. * test:
  841. * - k1: 12
  842. * - k2: 22
  843. * }
  844. * 这种做一层缩进,由于snake的map转yaml后有缩进问题
  845. */
  846. private String yamlFormatForMap(String content) {
  847. if (isEmpty(content)) {
  848. return null;
  849. }
  850. return cacheCompute("yamlFormatForMap", content, () -> {
  851. if (!content.contains(":") && !content.contains("-")) {
  852. return null;
  853. }
  854. StringBuilder stringBuilder = new StringBuilder();
  855. String[] items = content.split("\n");
  856. Integer blankSize = null;
  857. // 判断是否在数组中
  858. boolean inArray = false;
  859. for (String item : items) {
  860. int innerBlankSize = item.substring(0, item.indexOf(item.trim())).length();
  861. // 数组
  862. if (item.trim().startsWith("- ")) {
  863. if (inArray) {
  864. // 多重数组,则多层嵌套
  865. if (innerBlankSize > blankSize) {
  866. stringBuilder.append(INDENT_BLANKS).append(INDENT_BLANKS).append(item).append("\n");
  867. continue;
  868. }
  869. }
  870. inArray = true;
  871. blankSize = innerBlankSize;
  872. } else {
  873. // 其他的字符
  874. if (null != blankSize) {
  875. if (innerBlankSize <= blankSize) {
  876. inArray = false;
  877. }
  878. }
  879. }
  880. if (inArray) {
  881. stringBuilder.append(INDENT_BLANKS).append(item).append("\n");
  882. } else {
  883. stringBuilder.append(item).append("\n");
  884. }
  885. }
  886. return stringBuilder.toString();
  887. });
  888. }
  889. /**
  890. * 将key转换为yaml节点
  891. *
  892. * @param lineWordList 待转换的key,比如{@code k1.k2.k3=123}
  893. * @param nodeList 已经保存的节点数据
  894. * @param lastNodeArrayFlag 上一个节点是否数组类型
  895. * @param index 索引下标
  896. * @param value 解析的值
  897. * @param remark 当前value对应的注释
  898. */
  899. private void wordToNode(List<String> lineWordList, List<YamlNode> nodeList, YamlNode parentNode, Boolean lastNodeArrayFlag, Integer index, String value, String projectRemark,
  900. String remark) {
  901. if (lineWordList.isEmpty()) {
  902. if (lastNodeArrayFlag) {
  903. YamlNode node = new YamlNode();
  904. node.setValue(value);
  905. node.setRemark(remark);
  906. nodeList.add(node);
  907. }
  908. } else {
  909. String nodeName = lineWordList.get(0);
  910. Pair<String, Integer> nameAndIndex = peelArray(nodeName);
  911. nodeName = nameAndIndex.getKey();
  912. Integer nextIndex = nameAndIndex.getValue();
  913. YamlNode node = new YamlNode();
  914. node.setName(nodeName);
  915. node.setProjectRemark(projectRemark);
  916. node.setParent(parentNode);
  917. node.setRemark(remark);
  918. node.setLastNodeIndex(index);
  919. lineWordList.remove(0);
  920. //如果节点下面的子节点数量为0,则为终端节点,也就是赋值节点
  921. if (lineWordList.size() == 0) {
  922. if (null == nextIndex) {
  923. node.setRemark(remark);
  924. node.setValue(value);
  925. }
  926. }
  927. // nextIndex 不空,表示当前节点为数组,则之后的数据为他的节点数据
  928. if (null != nextIndex) {
  929. node.setArrayFlag(true);
  930. boolean hasEqualsName = false;
  931. //遍历查询节点是否存在
  932. for (YamlNode YamlNode : nodeList) {
  933. //如果节点名称已存在,则递归添加剩下的数据节点
  934. if (nodeName.equals(YamlNode.getName()) && YamlNode.getArrayFlag()) {
  935. Integer yamlNodeIndex = YamlNode.getLastNodeIndex();
  936. if (null == yamlNodeIndex || index.equals(yamlNodeIndex)) {
  937. hasEqualsName = true;
  938. wordToNode(lineWordList, YamlNode.getValueList(), node.getParent(), true, nextIndex, appendSpaceForArrayValue(value), null, remark);
  939. }
  940. }
  941. }
  942. //如果遍历结果为节点名称不存在,则递归添加剩下的数据节点,并把新节点添加到上级yamlTree的子节点中
  943. if (!hasEqualsName) {
  944. wordToNode(lineWordList, node.getValueList(), node.getParent(), true, nextIndex, appendSpaceForArrayValue(value), null, remark);
  945. nodeList.add(node);
  946. }
  947. } else {
  948. boolean hasEqualsName = false;
  949. //遍历查询节点是否存在
  950. for (YamlNode YamlNode : nodeList) {
  951. if (!lastNodeArrayFlag) {
  952. //如果节点名称已存在,则递归添加剩下的数据节点
  953. if (nodeName.equals(YamlNode.getName())) {
  954. hasEqualsName = true;
  955. wordToNode(lineWordList, YamlNode.getChildren(), YamlNode, false, nextIndex, appendSpaceForArrayValue(value), null, remark);
  956. }
  957. } else {
  958. //如果节点名称已存在,则递归添加剩下的数据节点
  959. if (nodeName.equals(YamlNode.getName())) {
  960. Integer yamlNodeIndex = YamlNode.getLastNodeIndex();
  961. if (null == yamlNodeIndex || index.equals(yamlNodeIndex)) {
  962. hasEqualsName = true;
  963. wordToNode(lineWordList, YamlNode.getChildren(), YamlNode, true, nextIndex, appendSpaceForArrayValue(value), null, remark);
  964. }
  965. }
  966. }
  967. }
  968. //如果遍历结果为节点名称不存在,则递归添加剩下的数据节点,并把新节点添加到上级yamlTree的子节点中
  969. if (!hasEqualsName) {
  970. wordToNode(lineWordList, node.getChildren(), node, false, nextIndex, appendSpaceForArrayValue(value), null, remark);
  971. nodeList.add(node);
  972. }
  973. }
  974. }
  975. }
  976. /**
  977. * 获取yaml中的注释
  978. *
  979. * @param remarkMap 解析后填充的注释map:key为a.b.c.d,value为对应的注释,去除掉前缀#后的数据
  980. * @param mapping yaml解析后数据
  981. * @param prefix 前缀
  982. */
  983. private void yamlToRemarkMap(Map<String, String> remarkMap, YamlMapping mapping, String prefix) {
  984. if (null == mapping) {
  985. return;
  986. }
  987. for (com.amihaiemil.eoyaml.YamlNode node : mapping.keys()) {
  988. String nodeName = node.asScalar().value();
  989. String remark = mapping.value(node).comment().value();
  990. if (null != remark && !"".equals(remark)) {
  991. remarkMap.put(wrapKey(prefix, nodeName), remark);
  992. }
  993. yamlToRemarkMap(remarkMap, mapping.yamlMapping(node), wrapKey(prefix, nodeName));
  994. }
  995. }
  996. private String wrapKey(String prefix, String value) {
  997. if (isEmpty(prefix)) {
  998. return prefix + "." + value;
  999. }
  1000. return value;
  1001. }
  1002. /**
  1003. * 解析节点名字,为数组则返回数组名和节点下标
  1004. * <p>
  1005. * name.test[0] 将test和0进行返回
  1006. *
  1007. * @param nodeName 界面的名字
  1008. * @return 如果是数组,则将数组名和解析后的下标返回
  1009. */
  1010. private Pair<String, Integer> peelArray(String nodeName) {
  1011. String name = nodeName;
  1012. Integer index = null;
  1013. Matcher matcher = rangePattern.matcher(nodeName);
  1014. if (matcher.find()) {
  1015. String indexStr = matcher.group(2);
  1016. if (null != indexStr) {
  1017. index = Integer.valueOf(indexStr);
  1018. }
  1019. name = matcher.group(1);
  1020. }
  1021. return new Pair<>(name, index);
  1022. }
  1023. /**
  1024. * 将yaml对应的这种value进行添加前缀空格,其中value为key1对应的value
  1025. * {@code
  1026. * test:
  1027. * key1: |
  1028. * value1
  1029. * value2
  1030. * value3
  1031. * }
  1032. * 对应的值
  1033. * {@code
  1034. * |
  1035. * value1
  1036. * value2
  1037. * value3
  1038. * }
  1039. *
  1040. * @param value 待转换的值比如{@code
  1041. * test:
  1042. * key1: |
  1043. * value1
  1044. * value2
  1045. * value3
  1046. * }
  1047. * @return 添加前缀空格之后的处理
  1048. * {@code
  1049. * |
  1050. * value1
  1051. * value2
  1052. * value3
  1053. * }
  1054. */
  1055. private String appendSpaceForArrayValue(String value) {
  1056. if (!value.startsWith(yaml_NEW_LINE_DOM)) {
  1057. return value;
  1058. }
  1059. String valueTem = value.substring(yaml_NEW_LINE_DOM.length());
  1060. return yaml_NEW_LINE_DOM + Arrays.stream(valueTem.split("\\n")).map(e -> {
  1061. String tem = e;
  1062. if (e.endsWith("\\")) {
  1063. tem = e.substring(0, e.length() - 1);
  1064. }
  1065. return INDENT_BLANKS + tem;
  1066. }).reduce((a, b) -> a + "\n" + b).orElse(valueTem);
  1067. }
  1068. private void formatPropertiesToYaml(List<String> yamlLineList, List<YamlNode> YamlNodes, Boolean lastNodeArrayFlag, String blanks) {
  1069. Integer beforeNodeIndex = null;
  1070. String equalSign;
  1071. for (YamlNode YamlNode : YamlNodes) {
  1072. String value = YamlNode.getValue();
  1073. String remark = YamlNode.getRemark();
  1074. equalSign = SIGN_SEMICOLON;
  1075. if (null == value || "".equals(value)) {
  1076. value = "";
  1077. } else {
  1078. equalSign = SIGN_SEMICOLON + " ";
  1079. }
  1080. YamlNode.resortValue();
  1081. String name = YamlNode.getName();
  1082. if (lastNodeArrayFlag) {
  1083. if (null == name) {
  1084. yamlLineList.add(blanks + ARRAY_BLANKS + stringValueWrap(value));
  1085. } else {
  1086. if (null != beforeNodeIndex && beforeNodeIndex.equals(YamlNode.getLastNodeIndex())) {
  1087. yamlLineList.add(blanks + INDENT_BLANKS + name + equalSign + stringValueWrap(value));
  1088. } else {
  1089. yamlLineList.add(blanks + ARRAY_BLANKS + name + equalSign + stringValueWrap(value));
  1090. }
  1091. }
  1092. beforeNodeIndex = YamlNode.getLastNodeIndex();
  1093. } else {
  1094. // 父节点为空,表示,当前为顶层
  1095. if (null == YamlNode.getParent()) {
  1096. String remarkTem = getRemarkProject(YamlNode.getProjectRemark());
  1097. if (!"".equals(remarkTem)) {
  1098. yamlLineList.add(blanks + getRemarkProject(YamlNode.getProjectRemark()));
  1099. }
  1100. }
  1101. // 自己节点为数组,则添加对应的注释
  1102. if (YamlNode.getArrayFlag()) {
  1103. if (null != remark && !"".equals(remark)) {
  1104. yamlLineList.add(blanks + remark);
  1105. }
  1106. }
  1107. yamlLineList.add(blanks + name + equalSign + stringValueWrap(value, remark));
  1108. }
  1109. if (YamlNode.getArrayFlag()) {
  1110. if (lastNodeArrayFlag) {
  1111. formatPropertiesToYaml(yamlLineList, YamlNode.getValueList(), true, INDENT_BLANKS + INDENT_BLANKS + blanks);
  1112. } else {
  1113. formatPropertiesToYaml(yamlLineList, YamlNode.getValueList(), true, INDENT_BLANKS + blanks);
  1114. }
  1115. } else {
  1116. if (lastNodeArrayFlag) {
  1117. formatPropertiesToYaml(yamlLineList, YamlNode.getChildren(), false, INDENT_BLANKS + INDENT_BLANKS + blanks);
  1118. } else {
  1119. formatPropertiesToYaml(yamlLineList, YamlNode.getChildren(), false, INDENT_BLANKS + blanks);
  1120. }
  1121. }
  1122. }
  1123. }
  1124. @SuppressWarnings("rawtypes")
  1125. private void formatYamlToProperties(List<String> propertiesLineList, Map<String, String> remarkMap, Object object, String prefix) {
  1126. if (null == object) {
  1127. return;
  1128. }
  1129. if (object instanceof Map) {
  1130. // 填充注释
  1131. if (remarkMap.containsKey(prefix)) {
  1132. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefix));
  1133. }
  1134. Map map = (Map) object;
  1135. Set<?> set = map.keySet();
  1136. for (Object key : set) {
  1137. Object value = map.get(key);
  1138. if (null == value) {
  1139. value = "";
  1140. }
  1141. if (value instanceof Map) {
  1142. formatYamlToProperties(propertiesLineList, remarkMap, value, prefixWithDOT(prefix) + key);
  1143. } else if (value instanceof Collection) {
  1144. Collection collection = (Collection) value;
  1145. if (!collection.isEmpty()) {
  1146. // 填充注释
  1147. if (remarkMap.containsKey(prefixWithDOT(prefix) + key)) {
  1148. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefixWithDOT(prefix) + key));
  1149. }
  1150. Iterator<?> iterator = collection.iterator();
  1151. int index = 0;
  1152. while (iterator.hasNext()) {
  1153. Object valueObject = iterator.next();
  1154. formatYamlToProperties(propertiesLineList, remarkMap, valueObject, prefixWithDOT(prefix) + key + "[" + index + "]");
  1155. index = index + 1;
  1156. }
  1157. }
  1158. } else if (value instanceof String) {
  1159. String valueStr = (String) value;
  1160. valueStr = valueStr.trim();
  1161. valueStr = valueStr.replace("\n", "\\\n");
  1162. // 填充注释
  1163. if (remarkMap.containsKey(prefixWithDOT(prefix) + key)) {
  1164. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefixWithDOT(prefix) + key));
  1165. }
  1166. propertiesLineList.add(prefixWithDOT(prefix) + key + SIGN_EQUAL + valueStr);
  1167. } else {
  1168. // 填充注释
  1169. if (remarkMap.containsKey(prefixWithDOT(prefix) + key)) {
  1170. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefixWithDOT(prefix) + key));
  1171. }
  1172. propertiesLineList.add(prefixWithDOT(prefix) + key + SIGN_EQUAL + value);
  1173. }
  1174. }
  1175. } else if (object instanceof Collection) {
  1176. Collection collection = (Collection) object;
  1177. if (!collection.isEmpty()) {
  1178. // 填充注释
  1179. if (remarkMap.containsKey(prefix)) {
  1180. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefix));
  1181. }
  1182. Iterator<?> iterator = collection.iterator();
  1183. int index = 0;
  1184. while (iterator.hasNext()) {
  1185. Object valueObject = iterator.next();
  1186. formatYamlToProperties(propertiesLineList, remarkMap, valueObject, prefix + "[" + index + "]");
  1187. index = index + 1;
  1188. }
  1189. }
  1190. } else if (object.getClass().isArray()) {
  1191. Object[] array = (Object[]) object;
  1192. for (int index = 0; index < array.length; index++) {
  1193. formatYamlToProperties(propertiesLineList, remarkMap, array[index], prefix + "[" + index + "]");
  1194. }
  1195. } else if (object instanceof String) {
  1196. String valueObject = (String) object;
  1197. valueObject = valueObject.replace("\n", "\\\n");
  1198. // 填充注释
  1199. if (remarkMap.containsKey(prefix)) {
  1200. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefix));
  1201. }
  1202. propertiesLineList.add(prefix + SIGN_EQUAL + valueObject);
  1203. } else {
  1204. // 填充注释
  1205. if (remarkMap.containsKey(prefix)) {
  1206. propertiesLineList.add(REMARK_PRE + remarkMap.get(prefix));
  1207. }
  1208. propertiesLineList.add(prefix + SIGN_EQUAL + object);
  1209. }
  1210. }
  1211. @SuppressWarnings("rawtypes")
  1212. private void formatYamlToPropertiesValue(Properties properties, Map<String, String> remarkMap, Object object, String prefix) {
  1213. if (null == object) {
  1214. return;
  1215. }
  1216. if (object instanceof Map) {
  1217. Map map = (Map) object;
  1218. Set<?> set = map.keySet();
  1219. for (Object key : set) {
  1220. Object value = map.get(key);
  1221. if (null == value) {
  1222. value = "";
  1223. }
  1224. if (value instanceof Map) {
  1225. formatYamlToPropertiesValue(properties, remarkMap, value, prefixWithDOT(prefix) + key);
  1226. } else if (value instanceof Collection) {
  1227. Collection collection = (Collection) value;
  1228. if (!collection.isEmpty()) {
  1229. Iterator<?> iterator = collection.iterator();
  1230. int index = 0;
  1231. while (iterator.hasNext()) {
  1232. Object valueObject = iterator.next();
  1233. formatYamlToPropertiesValue(properties, remarkMap, valueObject, prefixWithDOT(prefix) + key + "[" + index + "]");
  1234. index = index + 1;
  1235. }
  1236. }
  1237. } else if (value instanceof String) {
  1238. String valueStr = (String) value;
  1239. valueStr = valueStr.trim();
  1240. valueStr = valueStr.replace("\n", "\\\n");
  1241. properties.put(prefixWithDOT(prefix) + key, valueStr);
  1242. } else {
  1243. properties.put(prefixWithDOT(prefix) + key, value);
  1244. }
  1245. }
  1246. } else if (object instanceof Collection) {
  1247. Collection collection = (Collection) object;
  1248. if (!collection.isEmpty()) {
  1249. Iterator<?> iterator = collection.iterator();
  1250. int index = 0;
  1251. while (iterator.hasNext()) {
  1252. Object valueObject = iterator.next();
  1253. formatYamlToPropertiesValue(properties, remarkMap, valueObject, prefix + "[" + index + "]");
  1254. index = index + 1;
  1255. }
  1256. }
  1257. } else if (object.getClass().isArray()) {
  1258. Object[] array = (Object[]) object;
  1259. for (int index = 0; index < array.length; index++) {
  1260. formatYamlToPropertiesValue(properties, remarkMap, array[index], prefix + "[" + index + "]");
  1261. }
  1262. } else if (object instanceof String) {
  1263. String valueObject = (String) object;
  1264. valueObject = valueObject.replace("\n", "\\\n");
  1265. properties.put(prefix, valueObject);
  1266. } else {
  1267. properties.put(prefix, object);
  1268. }
  1269. }
  1270. private String prefixWithDOT(String prefix) {
  1271. if ("".equals(prefix)) {
  1272. return prefix;
  1273. }
  1274. return prefix + DOT;
  1275. }
  1276. private String stringValueWrap(String value) {
  1277. if (isEmpty(value)) {
  1278. return "";
  1279. }
  1280. // 对数组的数据进行特殊处理
  1281. if (value.startsWith("[") && value.endsWith("]")) {
  1282. return "'" + value + "'";
  1283. }
  1284. return value;
  1285. }
  1286. private String stringValueWrap(String value, String remark) {
  1287. if (isEmpty(value)) {
  1288. return "";
  1289. }
  1290. // 对数组的数据进行特殊处理
  1291. if (value.startsWith("[") && value.endsWith("]")) {
  1292. return "'" + value + "'" + getRemark(remark);
  1293. }
  1294. return value + getRemark(remark);
  1295. }
  1296. private String getRemark(String remark) {
  1297. if (null != remark && !"".endsWith(remark) && remark.startsWith("#")) {
  1298. return " # " + remark.substring(1).trim();
  1299. } else {
  1300. return "";
  1301. }
  1302. }
  1303. private String getRemarkProject(String remark) {
  1304. if (null != remark && !"".endsWith(remark) && remark.startsWith("#")) {
  1305. return " # " + remark.substring(1).trim();
  1306. } else {
  1307. return "";
  1308. }
  1309. }
  1310. /**
  1311. * 数据存在则返回,不存在则计算后添加到缓存中
  1312. */
  1313. @SuppressWarnings("unchecked")
  1314. private <T> T cacheCompute(String funName, Object key, Supplier<T> biFunction) {
  1315. String cacheKey = buildCacheKey(funName, key);
  1316. if (typeContentMap.containsKey(cacheKey)) {
  1317. return (T) typeContentMap.get(cacheKey);
  1318. }
  1319. T result = biFunction.get();
  1320. if (null != result) {
  1321. typeContentMap.put(cacheKey, result);
  1322. }
  1323. return result;
  1324. }
  1325. @SuppressWarnings("unchecked")
  1326. private <T> T cacheCompute(String funName, Object key, Object value, Supplier<T> biFunction) {
  1327. String cacheKey = buildCacheKey(funName, key, value);
  1328. if (typeContentMap.containsKey(cacheKey)) {
  1329. return (T) typeContentMap.get(cacheKey);
  1330. }
  1331. T result = biFunction.get();
  1332. if (null != result) {
  1333. typeContentMap.put(cacheKey, result);
  1334. }
  1335. return result;
  1336. }
  1337. private <T> T cacheCompute(String funName, Object key, Object value, String desc, Supplier<T> biFunction) {
  1338. String cacheKey = buildCacheKey(funName, key, value, desc);
  1339. if (typeContentMap.containsKey(cacheKey)) {
  1340. return (T) typeContentMap.get(cacheKey);
  1341. }
  1342. T result = biFunction.get();
  1343. if (null != result) {
  1344. typeContentMap.put(cacheKey, result);
  1345. }
  1346. return result;
  1347. }
  1348. private String buildCacheKey(String funName, Object... parameters) {
  1349. StringBuilder stringBuilder = new StringBuilder(funName);
  1350. for (Object parameter : parameters) {
  1351. if (null != parameter) {
  1352. stringBuilder.append(":").append(parameter.toString());
  1353. }
  1354. }
  1355. return stringBuilder.toString();
  1356. }
  1357. private boolean isEmpty(String string) {
  1358. return null == string || "".endsWith(string);
  1359. }
  1360. private boolean isEmpty(Collection<?> collection) {
  1361. return null == collection || collection.isEmpty();
  1362. }
  1363. private boolean isEmpty(Map<?, ?> map) {
  1364. return null == map || map.isEmpty();
  1365. }
  1366. @Data
  1367. class YamlNode {
  1368. private YamlNode parent;
  1369. /**
  1370. * 只有parent为null时候,该值才可能有值
  1371. */
  1372. private String projectRemark;
  1373. /**
  1374. * name
  1375. */
  1376. private String name;
  1377. /**
  1378. * value
  1379. */
  1380. private String value;
  1381. /**
  1382. * 注释
  1383. */
  1384. private String remark;
  1385. /**
  1386. * 子节点
  1387. */
  1388. private List<YamlNode> children = new ArrayList<>();
  1389. /**
  1390. * 数组标示:
  1391. */
  1392. private Boolean arrayFlag = false;
  1393. /**
  1394. * 存储的数组中的前一个节点的下标
  1395. */
  1396. private Integer lastNodeIndex;
  1397. /**
  1398. * 只有数组标示为true,下面的value才有值
  1399. */
  1400. private List<YamlNode> valueList = new ArrayList<>();
  1401. /**
  1402. * 将其中的value按照index下标顺序进行重拍
  1403. */
  1404. public void resortValue() {
  1405. if (!arrayFlag || valueList.isEmpty()) {
  1406. return;
  1407. }
  1408. // 升序
  1409. valueList.sort((a, b) -> {
  1410. if (null == a.getLastNodeIndex() || null == b.getLastNodeIndex()) {
  1411. return 0;
  1412. }
  1413. return a.getLastNodeIndex() - b.getLastNodeIndex();
  1414. });
  1415. // 是数组的节点也循环下
  1416. valueList.forEach(YamlNode::resortValue);
  1417. }
  1418. }
  1419. }
import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author shizi
 * @since 2020/11/13 6:11 PM
 */
@AllArgsConstructor
public enum ConfigValueTypeEnum {

    /**
     * yaml配置
     */
    YAML("yaml配置"),
    /**
     * properties配置
     */
    PROPERTIES("properties配置"),
    /**
     * 打包中
     */
    JSON("json配置"),
    /**
     * string对应的kv配置
     */
    STRING("string对应的kv配置");

    @Getter
    private final String desc;

    private static final Map<Integer, ConfigValueTypeEnum> INDEX_ENUM_MAP;
    private static final Map<String, ConfigValueTypeEnum> NAME_ENUM_MAP;

    static {
        INDEX_ENUM_MAP = Arrays.stream(ConfigValueTypeEnum.values()).collect(Collectors.toMap(ConfigValueTypeEnum::ordinal, e -> e));
        NAME_ENUM_MAP = Arrays.stream(ConfigValueTypeEnum.values()).collect(Collectors.toMap(ConfigValueTypeEnum::name, e -> e));
    }

    public static ConfigValueTypeEnum parse(Integer index) {
        if (!INDEX_ENUM_MAP.containsKey(index)) {
            throw new RuntimeException("不支持下标: " + index);
        }
        return INDEX_ENUM_MAP.get(index);
    }

    public static ConfigValueTypeEnum parse(String name) {
        if (!NAME_ENUM_MAP.containsKey(name)) {
            throw new RuntimeException("不支持name: " + name);
        }
        return NAME_ENUM_MAP.get(name);
    }
}
public class ValueChangeException extends RuntimeException{

    public ValueChangeException(Throwable e) {
        super(e);
    }

    public ValueChangeException(String message) {
        super(message);
    }

    public ValueChangeException(String message, Throwable e) {
        super(message, e);
    }
}
public class ValueCheckException extends RuntimeException{

    public ValueCheckException(Throwable e) {
        super(e);
    }

    public ValueCheckException(String message) {
        super(message);
    }

    public ValueCheckException(String message, Throwable e) {
        super(message, e);
    }
}

properties 转 yml

package com.simon.ocean.yml;

import com.simon.ocean.FileUtil;
import com.simon.ocean.YamlUtil;
import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author shizi
 * @since 2020/10/16 8:38 下午
 */
public class YamlUtilPropertiesToYamlTest {

    /**
     * 基本测试
     *
     * a.b.c.d.e=1
     * a.b1.c1.d1.e1=1
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlBaseTest() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/base.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/base.yml");

        //a:
        //  b:
        //    c:
        //      d:
        //        e: 1
        //  b1:
        //    c1:
        //      d1:
        //        e1: 1
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 基本测试:带注释
     *
     * # 总的
     * # test
     * a.b.c=1
     * # 测试1
     * a.b1.c.d.e=1
     * # 用来说明xxx
     * a.b2.c1.d1.e1=1
     * a.b2.c1.d1.e2=2
     * a.b2.c1.d1.e3=3
     * # 数组
     * a.b2.c1.d2[0]=3
     * a.b2.c1.d2[1]=3
     * a.b2.c1.d2[2]=3
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlBase1Test() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/base1.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/base1.yml");

        //# 总的
        //a:
        //  b:
        //    c: 1 # test
        //  b1:
        //    c:
        //      d:
        //        e: 1 # 测试1
        //  b2:
        //    c1:
        //      d1:
        //        e1: 1 # 用来说明xxx
        //        e2: 2
        //        e3: 3
        //      # 数组
        //      d2:
        //        - 3
        //        - 3
        //        - 3
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试1
     *
     * a.b.c[0].d=1
     * a.b.c[1].e=2
     * a.b.c[2].e=3
     * a.b.d.e=4
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest1() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array1.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array1.yml");
        //a:
        //  b:
        //    c:
        //      - d: 1
        //      - e: 2
        //      - e: 3
        //    d:
        //      e: 4
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试2
     *
     * a.b.c[0].d=1
     * a.b.c[0].e=2
     * a.b.c[0].f=3
     * a.b.c[1].d=4
     * a.b.c[1].e=5
     * a.b.c[1].f=6
     * a.b.d.e=7
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest2() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array2.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array2.yml");
        //a:
        //  b:
        //    c:
        //      - d: 1
        //        e: 2
        //        f: 3
        //      - d: 4
        //        e: 5
        //        f: 6
        //    d:
        //      e: 7
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试3:多级数组
     *
     * a.b.c[0].d=1
     * a.b.c[1].e[0]=2
     * a.b.c[1].e[1]=3
     * a.b.c[2].e[0]=4
     * a.b.d.e=5
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest3() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array3.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array3.yml");
        //a:
        //  b:
        //    c:
        //      - d: 1
        //      - e:
        //          - 2
        //          - 3
        //      - e:
        //          - 4
        //    d:
        //      e: 5
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试4
     *
     * a.b.c[0]=1
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest4() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array4.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array4.yml");
        //a:
        //  b:
        //    c:
        //      - 1
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试5
     *
     * a.b.c[0].d.e=1
     * a.b.c[0].d.f=2
     * a.b.c[1].d.e.f=3
     * a.b.c[2].e=4
     * a.b.c[3]=5
     * a.b.d.e=6
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest5() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array5.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array5.yml");
        // a:
        //  b:
        //    c:
        //      - d:
        //          e: 1
        //          f: 2
        //      - d:
        //          e:
        //            f: 3
        //      - e: 4
        //      - 5
        //    d:
        //      e: 6
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试6
     *
     * a.b.e[0]=2
     * a.b.d.e=3
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest6() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array6.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array6.yml");
        //a:
        //  b:
        //    e:
        //      - 2
        //    d:
        //      e: 3
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 数组测试7:数组(带字符的)测试
     *
     * knowledge.init.knowledgeTitles[0].kdTitle=听不清
     * knowledge.init.knowledgeTitles[0].keyWords=[你说什么,没听清,听不清楚,再说一遍]
     * knowledge.init.knowledgeTitles[0].question=[没听懂,听不清楚]
     * knowledge.init.knowledgeTitles[1].kdInfos[0]=你好
     * knowledge.init.knowledgeTitles[1].kdInfos[1]=hello
     * knowledge.init.knowledgeTitles[1].kdInfos[2]=hi
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlArrayTest7() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/array7.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/array7.yml");

        //knowledge:
        //  init:
        //    knowledgeTitles:
        //      - kdTitle: 听不清
        //        keyWords: '[你说什么,没听清,听不清楚,再说一遍]'
        //        question: '[没听懂,听不清楚]'
        //      - kdInfos:
        //        - 你好
        //        - hello
        //        - hi
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }

    /**
     * 多行数据测试
     *
     * isc.log.hosts=root:dell@123:10.30.30.33:22\
     * root:dell@123:10.30.30.34:22\
     * root:dell@123:10.30.30.35:22
     */
    @SneakyThrows
    @Test
    public void propertiesToYamlMultiLineTest() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/properties/multi_line.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilPropertiesToYamlTest.class, "/yml/multi_line.yml");

        //isc:
        //  log:
        //    hosts: |
        //      root:dell@123:10.30.30.33:22
        //      root:dell@123:10.30.30.34:22
        //      root:dell@123:10.30.30.35:22
        Assert.assertEquals(yamlContent.trim(), YamlUtil.propertiesToYaml(propertiesContent).trim());
    }
}

yml 转 properties

package com.simon.ocean.yml;

import com.simon.ocean.FileUtil;
import com.simon.ocean.YamlUtil;
import lombok.SneakyThrows;
import org.junit.Assert;
import org.junit.Test;

/**
 * @author shizi
 * @since 2020/10/12 4:34 下午
 */
public class YamlUtilYamlToPropertiesTest {


    /**
     * 基本测试
     *
     * a:
     *   b:
     *     c:
     *       d:
     *         e: 1
     *   b1:
     *     c1:
     *       d1:
     *         e1: 1
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesBaseTest() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/base.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/base.yml");
        //a.b.c.d.e=1
        //a.b1.c1.d1.e1=1
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 基本测试:带注释
     *
     * # 总的
     * a:
     *   b:
     *     c: 1 # test
     *   b1:
     *     c:
     *       d:
     *         e: 1 # 测试1
     *   b2:
     *     c1:
     *       d1:
     *         e1: 1 # 用来说明xxx
     *         e2: 2
     *         e3: 3
     *       # 数组
     *       d2:
     *         - 3
     *         - 3
     *         - 3
     */
    @SneakyThrows
    @Test
    public void propertiesToYmlBase1Test() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/base1.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/base1.yml");

        //# 总的
        //# test
        //a.b.c=1
        //# 测试1
        //a.b1.c.d.e=1
        //# 用来说明xxx
        //a.b2.c1.d1.e1=1
        //a.b2.c1.d1.e2=2
        //a.b2.c1.d1.e3=3
        //# 数组
        //a.b2.c1.d2[0]=3
        //a.b2.c1.d2[1]=3
        //a.b2.c1.d2[2]=3
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试
     *
     * a:
     *   b:
     *     c:
     *       - d: 1
     *       - e: 2
     *       - e: 3
     *     d:
     *       e: 4
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest1() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array1.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array1.yml");
        //a.b.c[0].d=1
        //a.b.c[1].e=2
        //a.b.c[2].e=3
        //a.b.d.e=4
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试2
     *
     * a:
     *   b:
     *     c:
     *       - d: 1
     *         e: 2
     *         f: 3
     *       - d: 4
     *         e: 5
     *         f: 6
     *     d:
     *       e: 7
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest2() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array2.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array2.yml");
        //a.b.c[0].d=1
        //a.b.c[0].e=2
        //a.b.c[0].f=3
        //a.b.c[1].d=4
        //a.b.c[1].e=5
        //a.b.c[1].f=6
        //a.b.d.e=7
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试3:多级数组
     *
     * a:
     *   b:
     *     c:
     *       - d: 1
     *       - e:
     *           - 2
     *           - 3
     *       - e:
     *           - 4
     *     d:
     *       e: 5
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest3() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array3.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array3.yml");
        //a.b.c[0].d=1
        //a.b.c[1].e[0]=2
        //a.b.c[1].e[1]=3
        //a.b.c[2].e[0]=4
        //a.b.d.e=5
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试4
     *
     * a:
     *   b:
     *     c:
     *       - 1
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest4() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array4.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array4.yml");
        //a.b.c[0]=1
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试5
     *
     * a:
     *   b:
     *     c:
     *       - d:
     *           e: 1
     *           f: 2
     *       - d:
     *           e:
     *             f: 3
     *       - e: 4
     *       - 5
     *     d:
     *       e: 6
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest5() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array5.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array5.yml");
        //a.b.c[0].d.e=1
        //a.b.c[0].d.f=2
        //a.b.c[1].d.e.f=3
        //a.b.c[2].e=4
        //a.b.c[3]=5
        //a.b.d.e=6
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试6
     *
     * a:
     *   b:
     *     e:
     *       - 2
     *     d:
     *       e: 3
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest6() {
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array6.properties");
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array6.yml");
        //a.b.e[0]=2
        //a.b.d.e=3
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 数组测试7:带字符
     *
     * knowledge:
     *   init:
     *     knowledgeTitles:
     *       - kdTitle: 听不清
     *         keyWords: '[你说什么,没听清,听不清楚,再说一遍]'
     *         question: '[没听懂,听不清楚]'
     *       - kdInfos:
     *         - 你好
     *         - hello
     *         - hi
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesArrayTest7() {
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/array7.yml");
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/array7.properties");

        //knowledge.init.knowledgeTitles[0].kdTitle=听不清
        //knowledge.init.knowledgeTitles[0].keyWords=[你说什么,没听清,听不清楚,再说一遍]
        //knowledge.init.knowledgeTitles[0].question=[没听懂,听不清楚]
        //knowledge.init.knowledgeTitles[1].kdInfos[0]=你好
        //knowledge.init.knowledgeTitles[1].kdInfos[1]=hello
        //knowledge.init.knowledgeTitles[1].kdInfos[2]=hi
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }

    /**
     * 多行测试
     *
     * isc:
     *   log:
     *     hosts: |
     *       root:dell@123:10.30.30.33:22
     *       root:dell@123:10.30.30.34:22
     *       root:dell@123:10.30.30.35:22
     */
    @SneakyThrows
    @Test
    public void yamlToPropertiesMultiLineTest() {
        String yamlContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/yml/multi_line.yml");
        String propertiesContent = FileUtil.readFromResource(YamlUtilYamlToPropertiesTest.class, "/properties/multi_line.properties");

        //isc.log.hosts=root:dell@123:10.30.30.33:22\
        //root:dell@123:10.30.30.34:22\
        //root:dell@123:10.30.30.35:22
        Assert.assertEquals(propertiesContent.trim(), YamlUtil.yamlToProperties(yamlContent).trim());
    }
}