Skip to content

Commit ad57f00

Browse files
committed
more frugal enumset + correctly typed empty enumsets
1 parent 1463fa8 commit ad57f00

File tree

5 files changed

+180
-29
lines changed

5 files changed

+180
-29
lines changed

src/main/java/com/cedarsoftware/util/io/JsonWriter.java

+81
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,10 @@ public void writeImpl(Object obj, boolean showType, boolean allowRef, boolean al
10891089
{
10901090
writeArray(obj, showType);
10911091
}
1092+
else if (obj instanceof EnumSet)
1093+
{
1094+
writeEnumSet((EnumSet)obj, showType);
1095+
}
10921096
else if (obj instanceof Collection)
10931097
{
10941098
writeCollection((Collection) obj, showType);
@@ -2207,6 +2211,83 @@ else if (neverShowType && MetaUtils.isPrimitive(o.getClass()))
22072211
}
22082212
}
22092213

2214+
public void writeEnumSet(final EnumSet<?> enumSet, boolean showType) throws IOException
2215+
{
2216+
out.write('{');
2217+
tabIn();
2218+
2219+
boolean referenced = objsReferenced.containsKey(enumSet);
2220+
if (referenced)
2221+
{
2222+
writeId(getId(enumSet));
2223+
out.write(',');
2224+
newLine();
2225+
}
2226+
2227+
if (showType) {
2228+
writeType(enumSet, out);
2229+
out.write(",");
2230+
newLine();
2231+
}
2232+
2233+
writeJsonUtf8String("@enum", out);
2234+
out.write(':');
2235+
2236+
Field elementTypeField = MetaUtils.getField(EnumSet.class, "elementType");
2237+
Class elementType = (Class) getValueByReflect(enumSet, elementTypeField);
2238+
writeJsonUtf8String(elementType.getName(), out);
2239+
2240+
var mapOfFileds = MetaUtils.getDeepDeclaredFields(elementType);
2241+
//Field[] enumFields = elementType.getDeclaredFields();
2242+
int enumFieldsCount = mapOfFileds.size();
2243+
2244+
if (!enumSet.isEmpty()) {
2245+
out.write(",");
2246+
newLine();
2247+
2248+
writeJsonUtf8String("@items", out);
2249+
out.write(":[");
2250+
if (enumFieldsCount > 2)
2251+
{
2252+
newLine();
2253+
}
2254+
2255+
boolean firstInSet = true;
2256+
for (var e : enumSet) {
2257+
if (!firstInSet)
2258+
{
2259+
out.write(",");
2260+
if (enumFieldsCount > 2)
2261+
{
2262+
newLine();
2263+
}
2264+
}
2265+
firstInSet = false;
2266+
2267+
if (enumFieldsCount <= 2)
2268+
{
2269+
writeJsonUtf8String(e.name(), out);
2270+
}
2271+
else
2272+
{
2273+
boolean firstInEntry = true;
2274+
out.write('{');
2275+
for (var f : mapOfFileds.values())
2276+
{
2277+
firstInEntry = writeField(e, firstInEntry, f.getName(), f, false);
2278+
}
2279+
out.write('}');
2280+
}
2281+
}
2282+
2283+
out.write("]");
2284+
}
2285+
2286+
2287+
tabOut();
2288+
out.write('}');
2289+
}
2290+
22102291
/**
22112292
* @param obj Object to be written in JSON format
22122293
* @param showType boolean true means show the "@type" field, false

src/main/java/com/cedarsoftware/util/io/ObjectResolver.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,13 @@ protected void traverseCollection(final Deque<JsonObject<String, Object>> stack,
414414
}
415415
return;
416416
}
417+
418+
Class mayEnumClass = null;
419+
String mayEnumClasName = (String)jsonObj.get("@enum");
420+
if (mayEnumClasName != null) {
421+
mayEnumClass = MetaUtils.classForName(mayEnumClasName, classLoader);
422+
}
423+
417424
final boolean isImmutable = className != null && className.startsWith("java.util.Immutable");
418425
final Collection col = isImmutable ? new ArrayList() : (Collection) jsonObj.target;
419426
final boolean isList = col instanceof List;
@@ -436,7 +443,10 @@ else if ((special = readIfMatching(element, null, stack)) != null)
436443
}
437444
else if (element instanceof String || element instanceof Boolean || element instanceof Double || element instanceof Long)
438445
{ // Allow Strings, Booleans, Longs, and Doubles to be "inline" without Java object decoration (@id, @type, etc.)
439-
col.add(element);
446+
if (mayEnumClass == null)
447+
col.add(element);
448+
else
449+
col.add(Enum.valueOf(mayEnumClass, (String)element));
440450
}
441451
else if (element.getClass().isArray())
442452
{

src/main/java/com/cedarsoftware/util/io/Resolver.java

+39-3
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ else if (Enum.class.isAssignableFrom(c)) // anonymous subclass of an enum
380380
}
381381
else if (EnumSet.class.isAssignableFrom(c))
382382
{
383-
mate = getEnumSet(c, jsonObj);
383+
mate = extractEnumSet(c, jsonObj);
384384
}
385385
else if ((mate = coerceCertainTypes(c.getName())) != null)
386386
{ // if coerceCertainTypes() returns non-null, it did the work
@@ -426,7 +426,7 @@ else if (Enum.class.isAssignableFrom(clazz)) // anonymous subclass of an enum
426426
}
427427
else if (EnumSet.class.isAssignableFrom(clazz)) // anonymous subclass of an enum
428428
{
429-
mate = getEnumSet(clazz, jsonObj);
429+
mate = extractEnumSet(clazz, jsonObj);
430430
}
431431
else if ((mate = coerceCertainTypes(clazz.getName())) != null)
432432
{ // if coerceCertainTypes() returns non-null, it did the work
@@ -533,7 +533,7 @@ private static enum OneEnum {
533533
/*
534534
/* java 17 don't allow to call reflect on internal java api like EnumSet's implement, so need to create like this
535535
*/
536-
private Object getEmptyEnumSet() {
536+
private EnumSet getEmptyEnumSet() {
537537
return EnumSet.noneOf(OneEnum.class);
538538
}
539539

@@ -568,6 +568,42 @@ private Object getEnumSet(Class c, JsonObject<String, Object> jsonObj)
568568
return enumSet;
569569
}
570570

571+
protected EnumSet<?> extractEnumSet(Class c, JsonObject<String, Object> jsonObj)
572+
{
573+
String enumClassName = (String) jsonObj.get("@enum");
574+
Class enumClass = MetaUtils.classForName(enumClassName, reader.getClassLoader());
575+
Object[] items = jsonObj.getArray();
576+
if (items == null || items.length == 0)
577+
{
578+
return EnumSet.noneOf(enumClass);
579+
}
580+
581+
EnumSet enumSet = null;
582+
for (Object item : items)
583+
{
584+
Enum enumItem;
585+
if (item instanceof String)
586+
{
587+
enumItem = Enum.valueOf(enumClass, (String)item);
588+
}
589+
else
590+
{
591+
JsonObject jsItem = (JsonObject) item;
592+
enumItem = Enum.valueOf(c, (String) jsItem.get("name"));
593+
}
594+
595+
if (enumSet == null)
596+
{ // Lazy init the EnumSet
597+
enumSet = EnumSet.of(enumItem);
598+
}
599+
else
600+
{
601+
enumSet.add(enumItem);
602+
}
603+
}
604+
return enumSet;
605+
}
606+
571607
/**
572608
* For all fields where the value was "@ref":"n" where 'n' was the id of an object
573609
* that had not yet been encountered in the stream, make the final substitution.

src/test/java/com/cedarsoftware/util/io/TestEmptyEnumSetOnJDK17.java

+36-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package com.cedarsoftware.util.io;
22

3-
import com.google.gson.Gson;
43
import org.junit.Test;
54

6-
import java.util.ArrayList;
75
import java.util.EnumSet;
8-
import java.util.List;
9-
import java.util.Map;
6+
import java.util.Objects;
107

118
/**
129
* @author John DeRegnaucourt ([email protected])
@@ -29,7 +26,29 @@ public class TestEmptyEnumSetOnJDK17
2926
{
3027
static enum TestEnum
3128
{
32-
V1
29+
V1, V2, V3
30+
}
31+
32+
static class MultiVersioned
33+
{
34+
EnumSet<TestEnum> versions;
35+
String dummy;
36+
37+
public MultiVersioned(EnumSet<TestEnum> versions, String dummy) {
38+
this.versions = versions;
39+
this.dummy = dummy;
40+
}
41+
42+
public boolean equals(Object o) {
43+
if (this == o) return true;
44+
if (o == null || getClass() != o.getClass()) return false;
45+
MultiVersioned that = (MultiVersioned) o;
46+
return Objects.equals(versions, that.versions) && Objects.equals(dummy, that.dummy);
47+
}
48+
49+
public int hashCode() {
50+
return Objects.hash(versions, dummy);
51+
}
3352
}
3453

3554
@Test
@@ -46,11 +65,22 @@ public void testEmptyEnumSetOnJDK17()
4665
@Test
4766
public void testEnumSetOnJDK17()
4867
{
49-
EnumSet source = EnumSet.of(TestEnum.V1);
68+
EnumSet source = EnumSet.of(TestEnum.V1, TestEnum.V3);
5069

5170
String json = JsonWriter.objectToJson(source);
5271
EnumSet target = (EnumSet) JsonReader.jsonToJava(json);
5372

5473
assert source.equals(target);
5574
}
75+
@Test
76+
77+
public void testEnumSetInPoJoOnJDK17()
78+
{
79+
MultiVersioned m = new MultiVersioned(EnumSet.of(TestEnum.V1, TestEnum.V3), "what");
80+
81+
String json = JsonWriter.objectToJson(m);
82+
MultiVersioned target = (MultiVersioned) JsonReader.jsonToJava(json);
83+
84+
assert m.equals(target);
85+
}
5686
}

src/test/java/com/cedarsoftware/util/io/TestJDK9Immutable.java

+13-19
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public void testCopyOfListOf() {
2727
final Object o = new ArrayList<>(List.of());
2828

2929
String json = JsonWriter.objectToJson(o);
30-
List es = (List) JsonReader.jsonToJava(json);
30+
List<?> es = (List<?>) JsonReader.jsonToJava(json);
3131

3232
Assert.assertEquals(0, es.size());
3333
Assert.assertEquals(o.getClass(), es.getClass());
@@ -38,7 +38,7 @@ public void testListOf() {
3838
final Object o = List.of();
3939

4040
String json = JsonWriter.objectToJson(o);
41-
List es = (List) JsonReader.jsonToJava(json);
41+
List<?> es = (List<?>) JsonReader.jsonToJava(json);
4242

4343
Assert.assertEquals(0, es.size());
4444
Assert.assertEquals(o.getClass(), es.getClass());
@@ -49,7 +49,7 @@ public void testListOfOne() {
4949
final Object o = List.of("One");
5050

5151
String json = JsonWriter.objectToJson(o);
52-
List es = (List) JsonReader.jsonToJava(json);
52+
List<?> es = (List<?>) JsonReader.jsonToJava(json);
5353

5454
Assert.assertEquals(1, es.size());
5555
Assert.assertEquals(o.getClass(), es.getClass());
@@ -60,7 +60,7 @@ public void testListOfTwo() {
6060
final Object o = List.of("One", "Two");
6161

6262
String json = JsonWriter.objectToJson(o);
63-
List es = (List) JsonReader.jsonToJava(json);
63+
List<?> es = (List<?>) JsonReader.jsonToJava(json);
6464

6565
Assert.assertEquals(2, es.size());
6666
Assert.assertEquals(o.getClass(), es.getClass());
@@ -71,7 +71,7 @@ public void testListOfThree() {
7171
final Object o = List.of("One", "Two", "Three");
7272

7373
String json = JsonWriter.objectToJson(o);
74-
List es = (List) JsonReader.jsonToJava(json);
74+
List<?> es = (List<?>) JsonReader.jsonToJava(json);
7575

7676
Assert.assertEquals(3, es.size());
7777
Assert.assertEquals(o.getClass(), es.getClass());
@@ -82,7 +82,7 @@ public void testSetOf() {
8282
final Object o = Set.of();
8383

8484
String json = JsonWriter.objectToJson(o);
85-
Set es = (Set) JsonReader.jsonToJava(json);
85+
Set<?> es = (Set<?>) JsonReader.jsonToJava(json);
8686

8787
Assert.assertEquals(0, es.size());
8888
Assert.assertEquals(o.getClass(), es.getClass());
@@ -93,7 +93,7 @@ public void testSetOfOne() {
9393
final Object o = Set.of("One");
9494

9595
String json = JsonWriter.objectToJson(o);
96-
Set es = (Set) JsonReader.jsonToJava(json);
96+
Set<?> es = (Set<?>) JsonReader.jsonToJava(json);
9797

9898
Assert.assertEquals(1, es.size());
9999
Assert.assertEquals(o.getClass(), es.getClass());
@@ -104,7 +104,7 @@ public void testSetOfTwo() {
104104
final Object o = Set.of("One", "Two");
105105

106106
String json = JsonWriter.objectToJson(o);
107-
Set es = (Set) JsonReader.jsonToJava(json);
107+
Set<?> es = (Set<?>) JsonReader.jsonToJava(json);
108108

109109
Assert.assertEquals(2, es.size());
110110
Assert.assertEquals(o.getClass(), es.getClass());
@@ -115,7 +115,7 @@ public void testSetOfThree() {
115115
final Object o = Set.of("One", "Two", "Three");
116116

117117
String json = JsonWriter.objectToJson(o);
118-
Set es = (Set) JsonReader.jsonToJava(json);
118+
Set<?> es = (Set<?>) JsonReader.jsonToJava(json);
119119

120120
Assert.assertEquals(3, es.size());
121121
Assert.assertEquals(o.getClass(), es.getClass());
@@ -129,7 +129,6 @@ public void testListOfThreeRecsMutableBoth() {
129129
rec2.link = rec1;
130130
rec1.mlinks = new ArrayList<>(List.of());
131131
rec2.mlinks = new ArrayList<>(List.of(rec1));
132-
//List<Rec> ol = new ArrayList<>(List.of(rec1, rec2, rec1));
133132
List<Rec> ol = new ArrayList<>(List.of(rec1, rec2, rec1));
134133

135134
String json = JsonWriter.objectToJson(ol);
@@ -161,7 +160,6 @@ public void testListOfThreeRecsMutableInside() {
161160
rec2.link = rec1;
162161
rec1.mlinks = new ArrayList<>(List.of());
163162
rec2.mlinks = new ArrayList<>(List.of(rec1));
164-
//List<Rec> ol = new ArrayList<>(List.of(rec1, rec2, rec1));
165163
List<Rec> ol = List.of(rec1, rec2, rec1);
166164

167165
String json = JsonWriter.objectToJson(ol);
@@ -198,11 +196,11 @@ public void testListOfThreeRecsBoth() {
198196
List<Rec> ol = List.of(rec1, rec2, rec1);
199197

200198
String json = JsonWriter.objectToJson(ol);
201-
List es = (List) JsonReader.jsonToJava(json);
199+
Object es = (List) JsonReader.jsonToJava(json);
202200

203201
Assert.assertEquals(((Object) ol).getClass(), es.getClass());
204202

205-
List<Rec> recs = es;
203+
List<Rec> recs = (List<Rec>) es;
206204
Assert.assertEquals(ol.size(), recs.size());
207205

208206
Assert.assertEquals(ol.get(0).s, recs.get(0).s);
@@ -229,26 +227,22 @@ public void testListOfThreeRecsBoth() {
229227
public void testListOfThreeRecsImmutableOnly() {
230228
Rec rec1 = new Rec("OneOrThree", 0);
231229
Rec rec2 = new Rec("Two", 2);
232-
//rec1.link = rec2;
233-
//rec2.link = rec1;
234230
rec1.ilinks = List.of(rec2, rec1);
235231
rec2.ilinks = List.of();
236232
List<Rec> ol = List.of(rec1, rec2, rec1);
237233

238234
String json = JsonWriter.objectToJson(ol);
239-
List es = (List) JsonReader.jsonToJava(json);
235+
Object es = JsonReader.jsonToJava(json);
240236

241237
Assert.assertEquals(((Object) ol).getClass(), es.getClass());
242238

243-
List<Rec> recs = es;
239+
List<Rec> recs = (List<Rec>) es;
244240
Assert.assertEquals(ol.size(), recs.size());
245241

246242
Assert.assertEquals(ol.get(0).s, recs.get(0).s);
247243
Assert.assertEquals(ol.get(0).i, recs.get(0).i);
248-
//Assert.assertEquals(recs.get(1), recs.get(0).link);
249244
Assert.assertEquals(ol.get(1).s, recs.get(1).s);
250245
Assert.assertEquals(ol.get(1).i, recs.get(1).i);
251-
//Assert.assertEquals(recs.get(0), recs.get(1).link);
252246

253247
Assert.assertEquals(recs.get(0), recs.get(2));
254248

0 commit comments

Comments
 (0)