Skip to content

Commit 75f3d2a

Browse files
committed
Complete stringifier, swap out functions in JSONObject for new Stringifier methods
1 parent 6e1aef7 commit 75f3d2a

File tree

6 files changed

+170
-154
lines changed

6 files changed

+170
-154
lines changed

src/main/java/core/FileOperations.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public static enum FileExtension {
2424
private final String extension;
2525

2626
FileExtension(String extension) {
27-
this.extension = extension;
27+
this.extension = extension != null ? extension : "";
2828
}
2929

3030
public String getExtension() {

src/main/java/core/JSONObject.java

Lines changed: 16 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,6 @@
1111
*/
1212
public class JSONObject implements Iterable<Object> {
1313

14-
/**
15-
* The maximum number of array entries which may be put on a single line in the string representation. Objects are
16-
* expanded and count as at least three lines.
17-
*/
18-
public static final int SINGLE_LINE_ENTRIES_MAX = 5;
19-
/** The maximum length of a line in string representation. Lines exceeding this length will be split. */
20-
public static final int LINE_LENGTH_MAX = 55;
21-
/** String used for indentation in formatted string output. */
22-
public static final String INDENT = " ";
23-
2414
/*
2515
* Valid JSON types include:
2616
* String:
@@ -180,7 +170,14 @@ public Boolean getAsBoolean() {
180170
}
181171

182172
public JSONObject getAsObject() {
183-
return value instanceof JSONObject ? (JSONObject) value : null;
173+
174+
if (value instanceof JSONObject) return (JSONObject) value;
175+
176+
if (value instanceof List<?> && type.equals(JSONObject.class)) {
177+
return this;
178+
}
179+
180+
return null;
184181
}
185182

186183
public List<?> getAsList() {
@@ -307,112 +304,7 @@ public Iterator<Object> iterator() {
307304
*/
308305
@Override
309306
public String toString() {
310-
return toString(0);
311-
}
312-
313-
/**
314-
* Turn this JSONObject into a String representation. Works recursively increasing the indentation with each
315-
* recursion.
316-
*
317-
* @param indent
318-
* The number of indentation steps to add to each line in the resulting String
319-
*
320-
* @return The String representation of this JSONObject, indented the given number of steps
321-
*
322-
* @see JSONObject#toString()
323-
* @see JSONObject#INDENT
324-
*/
325-
private String toString(int indent) {
326-
StringBuilder sb = new StringBuilder();
327-
String indentation = INDENT.repeat(indent);
328-
329-
if (!key.equals(""))
330-
sb.append(String.format("\"%s\" : ", this.key));
331-
332-
if (value == null)
333-
sb.append("null");
334-
else if (value instanceof String)
335-
sb.append(String.format("\"%s\"", value));
336-
else if (value instanceof Number || value instanceof Boolean)
337-
sb.append(value);
338-
else if (value instanceof List<?>) {
339-
List<?> list = getAsList();
340-
if (list.isEmpty()) {
341-
if (type != null && JSONObject.class.isAssignableFrom(type))
342-
sb.append("{}");
343-
else
344-
sb.append("[]");
345-
}
346-
else if (list.get(0) instanceof JSONObject) {
347-
sb.append("{\n");
348-
for (int i = 0; i < list.size(); i++) {
349-
sb.append(indentation).append(INDENT);
350-
JSONObject item = (JSONObject) list.get(i);
351-
if (item == null) {
352-
System.out.println("null");
353-
}
354-
if (item != null) {
355-
sb.append(item.toString(indent + 1));
356-
}
357-
else {
358-
sb.append("null");
359-
}
360-
if (i < list.size() - 1)
361-
sb.append(",");
362-
sb.append("\n");
363-
}
364-
sb.append(indentation).append("}");
365-
}
366-
else {
367-
StringBuilder listStrB = new StringBuilder();
368-
listStrB.append("[");
369-
for (int i = 0; i < list.size(); i++) {
370-
if (i > 0)
371-
listStrB.append(", ");
372-
listStrB.append(formatValue(list.get(i)));
373-
}
374-
listStrB.append("]");
375-
String result = listStrB.toString();
376-
377-
if (result.length() > LINE_LENGTH_MAX || countInnerListEntries(list) > SINGLE_LINE_ENTRIES_MAX) {
378-
// List must be single entry per line
379-
String[] lines = StringOperations.splitByStringNotInArray(result.substring(1, result.length() - 1),
380-
",");
381-
result = "";
382-
for (int i = 0; i < lines.length; i++) {
383-
String[] linelines = lines[i].split("\n");
384-
int extraIndent = 0;
385-
for (int j = 0; j < linelines.length; j++) {
386-
String lineline = linelines[j];
387-
if (lineline.equals("}"))
388-
extraIndent--;
389-
result += indentation + INDENT + INDENT.repeat(extraIndent) + lineline.trim();
390-
if (lineline.equals("{")) {
391-
extraIndent++;
392-
result += "\n"; // skip comma
393-
continue;
394-
}
395-
if (j < linelines.length - 2)
396-
result += ",\n";
397-
else if (j == linelines.length - 2)
398-
result += "\n";
399-
else if (i < lines.length - 1)
400-
result += ",\n";
401-
}
402-
}
403-
// result = String.join(",\n", lines);
404-
405-
sb.append("[\n").append(result).append("\n").append(indentation).append("]");
406-
}
407-
else {
408-
result = indentation + INDENT + result;
409-
410-
sb.append(result.trim());
411-
}
412-
}
413-
}
414-
415-
return sb.toString();
307+
return String.join("\n", JSONStringifier.expandJson(JSONStringifier.stringifyJson(this)));
416308
}
417309

418310
/**
@@ -474,7 +366,13 @@ public int hashCode() {
474366
*
475367
* @see JSONObject#toString()
476368
*/
477-
public boolean equals(JSONObject other) {
369+
@Override
370+
public boolean equals(Object obj) {
371+
if (this == obj)
372+
return true;
373+
if (obj == null || getClass() != obj.getClass())
374+
return false;
375+
JSONObject other = (JSONObject) obj;
478376
return this.toString().equals(other.toString());
479377
}
480378

src/main/java/core/JSONProcessor.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public class JSONProcessor {
3737
*/
3838

3939
public static JSONObject processJson(Path path) {
40+
if (path == null) return null;
4041
List<String> contents = FileOperations.readFile(path);
4142
String key = path.getFileName().toString().split("\\.")[0];
4243
return processJson(key, contents);

src/main/java/core/JSONStringifier.java

Lines changed: 96 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
package core;
22

33
import java.nio.file.Path;
4+
import java.util.ArrayList;
45
import java.util.Iterator;
56
import java.util.List;
67

78
public class JSONStringifier {
8-
9-
public static void main(String[] args) {
10-
JSONObject json = JSONProcessor.processJson(Path.of("src\\tests\\java\\data\\test1\\test1.json"));
11-
System.out.println(JSONStringifier.stringifyJson(json));
12-
}
139

1410
/*
1511
* JSON BNF Grammar
@@ -40,37 +36,61 @@ public static void main(String[] args) {
4036
*/
4137

4238
public static String stringifyJson(JSONObject json) {
43-
return stringifyValue(json.getValue());
39+
String result = stringifyObject(json.getAsObject());
40+
return result.substring(1, result.length() - 1);
4441
}
4542

46-
public static String stringifyValue(Object value) {
47-
if (value instanceof List) {
48-
List<?> list = (List<?>) value;
49-
if (!list.isEmpty()) {
50-
51-
}
52-
return stringifyArray((List<?>) value);
43+
public static String stringifyValue(Object value, Class<?> type) {
44+
if (type.equals(JSONObject.class)) {
45+
@SuppressWarnings("unchecked") // The type of this object is known from the type parameter
46+
ArrayList<JSONObject> objects = (ArrayList<JSONObject>) value;
47+
StringBuilder result = new StringBuilder();
48+
for (JSONObject object : objects)
49+
result.append(stringifyObject(object));
50+
return result.toString();
51+
}
52+
if (type.equals(ArrayList.class)) {
53+
return stringifyArray((ArrayList<?>) value);
5354
}
55+
return stringifyValue(value);
56+
}
57+
public static String stringifyValue(Object value) {
5458
if (value instanceof String) return "\"" + stringifyEscape((String) value) + "\"";
5559
if (value instanceof Number || value instanceof Boolean) return value.toString();
5660
if (value == null) return "null";
5761
else throw new IllegalArgumentException("Unsupported JSON value: " + value);
5862
}
59-
public static String stringifyValue(Object value, Class<?> type) {
60-
return null;
61-
}
6263

6364
public static String stringifyObject(JSONObject object) {
6465
if (object == null) return "{}";
6566

6667
StringBuilder sb = new StringBuilder();
6768
sb.append("{");
68-
Iterator<?> it = object.iterator();
69-
while (it.hasNext()) {
70-
sb.append(stringifyValue(object.getKey())).append(" : ");
71-
sb.append(stringifyValue(it.next()));
72-
if (it.hasNext()) sb.append(", ");
69+
70+
sb.append(stringifyValue(object.getKey()));
71+
sb.append(" : ");
72+
73+
Object value = object.getValue();
74+
Class<?> type = object.getType();
75+
76+
if (value == null)
77+
sb.append("null");
78+
else if (type != null && type.equals(JSONObject.class)) {
79+
@SuppressWarnings("unchecked")
80+
List<JSONObject> objects = (ArrayList<JSONObject>) value;
81+
sb.append("{");
82+
for (int i = 0; i < objects.size(); i++) {
83+
String nested = stringifyObject(objects.get(i));
84+
sb.append(nested.substring(1, nested.length() - 1));
85+
if (i < objects.size() - 1) sb.append(", ");
86+
}
87+
sb.append("}");
7388
}
89+
else if (type != null)
90+
sb.append(stringifyValue(value, type));
91+
else
92+
sb.append(stringifyValue(value));
93+
7494
sb.append("}");
7595

7696
return sb.toString();
@@ -102,4 +122,59 @@ public static String stringifyEscape(String escape) {
102122
.replace("\t", "\\t");
103123
}
104124

125+
public static List<String> expandJson(String json) {
126+
List<String> result = new ArrayList<>();
127+
int indentation = 0;
128+
String tab = " ";
129+
130+
StringBuilder currentLine = new StringBuilder();
131+
132+
for (int i = 0; i < json.length(); i++) {
133+
char c = json.charAt(i);
134+
135+
if (StringOperations.isInString(json, i) && c != '"') {
136+
currentLine.append(c);
137+
continue;
138+
}
139+
switch (c) {
140+
case '"' :
141+
currentLine.append(c);
142+
break;
143+
case '{' :
144+
case '[' :
145+
currentLine.append(c);
146+
result.add(tab.repeat(indentation) + currentLine);
147+
currentLine = new StringBuilder();
148+
indentation++;
149+
break;
150+
case '}' :
151+
case ']' :
152+
if (currentLine.length() > 0) {
153+
result.add(tab.repeat(indentation) + currentLine);
154+
currentLine = new StringBuilder();
155+
}
156+
indentation--;
157+
result.add(tab.repeat(indentation) + c);
158+
break;
159+
case ',' :
160+
currentLine.append(c);
161+
result.add(tab.repeat(indentation) + currentLine);
162+
currentLine = new StringBuilder();
163+
break;
164+
case ':' :
165+
currentLine.append(" ").append(c).append(" ");
166+
break;
167+
default :
168+
if (!Character.isWhitespace(c)) {
169+
currentLine.append(c);
170+
}
171+
}
172+
}
173+
174+
if (currentLine.length() > 0) {
175+
result.add(tab.repeat(indentation) + currentLine);
176+
}
177+
return result;
178+
}
179+
105180
}

src/tests/java/StringifierTests.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import static org.junit.Assert.*;
2+
import org.junit.Test;
3+
import core.JSONObject;
4+
import core.JSONStringifier;
5+
import java.util.Arrays;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
public class StringifierTests {
10+
11+
@Test
12+
public void stringifyJson() {
13+
ArrayList<JSONObject> inner = new ArrayList<>();
14+
inner.add(new JSONObject("key1", "value1"));
15+
inner.add(new JSONObject("key2", 42));
16+
JSONObject nested = new JSONObject("nested", inner);
17+
String result = JSONStringifier.stringifyJson(nested);
18+
assertEquals("\"nested\" : {\"key1\" : \"value1\", \"key2\" : 42}", result);
19+
}
20+
21+
@Test
22+
public void stringifyValue() {
23+
// Test primitive values
24+
assertEquals("\"hello\"", JSONStringifier.stringifyValue("hello"));
25+
assertEquals("42", JSONStringifier.stringifyValue(42));
26+
assertEquals("true", JSONStringifier.stringifyValue(true));
27+
assertEquals("null", JSONStringifier.stringifyValue(null));
28+
29+
// Test with type information
30+
List<Integer> numbers = new ArrayList<>();
31+
numbers.add(1);
32+
numbers.add(2);
33+
numbers.add(3);
34+
assertEquals("[1, 2, 3]", JSONStringifier.stringifyValue(numbers, ArrayList.class));
35+
36+
// Test nested objects with type
37+
List<JSONObject> objects = new ArrayList<>();
38+
objects.add(new JSONObject("key1", "value1"));
39+
objects.add(new JSONObject("key2", "value2"));
40+
String result = JSONStringifier.stringifyValue(objects, JSONObject.class);
41+
assertEquals("{\"key1\" : \"value1\"}{\"key2\" : \"value2\"}", result);
42+
}
43+
44+
}

0 commit comments

Comments
 (0)