Skip to content

Commit eef0f8d

Browse files
committed
JSON Pretty printing
1 parent 6fb2581 commit eef0f8d

File tree

7 files changed

+106
-6
lines changed

7 files changed

+106
-6
lines changed

convex-core/src/main/java/convex/core/util/JSONUtils.java

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,18 @@ public static AString toJSONString(Object value) {
171171
appendJSON(bb, value);
172172
return Strings.create(bb.toBlob());
173173
}
174+
175+
/**
176+
* Convert any object to JSON
177+
*
178+
* @param value Value to convert to JSON, may be Java or CVM structure
179+
* @return CVM String containing valid JSON
180+
*/
181+
public static AString toJSONPretty(Object value) {
182+
BlobBuilder bb = new BlobBuilder();
183+
appendPrettyJSON(bb, RT.cvm(value),0);
184+
return Strings.create(bb.toBlob());
185+
}
174186

175187
private static void appendJSON(BlobBuilder bb, Object value) {
176188
if (value == null) {
@@ -336,6 +348,80 @@ private static void appendJSON(BlobBuilder bb, ACell value) {
336348

337349
throw new IllegalArgumentException("Can't print as JSON: "+Utils.getClassName(value));
338350
}
351+
352+
private static final int INDENT=2;
353+
354+
private static BlobBuilder appendPrettyJSON(BlobBuilder sb, ACell o, int indent) {
355+
if (o instanceof AMap) {
356+
int entryIndent = indent + INDENT;
357+
sb.append("{\n");
358+
AMap<?, ?> m = ((AMap<?, ?>) o);
359+
int size = m.size();
360+
int pos = 0;
361+
for (int i = 0; i < size; i++) {
362+
MapEntry<?,?> me=m.entryAt(i);
363+
AString k = keyValue(me.getKey());
364+
appendWhitespaceString(sb, entryIndent);
365+
sb.append(toString(k));
366+
sb.append(": ");
367+
int vIndent = entryIndent + k.size() + 4; // indent for value
368+
ACell v = me.getValue();
369+
appendPrettyJSON(sb, v, vIndent);
370+
pos++;
371+
if (pos == size) {
372+
sb.append('\n'); // final entry
373+
} else {
374+
sb.append(",\n"); // comma for next entry
375+
}
376+
}
377+
appendWhitespaceString(sb, indent);
378+
sb.append("}");
379+
} else if (o instanceof ASequence) {
380+
ASequence<?> list = (ASequence<?>) o;
381+
int size = list.size();
382+
int entryIndent = indent + 1;
383+
sb.append("[");
384+
for (int i = 0; i < size; i++) {
385+
if (i > 0) {
386+
sb.append(",\n");
387+
appendWhitespaceString(sb, entryIndent);
388+
}
389+
ACell v = list.get(i);
390+
appendPrettyJSON(sb, v, entryIndent);
391+
}
392+
sb.append("]");
393+
} else {
394+
sb.append(toString(o));
395+
}
396+
return sb;
397+
}
398+
399+
/**
400+
* Convert any CVM value into a JSON style key
401+
* @param key
402+
* @return
403+
*/
404+
private static AString keyValue(ACell key) {
405+
return RT.str(key);
406+
}
407+
408+
private static final StringShort WHITESPACE=StringShort.create(" ");
409+
private static final long WHITESPACE_LENGTH=WHITESPACE.count();
410+
/**
411+
* Appends a whitespace string of the specified length.
412+
*
413+
* @param sb StringBuilder to append the whitespace characters
414+
* @param count Number of whitespace characters
415+
* @return Updated StringBuilder
416+
*/
417+
private static BlobBuilder appendWhitespaceString(BlobBuilder sb, long count) {
418+
while (count > WHITESPACE_LENGTH) {
419+
sb.append(WHITESPACE);
420+
count -= WHITESPACE_LENGTH;
421+
}
422+
sb.append(WHITESPACE.slice(0, count));
423+
return sb;
424+
}
339425

340426

341427
private static void appendCVMStringQuoted(BlobBuilder bb, CharSequence cs) {

convex-core/src/main/java/convex/core/util/Utils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ public static String joinStrings(List<String> strings, String separator) {
13241324
* @param c Divisor
13251325
* @return Result of (a*b)/c
13261326
*/
1327-
static long slowMulDiv(long a, long b, long c) {
1327+
public static long slowMulDiv(long a, long b, long c) {
13281328
// TODO: we want a faster version of this
13291329

13301330
BigInteger result=BigInteger.valueOf(a).multiply(BigInteger.valueOf(b)).divide(BigInteger.valueOf(c));

convex-core/src/test/java/convex/core/data/VectorsTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import convex.core.data.util.VectorBuilder;
2121
import convex.core.exceptions.BadFormatException;
2222
import convex.core.lang.RT;
23-
import convex.core.utils.VisitCounter;
23+
import convex.core.util.VisitCounter;
2424
import convex.test.Samples;
2525

2626
/**

convex-core/src/test/java/convex/core/util/EconomicsTest.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import org.junit.jupiter.api.Test;
1111

12+
import convex.core.util.Economics;
13+
1214
public class EconomicsTest {
1315

1416
@Test

convex-core/src/test/java/convex/core/util/GenTestEconomics.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
import com.pholser.junit.quickcheck.Property;
1111
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck;
1212

13+
import convex.core.util.Economics;
14+
import convex.core.util.Utils;
15+
1316
@RunWith(JUnitQuickcheck.class)
1417
public class GenTestEconomics {
1518

convex-core/src/test/java/convex/core/utils/JSONUtilsTest.java renamed to convex-core/src/test/java/convex/core/util/JSONUtilsTest.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package convex.core.utils;
1+
package convex.core.util;
22

33
import static org.junit.jupiter.api.Assertions.assertEquals;
44
import static org.junit.jupiter.api.Assertions.assertNull;
@@ -34,7 +34,6 @@
3434
import convex.core.exceptions.ParseException;
3535
import convex.core.json.JSONReader;
3636
import convex.core.lang.RT;
37-
import convex.core.util.JSONUtils;
3837

3938
public class JSONUtilsTest {
4039

@@ -121,6 +120,11 @@ public void testEscape() {
121120
assertEquals(StringShort.create(" \\\""),JSONUtils.escape(" \""));
122121
}
123122

123+
@Test
124+
public void testPrettyJSON() {
125+
assertEquals("{\n \"foo\": \"bar\"\n}",JSONUtils.toJSONPretty(Maps.of("foo","bar")).toString());
126+
}
127+
124128
@Test
125129
public void testJSON() {
126130
assertNull(JSONUtils.json(null));
@@ -226,6 +230,8 @@ private void checkJSON5Only(String s) {
226230
JSONUtils.parseJSON5(s);
227231
}
228232

233+
234+
229235
@Test
230236
public void testJSONRoundTrips() {
231237

@@ -259,10 +265,13 @@ private void doJSONRoundTrip(Object o, ACell c) {
259265
String js1=JSONUtils.toString(o);
260266
String js2=JSONUtils.toString(c);
261267
assertEquals(js1.length(),js2.length()); // should be same length, orders might differ
262-
268+
269+
String jsp=JSONUtils.toJSONPretty(c).toString();
270+
263271
// Written JSON should be parseable as strict JSON
264272
assertEquals(c,JSONUtils.parse(js1),()->"JSON="+js1);
265273
assertEquals(c,JSONUtils.parse(js2));
274+
assertEquals(c,JSONUtils.parse(jsp));
266275
assertEquals(c,JSONReader.read(js2));
267276
}
268277

convex-core/src/test/java/convex/core/utils/VisitCounter.java renamed to convex-core/src/test/java/convex/core/util/VisitCounter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package convex.core.utils;
1+
package convex.core.util;
22

33
import java.util.function.Consumer;
44

0 commit comments

Comments
 (0)