Skip to content

An impl for read/write Json5 comments- patch2 #26

@Zim-Inn

Description

@Zim-Inn

below is after patch-1

Index: src/main/java/de/marhali/json5/Json5Array.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Array.java b/src/main/java/de/marhali/json5/Json5Array.java
--- a/src/main/java/de/marhali/json5/Json5Array.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Array.java	(date 1757065878327)
@@ -32,6 +32,7 @@
  * @author Inderjeet Singh
  * @author Joel Leitch
  */
+@SuppressWarnings("unused")
 public final class Json5Array extends Json5Element implements Iterable<Json5Element> {
     private final List<Json5Element> elements;
 
@@ -56,119 +57,23 @@
             for (Json5Element element : elements) {
                 result.add(element.deepCopy());
             }
+            result.setComment(this.getComment());
             return result;
         }
         return new Json5Array();
     }
 
-    /**
-     * Adds the specified boolean to self.
-     *
-     * @param bool the boolean that needs to be added to the array.
-     */
-    public void add(Boolean bool) {
-        elements.add(bool == null ? Json5Null.INSTANCE : new Json5Boolean(bool));
-    }
-
-    /**
-     * Adds the specified character to self.
-     *
-     * @param character the character that needs to be added to the array.
-     */
-    public void add(Character character) {
-        elements.add(character == null ? Json5Null.INSTANCE : new Json5String(character.toString()));
-    }
-
-    /**
-     * Adds the specified number to self.
-     *
-     * @param number the number that needs to be added to the array.
-     */
-    public void add(Number number) {
-        elements.add(number == null ? Json5Null.INSTANCE : new Json5Number(number));
+    @Override
+    public Json5Element noCommentCopy() {
+        if (!elements.isEmpty()) {
+            Json5Array result = new Json5Array(elements.size());
+            for (Json5Element element : elements) {
+                result.add(element.noCommentCopy());
+            }
+            return result;
+        }
+        return new Json5Array();
     }
-
-    /**
-     * Adds the specified string to self.
-     *
-     * @param string the string that needs to be added to the array.
-     */
-    public void add(String string) {
-        elements.add(string == null ? Json5Null.INSTANCE : new Json5String(string));
-    }
-
-    /**
-     * Adds the specified element to self.
-     *
-     * @param element the element that needs to be added to the array.
-     */
-    public void add(Json5Element element) {
-        if (element == null) {
-            element = Json5Null.INSTANCE;
-        }
-        elements.add(element);
-    }
-
-    /**
-     * Adds all the elements of the specified array to self.
-     *
-     * @param array the array whose elements need to be added to the array.
-     */
-    public void addAll(Json5Array array) {
-        elements.addAll(array.elements);
-    }
-
-    /**
-     * Replaces the element at the specified position in this array with the specified element.
-     *   Element can be null.
-     * @param index index of the element to replace
-     * @param element element to be stored at the specified position
-     * @return the element previously at the specified position
-     * @throws IndexOutOfBoundsException if the specified index is outside the array bounds
-     */
-    public Json5Element set(int index, Json5Element element) {
-        return elements.set(index, element);
-    }
-
-    /**
-     * Removes the first occurrence of the specified element from this array, if it is present.
-     * If the array does not contain the element, it is unchanged.
-     * @param element element to be removed from this array, if present
-     * @return true if this array contained the specified element, false otherwise
-     */
-    public boolean remove(Json5Element element) {
-        return elements.remove(element);
-    }
-
-    /**
-     * Removes the element at the specified position in this array. Shifts any subsequent elements
-     * to the left (subtracts one from their indices). Returns the element that was removed from
-     * the array.
-     * @param index index the index of the element to be removed
-     * @return the element previously at the specified position
-     * @throws IndexOutOfBoundsException if the specified index is outside the array bounds
-     */
-    public Json5Element remove(int index) {
-        return elements.remove(index);
-    }
-
-    /**
-     * Returns true if this array contains the specified element.
-     * @return true if this array contains the specified element.
-     * @param element whose presence in this array is to be tested
-     */
-    public boolean contains(Json5Element element) {
-        return elements.contains(element);
-    }
-
-    /**
-     * Returns the number of elements in the array.
-     *
-     * @return the number of elements in the array.
-     */
-    public int size() {
-        return elements.size();
-    }
 
     /**
      * Returns true if the array is empty
@@ -180,31 +85,25 @@
     }
 
     /**
-     * Returns an iterator to navigate the elements of the array. Since the array is an ordered list,
-     * the iterator navigates the elements in the order they were inserted.
+     * convenience method to get this array as a boolean if it contains a single element.
      *
-     * @return an iterator to navigate the elements of the array.
+     * @return get this element as a boolean if it is a single element array.
+     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
+     * is not a valid boolean.
+     * @throws IllegalStateException if the array has more than one element.
      */
-    public Iterator<Json5Element> iterator() {
-        return elements.iterator();
-    }
-
-    /**
-     * Returns the ith element of the array.
-     *
-     * @param i the index of the element that is being sought.
-     * @return the element present at the ith index.
-     * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
-     * {@link #size()} of the array.
-     */
-    public Json5Element get(int i) {
-        return elements.get(i);
+    @Override
+    public boolean getAsBoolean() {
+        if (elements.size() == 1) {
+            return elements.get(0).getAsBoolean();
+        }
+        throw new IllegalStateException();
     }
 
     /**
      * convenience method to get this array as a {@link Number} if it contains a single element.
      *
-     * @return get this element as a number if it is single element array.
+     * @return get this element as a number if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid Number.
      * @throws IllegalStateException if the array has more than one element.
@@ -220,7 +119,7 @@
     /**
      * convenience method to get this array as a {@link String} if it contains a single element.
      *
-     * @return get this element as a String if it is single element array.
+     * @return get this element as a String if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid String.
      * @throws IllegalStateException if the array has more than one element.
@@ -236,7 +135,7 @@
     /**
      * convenience method to get this array as a double if it contains a single element.
      *
-     * @return get this element as a double if it is single element array.
+     * @return get this element as a double if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid double.
      * @throws IllegalStateException if the array has more than one element.
@@ -249,42 +148,10 @@
         throw new IllegalStateException();
     }
 
-    /**
-     * convenience method to get this array as a {@link BigDecimal} if it contains a single element.
-     *
-     * @return get this element as a {@link BigDecimal} if it is single element array.
-     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive}.
-     * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
-     * @throws IllegalStateException if the array has more than one element.
-     */
-    @Override
-    public BigDecimal getAsBigDecimal() {
-        if (elements.size() == 1) {
-            return elements.get(0).getAsBigDecimal();
-        }
-        throw new IllegalStateException();
-    }
-
-    /**
-     * convenience method to get this array as a {@link BigInteger} if it contains a single element.
-     *
-     * @return get this element as a {@link BigInteger} if it is single element array.
-     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive}.
-     * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
-     * @throws IllegalStateException if the array has more than one element.
-     */
-    @Override
-    public BigInteger getAsBigInteger() {
-        if (elements.size() == 1) {
-            return elements.get(0).getAsBigInteger();
-        }
-        throw new IllegalStateException();
-    }
-
     /**
      * convenience method to get this array as a float if it contains a single element.
      *
-     * @return get this element as a float if it is single element array.
+     * @return get this element as a float if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid float.
      * @throws IllegalStateException if the array has more than one element.
@@ -300,7 +167,7 @@
     /**
      * convenience method to get this array as a long if it contains a single element.
      *
-     * @return get this element as a long if it is single element array.
+     * @return get this element as a long if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid long.
      * @throws IllegalStateException if the array has more than one element.
@@ -316,7 +183,7 @@
     /**
      * convenience method to get this array as an integer if it contains a single element.
      *
-     * @return get this element as an integer if it is single element array.
+     * @return get this element as an integer if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid integer.
      * @throws IllegalStateException if the array has more than one element.
@@ -337,10 +204,42 @@
         throw new IllegalStateException();
     }
 
+    /**
+     * convenience method to get this array as a {@link BigDecimal} if it contains a single element.
+     *
+     * @return get this element as a {@link BigDecimal} if it is single element array.
+     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive}.
+     * @throws NumberFormatException if the element at index 0 is not a valid {@link BigDecimal}.
+     * @throws IllegalStateException if the array has more than one element.
+     */
+    @Override
+    public BigDecimal getAsBigDecimal() {
+        if (elements.size() == 1) {
+            return elements.get(0).getAsBigDecimal();
+        }
+        throw new IllegalStateException();
+    }
+
+    /**
+     * convenience method to get this array as a {@link BigInteger} if it contains a single element.
+     *
+     * @return get this element as a {@link BigInteger} if it is single element array.
+     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive}.
+     * @throws NumberFormatException if the element at index 0 is not a valid {@link BigInteger}.
+     * @throws IllegalStateException if the array has more than one element.
+     */
+    @Override
+    public BigInteger getAsBigInteger() {
+        if (elements.size() == 1) {
+            return elements.get(0).getAsBigInteger();
+        }
+        throw new IllegalStateException();
+    }
+
     /**
      * convenience method to get this array as a primitive short if it contains a single element.
      *
-     * @return get this element as a primitive short if it is single element array.
+     * @return get this element as a primitive short if it is a single element array.
      * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
      * is not a valid short.
      * @throws IllegalStateException if the array has more than one element.
@@ -354,28 +253,206 @@
     }
 
     /**
-     * convenience method to get this array as a boolean if it contains a single element.
+     * Adds the specified boolean to self.
+     *
+     * @param bool the boolean that needs to be added to the array.
+     */
+    public void add(Boolean bool) {
+        elements.add(bool == null ? Json5Null.INSTANCE : new Json5Boolean(bool));
+    }
+
+    /**
+     * Adds the specified character to self.
+     *
+     * @param character the character that needs to be added to the array.
+     */
+    public void add(Character character) {
+        elements.add(character == null ? Json5Null.INSTANCE : new Json5String(character.toString()));
+    }
+
+    /**
+     * Adds the specified number to self.
+     *
+     * @param number the number that needs to be added to the array.
+     */
+    public void add(Number number) {
+        elements.add(number == null ? Json5Null.INSTANCE : new Json5Number(number));
+    }
+
+    /**
+     * Adds the specified string to self.
+     *
+     * @param string the string that needs to be added to the array.
+     */
+    public void add(String string) {
+        elements.add(string == null ? Json5Null.INSTANCE : new Json5String(string));
+    }
+
+    /**
+     * Adds the specified element to self.
+     *
+     * @param element the element that needs to be added to the array.
+     */
+    public void add(Json5Element element) {
+        if (element == null) {
+            element = Json5Null.INSTANCE;
+        }
+        elements.add(element);
+    }
+
+    /**
+     * Adds all the elements of the specified array to self.
+     *
+     * @param array the array whose elements need to be added to the array.
+     */
+    public void addAll(Json5Array array) {
+        elements.addAll(array.elements);
+    }
+
+    /**
+     * Replaces the element at the specified position in this array with the specified element.
+     * Element can be null.
+     *
+     * @param index index of the element to replace
+     * @param element element to be stored at the specified position
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException if the specified index is outside the array bounds
+     */
+    public Json5Element set(int index, Json5Element element) {
+        return elements.set(index, element);
+    }
+
+    /**
+     * Removes the first occurrence of the specified element from this array, if it is present.
+     * If the array does not contain the element, it is unchanged.
+     *
+     * @param element element to be removed from this array, if present
+     * @return true if this array contained the specified element, false otherwise
+     */
+    public boolean remove(Json5Element element) {
+        return elements.remove(element);
+    }
+
+    /**
+     * Removes the element at the specified position in this array. Shifts any subsequent elements
+     * to the left (subtracts one from their indices). Returns the element that was removed from
+     * the array.
+     *
+     * @param index index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @throws IndexOutOfBoundsException if the specified index is outside the array bounds
+     */
+    @SuppressWarnings("UnusedReturnValue")
+    public Json5Element remove(int index) {
+        return elements.remove(index);
+    }
+
+    /**
+     * Returns true if this array contains the specified element.
+     *
+     * @param element whose presence in this array is to be tested
+     * @return true if this array contains the specified element.
+     */
+    public boolean contains(Json5Element element) {
+        return elements.contains(element);
+    }
+
+    /**
+     * Returns the number of elements in the array.
+     *
+     * @return the number of elements in the array.
+     */
+    public int size() {
+        return elements.size();
+    }
+
+    /**
+     * 将本对象的非空注释覆盖合并到目标对象
+     * 取两者长度较短者作为最大遍历长度
+     * 要求目标对象的同索引子元素应与本子元素具备类型一致性
+     *
+     * @param target 目标对象
+     */
+    public void mergeCommentTo(Json5Array target) {
+        super.copyCommentTo(target);
+        if (!elements.isEmpty()) {
+            int loop = Math.min(elements.size(), target.size());
+            for (int i = 0; i < loop; i++) {
+                Json5Element element = this.get(i);
+                if (!element.hasComment()) {
+                    continue;
+                }
+                if (element instanceof Json5Primitive) {
+                    element.copyCommentTo(target.get(i));
+                } else if (element instanceof Json5Array) {
+                    ((Json5Array) element).mergeCommentTo((Json5Array) target.get(i));
+                } else if (element instanceof Json5Object) {
+                    ((Json5Object) element).mergeCommentTo((Json5Object) target.get(i));
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets the comment for an element.
+     * comment字段不会参与equals 和hashCode
      *
-     * @return get this element as a boolean if it is single element array.
-     * @throws ClassCastException if the element in the array is of not a {@link Json5Primitive} and
-     * is not a valid boolean.
-     * @throws IllegalStateException if the array has more than one element.
+     * @param index index of elements
+     * @param comment comment for the member
      */
+    public void setComment(int index, String comment) {
+        Json5Element element = get(index);
+        if (element instanceof Json5Null) {
+            Json5Null json5Null = new Json5Null();
+            json5Null.setComment(comment);
+            elements.set(index, json5Null);
+        } else {
+            element.setComment(comment);
+        }
+    }
+
+    /**
+     * Returns an iterator to navigate the elements of the array. Since the array is an ordered list,
+     * the iterator navigates the elements in the order they were inserted.
+     *
+     * @return an iterator to navigate the elements of the array.
+     */
+    public Iterator<Json5Element> iterator() {
+        return elements.iterator();
+    }
+
+    /**
+     * Returns the ith element of the array.
+     *
+     * @param i the index of the element that is being sought.
+     * @return the element present at the ith index.
+     * @throws IndexOutOfBoundsException if i is negative or greater than or equal to the
+     * {@link #size()} of the array.
+     */
+    public Json5Element get(int i) {
+        return elements.get(i);
+    }
+
     @Override
-    public boolean getAsBoolean() {
-        if (elements.size() == 1) {
-            return elements.get(0).getAsBoolean();
-        }
-        throw new IllegalStateException();
+    public int hashCode() {
+        return elements.hashCode();
+    }
+
+    /**
+     * 暂不支持直接转POJO对象,请使用toStandardString然后使用其它反序列化框架处理
+     * @see Json5Element#toString(Json5Options)
+     * @see Json5Element#toStandardString
+     *
+     * @param clazz The class of the POJO to convert to.
+     * @param <T> The type of the POJO.
+     * @return An list instance of the specified POJO class, populated with data from this Json5Array.
+     */
+    public <T> List<T> toPojoList(Class<T> clazz) throws Exception {
+        throw new Exception("不支持的操作!");
     }
 
     @Override
     public boolean equals(Object o) {
         return (o == this) || (o instanceof Json5Array && ((Json5Array) o).elements.equals(elements));
     }
-
-    @Override
-    public int hashCode() {
-        return elements.hashCode();
-    }
 }
\ No newline at end of file
Index: src/main/java/de/marhali/json5/Json5Boolean.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Boolean.java b/src/main/java/de/marhali/json5/Json5Boolean.java
--- a/src/main/java/de/marhali/json5/Json5Boolean.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Boolean.java	(date 1757065878221)
@@ -25,4 +25,16 @@
     public Json5Boolean(Boolean value) {
         super(value);
     }
+
+    @Override
+    public Json5Element deepCopy() {
+        Json5Boolean o = new Json5Boolean((Boolean) value);
+        o.setComment(getComment());
+        return o;
+    }
+
+    @Override
+    public Json5Element noCommentCopy() {
+        return new  Json5Boolean((Boolean) value);
+    }
 }
Index: src/main/java/de/marhali/json5/Json5Element.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Element.java b/src/main/java/de/marhali/json5/Json5Element.java
--- a/src/main/java/de/marhali/json5/Json5Element.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Element.java	(date 1757065878328)
@@ -34,12 +34,54 @@
  * @author Joel Leitch
  */
 public abstract class Json5Element {
+    private String comment;
+
+    /**
+     * Gets the comment associated with this element.
+     *
+     * @return The comment string, or null if none exists.
+     */
+    public String getComment() {
+        return this.comment;
+    }
+
     /**
-     * @return A deep copy of this element. Immutable elements like primitives
-     * and nulls are not copied.
+     * 对于Json5Null对象的注释,请通过以下方法来set
+     * @see Json5Object#setComment(String, String)
+     * @see Json5Array#setComment(int, String)
+     * comment字段不会参与equals 和hashCode
+     *
+     * @param comment The comment string. Can be multi-line.
+     */
+    public void setComment(String comment) {
+        // 不应该直接操作Json5Null.INSTANCE实例的注释
+        // 应该通过JsonObject或Json5Array的 setComment方法来操作
+        if (this == Json5Null.INSTANCE) {
+            return;
+        }
+        this.comment = comment;
+    }
+
+    /**
+     * Checks if a comment is associated with this element.
+     *
+     * @return True if a comment exists, false otherwise.
+     */
+    public boolean hasComment() {
+        return this.comment != null;
+    }
+
+    /**
+     * @return 深拷贝对象,包含各个子元素的注释
      */
     public abstract Json5Element deepCopy();
 
+    /**
+     *
+     * @return 返回一个不带任何注释的拷贝对象
+     */
+    public abstract Json5Element noCommentCopy();
+
     /**
      * provides check for verifying if this element is an array or not.
      *
@@ -76,6 +118,40 @@
         return this instanceof Json5Null;
     }
 
+    /**
+     * 当对象为空字符串 空Json5Object 空Json5Array Json5Null时返回True,其它情况返回False.
+     *
+     * @return 对象是否为空
+     */
+    public boolean isEmpty() {
+        if (this instanceof Json5Null) {
+            return true;
+        } else if (this instanceof Json5Object) {
+            // noinspection RedundantCast
+            return ((Json5Object) this).isEmpty();
+        } else if (this instanceof Json5Array) {
+            // noinspection RedundantCast
+            return ((Json5Array) this).isEmpty();
+        } else if (this instanceof Json5String) {
+            // noinspection RedundantCast
+            return ((Json5String) this).isEmpty();
+        }
+        return false;
+    }
+
+    /**
+     * 将本对象的注释复制到目标对象
+     *
+     * @param target 目标对象
+     * @see Json5Object#mergeCommentTo(Json5Object)
+     * @see Json5Array#mergeCommentTo(Json5Array)
+     */
+    public void copyCommentTo(Json5Element target) {
+        if (target != null && this.comment != null) {
+            target.setComment(this.comment);
+        }
+    }
+
     /**
      * convenience method to get this element as a {@link Json5Object}. If the element is of some
      * other type, a {@link IllegalStateException} will result. Hence it is best to use this method
@@ -133,6 +209,7 @@
      * @return get this element as a {@link Json5Null}.
      * @throws IllegalStateException if the element is of another type.
      */
+    @SuppressWarnings("unused")
     public Json5Null getAsJson5Null() {
         if (isJson5Null()) {
             return (Json5Null) this;
@@ -286,6 +363,7 @@
     /**
      * Returns a simple String representation of this element.
      * For pretty-printing use {@link Json5Writer} with custom configuration options.
+     *
      * @see #toString(Json5Options)
      */
     @Override
@@ -293,8 +371,17 @@
         return toString(Json5Options.DEFAULT);
     }
 
+    /**
+     * 将对象转为无注释标准json字符串
+     * @return 压缩的json字符串
+     */
+    public String toStandardString() {
+        return toString(new Json5OptionsBuilder().notWriteComments().build());
+    }
+
     /**
      * Returns the String representation of this element.
+     *
      * @param options Configured serialization behaviour
      * @return Stringified representation of this element
      */
@@ -306,7 +393,6 @@
             Json5Writer json5Writer = new Json5Writer(options, stringWriter);
             json5Writer.write(this);
             return stringWriter.toString();
-
         } catch (IOException e) {
             throw new AssertionError(e);
         }
Index: src/main/java/de/marhali/json5/Json5Hexadecimal.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Hexadecimal.java b/src/main/java/de/marhali/json5/Json5Hexadecimal.java
--- a/src/main/java/de/marhali/json5/Json5Hexadecimal.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Hexadecimal.java	(date 1757065878221)
@@ -25,6 +25,23 @@
  * @author Marcel Haßlinger
  */
 public final class Json5Hexadecimal extends Json5Primitive {
+    /**
+     * Creates a primitive containing a hex value.
+     *
+     * @param hex the value to create the primitive with.
+     */
+    public Json5Hexadecimal(BigInteger hex) {
+        super(hex);
+    }
+
+    /**
+     * Creates a primitive containing a hex value. For String to Number conversion see {@link #parseHexString(String)}
+     *
+     * @param hex the value to create the primitive with.
+     */
+    public Json5Hexadecimal(String hex) {
+        super(parseHexString(hex));
+    }
 
     /**
      * Converts the provided hex string into it's number representation.
@@ -49,36 +66,30 @@
     /**
      * Converts the provided number into it's hex literal character representation.
      *
-     * @param bigInteger     the number value
+     * @param bigInteger the number value
      * @param prefixPositive Prefix positive values with {@code +0x...} if true otherwise {@code 0x...}.
      * @return Hex character string including prefix
      */
     public static String serializeHexString(BigInteger bigInteger, boolean prefixPositive) {
         Objects.requireNonNull(bigInteger);
 
-        if(bigInteger.signum() >= 0) {
+        if (bigInteger.signum() >= 0) {
             return (prefixPositive ? "+0x" : "0x") + bigInteger.toString(16);
         } else {
             return "-0x" + bigInteger.abs().toString(16);
         }
     }
 
-    /**
-     * Creates a primitive containing a hex value.
-     *
-     * @param hex the value to create the primitive with.
-     */
-    public Json5Hexadecimal(BigInteger hex) {
-        super(hex);
+    @Override
+    public Json5Element deepCopy() {
+        Json5Hexadecimal o = new Json5Hexadecimal((BigInteger) value);
+        o.setComment(getComment());
+        return o;
     }
 
-    /**
-     * Creates a primitive containing a hex value. For String to Number conversion see {@link #parseHexString(String)}
-     *
-     * @param hex the value to create the primitive with.
-     */
-    public Json5Hexadecimal(String hex) {
-        super(parseHexString(hex));
+    @Override
+    public Json5Element noCommentCopy() {
+        return new Json5Hexadecimal((BigInteger) value);
     }
 
     /**
Index: src/main/java/de/marhali/json5/Json5Null.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Null.java b/src/main/java/de/marhali/json5/Json5Null.java
--- a/src/main/java/de/marhali/json5/Json5Null.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Null.java	(date 1757065878222)
@@ -31,13 +31,20 @@
     /**
      * Constructor for internal use only. Use {@link #INSTANCE} instead.
      */
-    private Json5Null() {}
+    public Json5Null() { }
 
     /**
      * Returns the same instance since it is an immutable value
      */
     @Override
     public Json5Null deepCopy() {
+        Json5Null json5Null = new Json5Null();
+        json5Null.setComment(this.getComment());
+        return json5Null;
+    }
+
+    @Override
+    public Json5Element noCommentCopy() {
         return INSTANCE;
     }
 
Index: src/main/java/de/marhali/json5/Json5Number.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Number.java b/src/main/java/de/marhali/json5/Json5Number.java
--- a/src/main/java/de/marhali/json5/Json5Number.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Number.java	(date 1757065878222)
@@ -25,4 +25,16 @@
     public Json5Number(Number number) {
         super(number);
     }
+
+    @Override
+    public Json5Element deepCopy() {
+        Json5Number o = new Json5Number((Number) value);
+        o.setComment(getComment());
+        return o;
+    }
+
+    @Override
+    public Json5Element noCommentCopy() {
+        return new Json5Number((Number) value);
+    }
 }
Index: src/main/java/de/marhali/json5/Json5Object.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Object.java b/src/main/java/de/marhali/json5/Json5Object.java
--- a/src/main/java/de/marhali/json5/Json5Object.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Object.java	(date 1757065878328)
@@ -24,15 +24,15 @@
 
 /**
  * A class representing an object type in Json. An object consists of name-value pairs where names
- * are strings, and values are any other type of {@link Json5Element}. This allows for a creating a
+ * are strings, and values are any other type of {@link Json5Element}. This allows for creating a
  * tree of Json5Elements. The member elements of this object are maintained in order they were added.
  *
  * @author Inderjeet Singh
  * @author Joel Leitch
  */
+@SuppressWarnings("unused")
 public final class Json5Object extends Json5Element {
-    private final LinkedTreeMap<String, Json5Element> members =
-            new LinkedTreeMap<String, Json5Element>();
+    private final LinkedTreeMap<String, Json5Element> members = new LinkedTreeMap<String, Json5Element>();
 
     /**
      * Creates a deep copy of this element and all its children
@@ -43,9 +43,24 @@
         for (Map.Entry<String, Json5Element> entry : members.entrySet()) {
             result.add(entry.getKey(), entry.getValue().deepCopy());
         }
+        result.setComment(this.getComment());
         return result;
     }
 
+    @Override
+    public Json5Element noCommentCopy() {
+        Json5Object result = new Json5Object();
+        for (Map.Entry<String, Json5Element> entry : members.entrySet()) {
+            result.add(entry.getKey(), entry.getValue().noCommentCopy());
+        }
+        return result;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return members.isEmpty();
+    }
+
     /**
      * Adds a member, which is a name-value pair, to self. The name must be a String, but the value
      * can be an arbitrary Json5Element, thereby allowing you to build a full tree of Json5Elements
@@ -56,6 +71,33 @@
      */
     public void add(String property, Json5Element value) {
         members.put(property, value == null ? Json5Null.INSTANCE : value);
+        if (value != null && value.hasComment()) {
+            setComment(property, value.getComment());
+        }
+    }
+
+    /**
+     * 将本对象的非空注释覆盖合并到目标对象
+     * 要求目标对象的同key子节点应与本子节点具备类型一致性
+     *
+     * @param target 目标对象
+     */
+    public void mergeCommentTo(Json5Object target) {
+        super.copyCommentTo(target);
+        for (String key : target.keySet()) {
+            Json5Element element = this.get(key);
+            if (element != null && !element.hasComment()) {
+                continue;
+            }
+            if (element instanceof Json5Primitive) {
+                element.copyCommentTo(target.get(key));
+            } else if (element instanceof Json5Array) {
+                ((Json5Array) element).mergeCommentTo((Json5Array) target.get(key));
+            } else if (element instanceof Json5Object) {
+                ((Json5Object) element).mergeCommentTo((Json5Object) target.get(key));
+            }
+            target.setComment(key, this.getComment(key));
+        }
     }
 
     /**
@@ -64,6 +106,7 @@
      * @param property name of the member that should be removed.
      * @return the {@link Json5Element} object that is being removed.
      */
+    @SuppressWarnings("UnusedReturnValue")
     public Json5Element remove(String property) {
         return members.remove(property);
     }
@@ -112,6 +155,41 @@
         add(property, value == null ? Json5Null.INSTANCE : new Json5String(value.toString()));
     }
 
+    //<editor-fold desc="Modified by Ultreon (added support for comments)">
+
+    /**
+     * Sets the comment for a member.
+     * comment字段不会参与equals 和hashCode
+     *
+     * @param property name of the member
+     * @param comment comment for the member
+     */
+    public void setComment(String property, String comment) {
+        Json5Element element = get(property);
+        if (element == null) {
+            throw new RuntimeException(
+                "Property " + property + " is not defined! You should define a property before set comment.");
+        }
+        if (element instanceof Json5Null) {
+            Json5Null value = new Json5Null();
+            value.setComment(comment);
+            members.put(property, value);
+        } else {
+            element.setComment(comment);
+        }
+    }
+
+    /**
+     * Gets the comment for a member.
+     *
+     * @param property name of the member
+     * @return comment for the member
+     */
+    public String getComment(String property) {
+        return get(property).getComment();
+    }
+    //</editor-fold>
+
     /**
      * Returns a set of members of this object. The set is ordered, and the order is in which the
      * elements were added.
@@ -143,7 +221,7 @@
     /**
      * Convenience method to check if a member with the specified name is present in this object.
      *
-     * @param memberName name of the member that is being checked for presence.
+     * @param memberName the name of the member that is being checked for presence.
      * @return true if there is a member with the specified name, false otherwise.
      */
     public boolean has(String memberName) {
@@ -163,7 +241,7 @@
     /**
      * Convenience method to get the specified member as a Json5Primitive element.
      *
-     * @param memberName name of the member being requested.
+     * @param memberName the name of the member being requested.
      * @return the Json5Primitive corresponding to the specified member.
      */
     public Json5Primitive getAsJson5Primitive(String memberName) {
@@ -173,7 +251,7 @@
     /**
      * Convenience method to get the specified member as a Json5Array.
      *
-     * @param memberName name of the member being requested.
+     * @param memberName the name of the member being requested.
      * @return the Json5Array corresponding to the specified member.
      */
     public Json5Array getAsJson5Array(String memberName) {
@@ -183,21 +261,33 @@
     /**
      * Convenience method to get the specified member as a Json5Object.
      *
-     * @param memberName name of the member being requested.
+     * @param memberName the name of the member being requested.
      * @return the Json5Object corresponding to the specified member.
      */
     public Json5Object getAsJson5Object(String memberName) {
         return (Json5Object) members.get(memberName);
     }
 
-    @Override
-    public boolean equals(Object o) {
-        return (o == this) || (o instanceof Json5Object
-                && ((Json5Object) o).members.equals(members));
+    /**
+     * 暂不支持直接转POJO对象,请使用toStandardString然后使用其它反序列化框架处理
+     * @see Json5Element#toString(Json5Options)
+     * @see Json5Element#toStandardString
+     *
+     * @param clazz The class of the POJO to convert to.
+     * @param <T> The type of the POJO.
+     * @return An instance of the specified POJO class, populated with data from this Json5Object.
+     */
+    public <T> T toPojo(Class<T> clazz) throws Exception {
+        throw new Exception("不支持的操作!");
     }
 
     @Override
     public int hashCode() {
         return members.hashCode();
     }
+
+    @Override
+    public boolean equals(Object o) {
+        return (o == this) || (o instanceof Json5Object && ((Json5Object) o).members.equals(members));
+    }
 }
\ No newline at end of file
Index: src/main/java/de/marhali/json5/Json5Options.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Options.java b/src/main/java/de/marhali/json5/Json5Options.java
--- a/src/main/java/de/marhali/json5/Json5Options.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Options.java	(date 1757065878329)
@@ -61,11 +61,43 @@
      */
     private final int indentFactor;
 
-    public Json5Options(boolean allowInvalidSurrogates, boolean quoteSingle, boolean trailingComma, int indentFactor) {
+    //<editor-fold desc="Modified by Ultreon (added quoteless parameter)">
+    /**
+     * Whether keys of {@link Json5Object} should be without quotes.
+     * This is unless starting or ending with a digit.
+     */
+    private final boolean quoteless;
+
+    /**
+     * parse时是否读取注释
+     */
+    private final boolean readComments;
+
+    /**
+     * write时是否写注释
+     */
+    private final boolean writeComments;
+
+    //</editor-fold>
+    public Json5Options(boolean allowInvalidSurrogates, boolean quoteSingle, boolean trailingComma, int indentFactor, boolean quoteless, boolean readComments,
+        boolean writeComments) {
+        this.allowInvalidSurrogates = allowInvalidSurrogates;
+        this.quoteSingle = quoteSingle;
+        this.trailingComma = trailingComma;
+        this.indentFactor = Math.max(0, indentFactor);
+        this.quoteless = quoteless;
+        this.readComments = readComments;
+        this.writeComments = writeComments;
+    }
+
+    public Json5Options(boolean allowInvalidSurrogates, boolean quoteSingle, boolean trailingComma, int indentFactor, boolean quoteless) {
         this.allowInvalidSurrogates = allowInvalidSurrogates;
         this.quoteSingle = quoteSingle;
         this.trailingComma = trailingComma;
         this.indentFactor = Math.max(0, indentFactor);
+        this.quoteless = quoteless;
+        this.readComments = false;
+        this.writeComments = true;
     }
 
     public boolean isAllowInvalidSurrogates() {
@@ -76,6 +108,10 @@
         return quoteSingle;
     }
 
+    public boolean isWriteComments() {
+        return writeComments;
+    }
+
     public boolean isTrailingComma() {
         return trailingComma;
     }
@@ -83,4 +119,14 @@
     public int getIndentFactor() {
         return indentFactor;
     }
+
+    public boolean isReadComments() {
+        return readComments;
+    }
+
+    //<editor-fold desc="Modified by Ultreon (added quoteless getter)">
+    public boolean isQuoteless() {
+        return quoteless;
+    }
+    //</editor-fold>
 }
\ No newline at end of file
Index: src/main/java/de/marhali/json5/Json5OptionsBuilder.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5OptionsBuilder.java b/src/main/java/de/marhali/json5/Json5OptionsBuilder.java
--- a/src/main/java/de/marhali/json5/Json5OptionsBuilder.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5OptionsBuilder.java	(date 1757065878329)
@@ -28,8 +28,16 @@
     private boolean quoteSingle = false;
     private boolean trailingComma = false;
 
+    //<editor-fold desc="Modified by Ultreon (added support for quoteless)">
+    private boolean quoteless = false;
+    //</editor-fold>
+
     private int indentFactor = 0;
 
+    private boolean readComments = false;
+
+    private boolean writeComments = true;
+
     /**
      * Constructs a new builder instance.
      */
@@ -87,10 +95,42 @@
         return this;
     }
 
+    //<editor-fold desc="Modified by Ultreon (added support for quoteless)">
+    /**
+     * Configures to output {@link Json5Object} keys without quotes. This option only affects Json serialization.
+     * This option has no effect if the key starts or ends with a digit, or if the key contains non-alphanumeric characters.
+     *
+     * @return Current builder instance
+     */
+    public Json5OptionsBuilder quoteless() {
+        this.quoteless = true;
+        return this;
+    }
+    //</editor-fold>
+
+    /**
+     * Configures to read comments from the source. This option only affects Json parsing.
+     * @return Current builder instance
+     */
+    public Json5OptionsBuilder readComments() {
+        this.readComments = true;
+        return this;
+    }
+
+    /**
+     * 设置json5Options序列化时不写注释
+     */
+    public Json5OptionsBuilder notWriteComments() {
+        this.writeComments = false;
+        return this;
+    }
     /**
      * @return Configured {@link Json5Options}
      */
     public Json5Options build() {
-        return new Json5Options(allowInvalidSurrogates, quoteSingle, trailingComma, indentFactor);
+        //<editor-fold desc="Modified by Ultreon (added support for quoteless)">
+        return new Json5Options(allowInvalidSurrogates, quoteSingle, trailingComma, indentFactor, quoteless,
+            readComments,writeComments);
+        //</editor-fold>
     }
 }
Index: src/main/java/de/marhali/json5/Json5Primitive.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5Primitive.java b/src/main/java/de/marhali/json5/Json5Primitive.java
--- a/src/main/java/de/marhali/json5/Json5Primitive.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5Primitive.java	(date 1757065878329)
@@ -33,9 +33,15 @@
  * @author Joel Leitch
  */
 public abstract class Json5Primitive extends Json5Element {
+    protected final Object value;
+
+    public Json5Primitive(Object value) {
+        this.value = Objects.requireNonNull(value);
+    }
 
     /**
      * Quick creator for a primitive with boolean value.
+     *
      * @param value Boolean value to apply.
      * @return Corresponding primitive with provided value.
      */
@@ -45,6 +51,7 @@
 
     /**
      * Quick creator for a primitive with number value.
+     *
      * @param value Number value to apply.
      * @return Corresponding primitive with provided value.
      */
@@ -55,6 +62,7 @@
     /**
      * Quick creator for a primitive with string value.
      * Set hexadecimal to true to receive a {@link Json5Hexadecimal}.
+     *
      * @param value String value to apply.
      * @param hexadecimal Is the provided value a hex string literal?
      * @return Corresponding primitive with provided value.
@@ -65,6 +73,7 @@
 
     /**
      * Quick creator for a primitive with string value.
+     *
      * @param value String value to apply.
      * @return Corresponding primitive with provided value.
      */
@@ -72,29 +81,6 @@
         return new Json5String(value);
     }
 
-    protected final Object value;
-
-    public Json5Primitive(Object value) {
-        this.value = Objects.requireNonNull(value);
-    }
-
-    /**
-     * Returns the same value as primitives are immutable.
-     */
-    @Override
-    public Json5Element deepCopy() {
-        return this;
-    }
-
-    /**
-     * Check whether this primitive contains a boolean value.
-     *
-     * @return true if this primitive contains a boolean value, false otherwise.
-     */
-    public boolean isBoolean() {
-        return value instanceof Boolean;
-    }
-
     /**
      * convenience method to get this element as a boolean value.
      *
@@ -109,15 +95,6 @@
         return Boolean.parseBoolean(getAsString());
     }
 
-    /**
-     * Check whether this primitive contains a Number.
-     *
-     * @return true if this primitive contains a Number, false otherwise.
-     */
-    public boolean isNumber() {
-        return value instanceof Number;
-    }
-
     /**
      * convenience method to get this element as a Number.
      *
@@ -129,15 +106,6 @@
         return value instanceof String ? new LazilyParsedNumber((String) value) : (Number) value;
     }
 
-    /**
-     * Check whether this primitive contains a String value.
-     *
-     * @return true if this primitive contains a String value, false otherwise.
-     */
-    public boolean isString() {
-        return value instanceof String;
-    }
-
     /**
      * convenience method to get this element as a String.
      *
@@ -165,29 +133,6 @@
         return isNumber() ? getAsNumber().doubleValue() : Double.parseDouble(getAsString());
     }
 
-    /**
-     * convenience method to get this element as a {@link BigDecimal}.
-     *
-     * @return get this element as a {@link BigDecimal}.
-     * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
-     */
-    @Override
-    public BigDecimal getAsBigDecimal() {
-        return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
-    }
-
-    /**
-     * convenience method to get this element as a {@link BigInteger}.
-     *
-     * @return get this element as a {@link BigInteger}.
-     * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
-     */
-    @Override
-    public BigInteger getAsBigInteger() {
-        return value instanceof BigInteger ?
-                (BigInteger) value : new BigInteger(value.toString());
-    }
-
     /**
      * convenience method to get this element as a float.
      *
@@ -210,17 +155,6 @@
         return isNumber() ? getAsNumber().longValue() : Long.parseLong(getAsString());
     }
 
-    /**
-     * convenience method to get this element as a primitive short.
-     *
-     * @return get this element as a primitive short.
-     * @throws NumberFormatException if the value contained is not a valid short value.
-     */
-    @Override
-    public short getAsShort() {
-        return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
-    }
-
     /**
      * convenience method to get this element as a primitive integer.
      *
@@ -237,12 +171,72 @@
         return isNumber() ? getAsNumber().byteValue() : Byte.parseByte(getAsString());
     }
 
+    /**
+     * convenience method to get this element as a {@link BigDecimal}.
+     *
+     * @return get this element as a {@link BigDecimal}.
+     * @throws NumberFormatException if the value contained is not a valid {@link BigDecimal}.
+     */
+    @Override
+    public BigDecimal getAsBigDecimal() {
+        return value instanceof BigDecimal ? (BigDecimal) value : new BigDecimal(value.toString());
+    }
+
+    /**
+     * convenience method to get this element as a {@link BigInteger}.
+     *
+     * @return get this element as a {@link BigInteger}.
+     * @throws NumberFormatException if the value contained is not a valid {@link BigInteger}.
+     */
+    @Override
+    public BigInteger getAsBigInteger() {
+        return value instanceof BigInteger ? (BigInteger) value : new BigInteger(value.toString());
+    }
+
+    /**
+     * convenience method to get this element as a primitive short.
+     *
+     * @return get this element as a primitive short.
+     * @throws NumberFormatException if the value contained is not a valid short value.
+     */
+    @Override
+    public short getAsShort() {
+        return isNumber() ? getAsNumber().shortValue() : Short.parseShort(getAsString());
+    }
+
+    /**
+     * Check whether this primitive contains a boolean value.
+     *
+     * @return true if this primitive contains a boolean value, false otherwise.
+     */
+    public boolean isBoolean() {
+        return value instanceof Boolean;
+    }
+
+    /**
+     * Check whether this primitive contains a Number.
+     *
+     * @return true if this primitive contains a Number, false otherwise.
+     */
+    public boolean isNumber() {
+        return value instanceof Number;
+    }
+
+    /**
+     * Check whether this primitive contains a String value.
+     *
+     * @return true if this primitive contains a String value, false otherwise.
+     */
+    public boolean isString() {
+        return value instanceof String;
+    }
+
     @Override
     public int hashCode() {
         if (value == null) {
             return 31;
         }
-        // Using recommended hashing algorithm from Effective Java for longs and doubles
+        // Using the recommended hashing algorithm from Effective Java for longs and doubles
         if (isIntegral(this)) {
             long value = getAsNumber().longValue();
             return (int) (value ^ (value >>> 32));
@@ -262,7 +256,7 @@
         if (obj == null || getClass() != obj.getClass()) {
             return false;
         }
-        Json5Primitive other = (Json5Primitive)obj;
+        Json5Primitive other = (Json5Primitive) obj;
         if (value == null) {
             return other.value == null;
         }
@@ -287,7 +281,7 @@
         if (primitive.value instanceof Number) {
             Number number = (Number) primitive.value;
             return number instanceof BigInteger || number instanceof Long || number instanceof Integer
-                    || number instanceof Short || number instanceof Byte;
+                || number instanceof Short || number instanceof Byte;
         }
         return false;
     }
Index: src/main/java/de/marhali/json5/Json5String.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/main/java/de/marhali/json5/Json5String.java b/src/main/java/de/marhali/json5/Json5String.java
--- a/src/main/java/de/marhali/json5/Json5String.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/main/java/de/marhali/json5/Json5String.java	(date 1757065878247)
@@ -25,4 +25,21 @@
     public Json5String(String string) {
         super(string);
     }
+
+    @Override
+    public Json5Element deepCopy() {
+        Json5String o = new Json5String((String) value);
+        o.setComment(getComment());
+        return o;
+    }
+
+    @Override
+    public Json5Element noCommentCopy() {
+        return new Json5String((String) value);
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return ((String) this.value).isEmpty();
+    }
 }
Index: src/test/java/de/marhali/json5/TestJson5.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/src/test/java/de/marhali/json5/TestJson5.java b/src/test/java/de/marhali/json5/TestJson5.java
--- a/src/test/java/de/marhali/json5/TestJson5.java	(revision d220224342fac20d9636fe37b6379afe2faef53e)
+++ b/src/test/java/de/marhali/json5/TestJson5.java	(date 1757065878247)
@@ -16,13 +16,20 @@
 
 package de.marhali.json5;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
-
-import static org.junit.jupiter.api.Assertions.*;
+import java.util.Optional;
 
 /**
  * Unit tests for the {@link Json5} core class.
@@ -30,7 +37,6 @@
  * @author Marcel Haßlinger
  */
 public class TestJson5 {
-
     private Json5 json5;
 
     private InputStream getTestResource(String fileName) {
@@ -45,14 +51,14 @@
                 buf.write((byte) result);
             }
 
-            return buf.toString(StandardCharsets.UTF_8);
+            return Optional.ofNullable(buf.toString(StandardCharsets.UTF_8)).map(s -> s.replace("\r\n", "\n")).map(
+                s -> s.replace("\r", "\n")).orElse(null);
         }
     }
 
     @BeforeEach
     void setup() {
-        json5 = Json5.builder(builder ->
-                builder.allowInvalidSurrogate().quoteSingle().indentFactor(2).build());
+        json5 = Json5.builder(builder -> builder.allowInvalidSurrogate().quoteSingle().indentFactor(2).build());
     }
 
     @Test
@@ -71,7 +77,7 @@
         Json5Object element = new Json5Object();
         element.addProperty("key", "value");
         element.addProperty("bool", true);
-        element.add("hex",  new Json5Hexadecimal("0x100"));
+        element.add("hex", new Json5Hexadecimal("0x100"));
 
         String jsonString = json5.serialize(element);
         String expect = "{\n  'key': 'value',\n  'bool': true,\n  'hex': 0x100\n}";
@@ -81,7 +87,7 @@
 
     @Test
     void ioArrayFile() throws IOException {
-        try(InputStream stream = getTestResource("test.array.json5")) {
+        try (InputStream stream = getTestResource("test.array.json5")) {
             Json5Element element = json5.parse(stream);
             assertTrue(element.isJson5Array());
             assertEquals(getTestResourceContent("expect.array.json5"), json5.serialize(element));
@@ -90,10 +96,47 @@
 
     @Test
     void ioObjectFile() throws IOException {
-        try(InputStream stream = getTestResource("test.object.json5")) {
+        try (InputStream stream = getTestResource("test.object.json5")) {
             Json5Element element = json5.parse(stream);
             assertTrue(element.isJson5Object());
             assertEquals(getTestResourceContent("expect.object.json5"), json5.serialize(element));
         }
     }
+
+    @Test
+    void testIsEmptyBehavior() {
+        // Json5Null
+        Json5Element nullValue = new Json5Null();
+        assertTrue(nullValue.isEmpty(), "Json5Null 应该被视为空");
+
+        // 空 Json5Object
+        Json5Object emptyObj = new Json5Object();
+        assertTrue(emptyObj.isEmpty(), "空 Json5Object 应该被视为空");
+
+        // 非空 Json5Object
+        Json5Object nonEmptyObj = new Json5Object();
+        nonEmptyObj.add("key", new Json5String("value"));
+        assertFalse(nonEmptyObj.isEmpty(), "非空 Json5Object 不应被视为空");
+
+        // 空 Json5Array
+        Json5Array emptyArr = new Json5Array();
+        assertTrue(emptyArr.isEmpty(), "空 Json5Array 应该被视为空");
+
+        // 非空 Json5Array
+        Json5Array nonEmptyArr = new Json5Array();
+        nonEmptyArr.add(new Json5String("item"));
+        assertFalse(nonEmptyArr.isEmpty(), "非空 Json5Array 不应被视为空");
+
+        // 空 Json5String
+        Json5String emptyStr = new Json5String("");
+        assertTrue(emptyStr.isEmpty(), "空字符串应该被视为空");
+
+        // 非空 Json5String
+        Json5String nonEmptyStr = new Json5String("hello");
+        assertFalse(nonEmptyStr.isEmpty(), "非空字符串不应被视为空");
+
+        // 其它类型(例如 Json5Number)
+        Json5Element number = new Json5Number(42); // 假设你有这个类型
+        assertFalse(number.isEmpty(), "Json5Number 不应被视为空");
+    }
 }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions