Skip to content

Commit efe20a6

Browse files
Handle enums that have true/false values as booleans (#275) (#277)
Co-authored-by: Sylvain Wallez <[email protected]>
1 parent d0cfe20 commit efe20a6

File tree

4 files changed

+85
-9
lines changed

4 files changed

+85
-9
lines changed

java-client/src/main/java/co/elastic/clients/elasticsearch/_types/Refresh.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import co.elastic.clients.json.JsonEnum;
2727
import co.elastic.clients.json.JsonpDeserializable;
2828
import co.elastic.clients.json.JsonpDeserializer;
29+
import co.elastic.clients.json.JsonpMapper;
30+
import jakarta.json.stream.JsonGenerator;
2931

3032
/**
3133
*
@@ -52,5 +54,17 @@ public String jsonValue() {
5254
return this.jsonValue;
5355
}
5456

55-
public static final JsonEnum.Deserializer<Refresh> _DESERIALIZER = new JsonEnum.Deserializer<>(Refresh.values());
57+
@Override
58+
public void serialize(JsonGenerator generator, JsonpMapper params) {
59+
if (this == Refresh.True) {
60+
generator.write(true);
61+
} else if (this == Refresh.False) {
62+
generator.write(false);
63+
} else {
64+
generator.write(jsonValue());
65+
}
66+
}
67+
68+
public static final JsonEnum.Deserializer<Refresh> _DESERIALIZER = new JsonEnum.Deserializer.AllowingBooleans<>(
69+
Refresh.values());
5670
}

java-client/src/main/java/co/elastic/clients/elasticsearch/_types/mapping/DynamicMapping.java

+14-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
import co.elastic.clients.json.JsonEnum;
2727
import co.elastic.clients.json.JsonpDeserializable;
2828
import co.elastic.clients.json.JsonpDeserializer;
29+
import co.elastic.clients.json.JsonpMapper;
30+
import jakarta.json.stream.JsonGenerator;
2931

3032
/**
3133
*
@@ -55,6 +57,17 @@ public String jsonValue() {
5557
return this.jsonValue;
5658
}
5759

58-
public static final JsonEnum.Deserializer<DynamicMapping> _DESERIALIZER = new JsonEnum.Deserializer<>(
60+
@Override
61+
public void serialize(JsonGenerator generator, JsonpMapper params) {
62+
if (this == DynamicMapping.True) {
63+
generator.write(true);
64+
} else if (this == DynamicMapping.False) {
65+
generator.write(false);
66+
} else {
67+
generator.write(jsonValue());
68+
}
69+
}
70+
71+
public static final JsonEnum.Deserializer<DynamicMapping> _DESERIALIZER = new JsonEnum.Deserializer.AllowingBooleans<>(
5972
DynamicMapping.values());
6073
}

java-client/src/main/java/co/elastic/clients/json/JsonEnum.java

+40-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import java.util.Map;
3030
import java.util.NoSuchElementException;
3131

32+
import static jakarta.json.stream.JsonParser.Event;
33+
3234
/**
3335
* Base interface for enumerations in API types. Members have a JSON representation and also accept
3436
* aliases when parsed from a string value.
@@ -47,13 +49,18 @@ default void serialize(JsonGenerator generator, JsonpMapper params) {
4749
}
4850

4951
class Deserializer<T extends JsonEnum> extends JsonpDeserializerBase<T> {
52+
53+
private static final EnumSet<Event> acceptedEvents = EnumSet.of(Event.VALUE_STRING, Event.KEY_NAME);
54+
private static final EnumSet<Event> nativeEvents = EnumSet.of(Event.VALUE_STRING);
55+
5056
private final Map<String, T> lookupTable;
5157

5258
public Deserializer(T[] values) {
53-
super(
54-
EnumSet.of(JsonParser.Event.VALUE_STRING, JsonParser.Event.KEY_NAME),
55-
EnumSet.of(JsonParser.Event.VALUE_STRING)
56-
);
59+
this(values, acceptedEvents);
60+
}
61+
62+
protected Deserializer(T[] values, EnumSet<Event> acceptedEvents) {
63+
super(acceptedEvents, nativeEvents);
5764

5865
// Use the same size calculation as in java.lang.Enum.enumConstantDirectory
5966
this.lookupTable = new HashMap<>((int)(values.length / 0.75f) + 1);
@@ -69,7 +76,7 @@ public Deserializer(T[] values) {
6976
}
7077

7178
@Override
72-
public T deserialize(JsonParser parser, JsonpMapper mapper, JsonParser.Event event) {
79+
public T deserialize(JsonParser parser, JsonpMapper mapper, Event event) {
7380
String value = parser.getString();
7481
return deserialize(value, parser);
7582
}
@@ -104,5 +111,33 @@ public T parse(String value) {
104111
}
105112
return result;
106113
}
114+
115+
/**
116+
* An enum deserializer that also accepts boolean values. Used for a few properties that started as two-state booleans
117+
* and evolved into enums over time.
118+
*/
119+
public static class AllowingBooleans<T extends JsonEnum> extends Deserializer<T> {
120+
121+
private static final EnumSet<Event> acceptedEventsAndBoolean =
122+
EnumSet.of(Event.VALUE_STRING, Event.KEY_NAME, Event.VALUE_TRUE, Event.VALUE_FALSE);
123+
124+
public AllowingBooleans(T[] values) {
125+
super(values, acceptedEventsAndBoolean);
126+
}
127+
128+
@Override
129+
public T deserialize(JsonParser parser, JsonpMapper mapper, Event event) {
130+
String value;
131+
if (event == Event.VALUE_TRUE) {
132+
value = "true";
133+
} else if (event == Event.VALUE_FALSE) {
134+
value = "false";
135+
} else {
136+
value = parser.getString();
137+
}
138+
139+
return deserialize(value, parser);
140+
}
141+
}
107142
}
108143
}

java-client/src/test/java/co/elastic/clients/elasticsearch/model/EnumTest.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,13 @@
2020
package co.elastic.clients.elasticsearch.model;
2121

2222
import co.elastic.clients.elasticsearch._types.Bytes;
23+
import co.elastic.clients.elasticsearch._types.Refresh;
2324
import co.elastic.clients.elasticsearch._types.mapping.GeoOrientation;
24-
import org.junit.Assert;
2525
import org.junit.Test;
2626

2727
import java.util.Arrays;
2828

29-
public class EnumTest extends Assert {
29+
public class EnumTest extends ModelTestCase {
3030

3131
@Test
3232
public void testSimpleEnum() {
@@ -43,4 +43,18 @@ public void testEnumWithAliases() {
4343
assertEquals(GeoOrientation.Right, GeoOrientation._DESERIALIZER.parse(alias));
4444
});
4545
}
46+
47+
@Test
48+
public void testBooleanEnum() {
49+
// Quoted value
50+
assertEquals(Refresh.WaitFor, checkJsonRoundtrip(Refresh.WaitFor, "\"wait_for\""));
51+
52+
// Unquoted boolean values
53+
assertEquals(Refresh.True, checkJsonRoundtrip(Refresh.True, "true"));
54+
assertEquals(Refresh.False, checkJsonRoundtrip(Refresh.False, "false"));
55+
56+
// true/false as strings
57+
assertEquals(Refresh.True, fromJson("\"true\"", Refresh.class));
58+
assertEquals(Refresh.False, fromJson("\"false\"", Refresh.class));
59+
}
4660
}

0 commit comments

Comments
 (0)