This commit is contained in:
Looly 2023-03-30 00:09:14 +08:00
parent df6208e8d9
commit 3ce7c3c36b
4 changed files with 107 additions and 34 deletions

View File

@ -12,10 +12,40 @@
package cn.hutool.setting.toml; package cn.hutool.setting.toml;
import cn.hutool.core.io.resource.Resource;
import java.io.Writer;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeFormatterBuilder;
import java.util.Map;
/**
* TOML读写封装<br>
* TODO 参考https://github.com/TheElectronWill/night-config改造
*
* @author TheElectronWill
*/
public class Toml { public class Toml {
/**
* 读取TOML
*
* @param resource 资源
* @return TOML信息
*/
public static Map<String, Object> read(final Resource resource){
return new TomlReader(resource.readUtf8Str(), false).read();
}
/**
* 将TOML数据写出到Writer
* @param data TOML数据
* @param writer {@link Writer}
*/
public static void write(Map<String, Object> data, Writer writer){
new TomlWriter(writer).write(data);
}
/** /**
* A DateTimeFormatter that uses the TOML format. * A DateTimeFormatter that uses the TOML format.
*/ */

View File

@ -145,6 +145,11 @@ public class TomlReader {
} }
} }
/**
* 读取TOML
*
* @return TOML
*/
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, Object> read() { public Map<String, Object> read() {
final Map<String, Object> map = nextTableContent(); final Map<String, Object> map = nextTableContent();
@ -237,7 +242,7 @@ public class TomlReader {
final Object child = valueMap.get(part); final Object child = valueMap.get(part);
final Map<String, Object> childMap; final Map<String, Object> childMap;
if (child == null) {// implicit table if (child == null) {// implicit table
childMap = new HashMap<>(4); childMap = new LinkedHashMap<>(4);
valueMap.put(part, childMap); valueMap.put(part, childMap);
} else if (child instanceof Map) {// table } else if (child instanceof Map) {// table
childMap = (Map<String, Object>) child; childMap = (Map<String, Object>) child;
@ -291,7 +296,7 @@ public class TomlReader {
} }
private Map<String, Object> nextInlineTable() { private Map<String, Object> nextInlineTable() {
final Map<String, Object> map = new HashMap<>(); final Map<String, Object> map = new LinkedHashMap<>();
while (true) { while (true) {
final char nameFirstChar = nextUsefulOrLinebreak(); final char nameFirstChar = nextUsefulOrLinebreak();
String name = null; String name = null;
@ -350,7 +355,7 @@ public class TomlReader {
} }
private Map<String, Object> nextTableContent() { private Map<String, Object> nextTableContent() {
final Map<String, Object> map = new HashMap<>(); final Map<String, Object> map = new LinkedHashMap<>();
while (true) { while (true) {
final char nameFirstChar = nextUseful(true); final char nameFirstChar = nextUseful(true);
if (!hasNext() || nameFirstChar == '[') { if (!hasNext() || nameFirstChar == '[') {

View File

@ -13,6 +13,7 @@
package cn.hutool.setting.toml; package cn.hutool.setting.toml;
import cn.hutool.core.array.ArrayUtil; import cn.hutool.core.array.ArrayUtil;
import cn.hutool.core.io.IORuntimeException;
import cn.hutool.core.util.CharUtil; import cn.hutool.core.util.CharUtil;
import cn.hutool.setting.SettingException; import cn.hutool.setting.SettingException;
@ -28,18 +29,16 @@ import java.util.LinkedList;
import java.util.Map; import java.util.Map;
/** /**
* Class for writing TOML v0.4.0. * TOML生成器
* <h1>DateTimes support</h1>
* <p> * <p>
* Any {@link TemporalAccessor} may be added in a Map passed to this writer, this writer can only write three * 日期格式支持
* kind of datetimes: {@link LocalDate}, {@link LocalDateTime} and {@link ZonedDateTime}. * <ul>
* </p> * <li>2015-03-20 转为{@link LocalDate}</li>
* <h1>Lenient bare keys</h1> * <li>2015-03-20T19:04:35 转为{@link LocalDateTime}</li>
* <li>2015-03-20T19:04:35+01:00 转为{@link ZonedDateTime}</li>
* </ul>
* <p> * <p>
* The {@link TomlWriter} always outputs data that strictly follows the TOML specification. Any key that * 此类支持更加宽松的key除了{@code A-Za-z0-9_- }其他key使用"包装。
* contains one
* or more non-strictly valid character is surrounded by quotes.
* </p>
* *
* @author TheElectronWill * @author TheElectronWill
*/ */
@ -113,13 +112,13 @@ public class TomlWriter {
* Writes the specified data in the TOML format. * Writes the specified data in the TOML format.
* *
* @param data the data to write * @param data the data to write
* @throws IOException if an error occurs * @throws IORuntimeException if an error occurs
*/ */
public void write(final Map<String, Object> data) throws IOException { public void write(final Map<String, Object> data) throws IORuntimeException {
writeTableContent(data); writeTableContent(data);
} }
private void writeTableName() throws IOException { private void writeTableName() throws IORuntimeException {
final Iterator<String> it = tablesNames.iterator(); final Iterator<String> it = tablesNames.iterator();
while (it.hasNext()) { while (it.hasNext()) {
final String namePart = it.next(); final String namePart = it.next();
@ -130,7 +129,7 @@ public class TomlWriter {
} }
} }
private void writeTableContent(final Map<String, Object> table) throws IOException { private void writeTableContent(final Map<String, Object> table) throws IORuntimeException {
writeTableContent(table, true); writeTableContent(table, true);
writeTableContent(table, false); writeTableContent(table, false);
} }
@ -144,7 +143,7 @@ public class TomlWriter {
* (and the arrays of tables). * (and the arrays of tables).
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void writeTableContent(final Map<String, Object> table, final boolean simpleValues) throws IOException { private void writeTableContent(final Map<String, Object> table, final boolean simpleValues) throws IORuntimeException {
for (final Map.Entry<String, Object> entry : table.entrySet()) { for (final Map.Entry<String, Object> entry : table.entrySet()) {
final String name = entry.getKey(); final String name = entry.getKey();
final Object value = entry.getValue(); final Object value = entry.getValue();
@ -232,7 +231,7 @@ public class TomlWriter {
newLine(); newLine();
} }
private void writeKey(final String key) throws IOException { private void writeKey(final String key) throws IORuntimeException {
for (int i = 0; i < key.length(); i++) { for (int i = 0; i < key.length(); i++) {
final char c = key.charAt(i); final char c = key.charAt(i);
if (false == isValidCharOfKey(c)) { if (false == isValidCharOfKey(c)) {
@ -246,13 +245,13 @@ public class TomlWriter {
private static boolean isValidCharOfKey(final char c) { private static boolean isValidCharOfKey(final char c) {
return (c >= 'a' && c <= 'z') || return (c >= 'a' && c <= 'z') ||
(c >= 'A' && c <= 'Z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9') || (c >= '0' && c <= '9') ||
c == '-' || c == '-' ||
c == '_'; c == '_';
} }
private void writeString(final String str) throws IOException { private void writeString(final String str) throws IORuntimeException {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
sb.append('"'); sb.append('"');
for (int i = 0; i < str.length(); i++) { for (int i = 0; i < str.length(); i++) {
@ -263,7 +262,7 @@ public class TomlWriter {
write(sb.toString()); write(sb.toString());
} }
private void writeArray(final Collection<?> c) throws IOException { private void writeArray(final Collection<?> c) throws IORuntimeException {
write('['); write('[');
for (final Object element : c) { for (final Object element : c) {
writeValue(element); writeValue(element);
@ -272,7 +271,7 @@ public class TomlWriter {
write(']'); write(']');
} }
private void writeValue(final Object value) throws IOException { private void writeValue(final Object value) throws IORuntimeException {
if (value instanceof String) { if (value instanceof String) {
writeString((String) value); writeString((String) value);
} else if (value instanceof Number || value instanceof Boolean) { } else if (value instanceof Number || value instanceof Boolean) {
@ -290,30 +289,42 @@ public class TomlWriter {
write(ArrayUtil.toString(value)); write(ArrayUtil.toString(value));
} else if (value instanceof Map) {// should not happen because an array of tables is detected by } else if (value instanceof Map) {// should not happen because an array of tables is detected by
// writeTableContent() // writeTableContent()
throw new IOException("Unexpected value " + value); throw new IORuntimeException("Unexpected value " + value);
} else { } else {
throw new SettingException("Unsupported value of type " + value.getClass().getCanonicalName()); throw new SettingException("Unsupported value of type " + value.getClass().getCanonicalName());
} }
} }
private void newLine() throws IOException { private void newLine() throws IORuntimeException {
if (lineBreaks <= 1) { if (lineBreaks <= 1) {
writer.write(lineSeparator); try {
writer.write(lineSeparator);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
lineBreaks++; lineBreaks++;
} }
} }
private void write(final char c) throws IOException { private void write(final char c) throws IORuntimeException {
writer.write(c); try {
writer.write(c);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
lineBreaks = 0; lineBreaks = 0;
} }
private void write(final String str) throws IOException { private void write(final String str) throws IORuntimeException {
writer.write(str); try {
writer.write(str);
} catch (final IOException e) {
throw new IORuntimeException(e);
}
lineBreaks = 0; lineBreaks = 0;
} }
private void indent() throws IOException { private void indent() throws IORuntimeException {
for (int i = 0; i < indentationLevel; i++) { for (int i = 0; i < indentationLevel; i++) {
for (int j = 0; j < indentSize; j++) { for (int j = 0; j < indentSize; j++) {
write(indentCharacter); write(indentCharacter);

View File

@ -0,0 +1,27 @@
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package cn.hutool.setting.toml;
import cn.hutool.core.io.resource.ResourceUtil;
import org.junit.Assert;
import org.junit.Test;
import java.util.Map;
public class TomlTest {
@Test
public void readTest() {
final Map<String, Object> read = Toml.read(ResourceUtil.getResource("test.toml"));
Assert.assertEquals(5, read.size());
}
}