From da6e90e427b5e85790c425b89eb43ace2fdd99b1 Mon Sep 17 00:00:00 2001 From: Sylvain Wallez Date: Tue, 3 May 2022 19:48:34 +0200 Subject: [PATCH] Handle enums that have true/false values as booleans (#275) --- .../clients/elasticsearch/_types/Refresh.java | 16 ++++++- .../_types/mapping/DynamicMapping.java | 15 ++++++- .../co/elastic/clients/json/JsonEnum.java | 45 ++++++++++++++++--- .../clients/elasticsearch/model/EnumTest.java | 18 +++++++- 4 files changed, 85 insertions(+), 9 deletions(-) diff --git a/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/Refresh.java b/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/Refresh.java index 6439caab1..99dccc0fc 100644 --- a/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/Refresh.java +++ b/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/Refresh.java @@ -26,6 +26,8 @@ import co.elastic.clients.json.JsonEnum; import co.elastic.clients.json.JsonpDeserializable; import co.elastic.clients.json.JsonpDeserializer; +import co.elastic.clients.json.JsonpMapper; +import jakarta.json.stream.JsonGenerator; /** * @@ -52,5 +54,17 @@ public String jsonValue() { return this.jsonValue; } - public static final JsonEnum.Deserializer _DESERIALIZER = new JsonEnum.Deserializer<>(Refresh.values()); + @Override + public void serialize(JsonGenerator generator, JsonpMapper params) { + if (this == Refresh.True) { + generator.write(true); + } else if (this == Refresh.False) { + generator.write(false); + } else { + generator.write(jsonValue()); + } + } + + public static final JsonEnum.Deserializer _DESERIALIZER = new JsonEnum.Deserializer.AllowingBooleans<>( + Refresh.values()); } diff --git a/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/mapping/DynamicMapping.java b/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/mapping/DynamicMapping.java index 2ca926aa6..fbbd17d2f 100644 --- a/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/mapping/DynamicMapping.java +++ b/java-client/src/main/java/co/elastic/clients/elasticsearch/_types/mapping/DynamicMapping.java @@ -26,6 +26,8 @@ import co.elastic.clients.json.JsonEnum; import co.elastic.clients.json.JsonpDeserializable; import co.elastic.clients.json.JsonpDeserializer; +import co.elastic.clients.json.JsonpMapper; +import jakarta.json.stream.JsonGenerator; /** * @@ -55,6 +57,17 @@ public String jsonValue() { return this.jsonValue; } - public static final JsonEnum.Deserializer _DESERIALIZER = new JsonEnum.Deserializer<>( + @Override + public void serialize(JsonGenerator generator, JsonpMapper params) { + if (this == DynamicMapping.True) { + generator.write(true); + } else if (this == DynamicMapping.False) { + generator.write(false); + } else { + generator.write(jsonValue()); + } + } + + public static final JsonEnum.Deserializer _DESERIALIZER = new JsonEnum.Deserializer.AllowingBooleans<>( DynamicMapping.values()); } diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonEnum.java b/java-client/src/main/java/co/elastic/clients/json/JsonEnum.java index 68d8073ff..d16c97eb1 100644 --- a/java-client/src/main/java/co/elastic/clients/json/JsonEnum.java +++ b/java-client/src/main/java/co/elastic/clients/json/JsonEnum.java @@ -29,6 +29,8 @@ import java.util.Map; import java.util.NoSuchElementException; +import static jakarta.json.stream.JsonParser.Event; + /** * Base interface for enumerations in API types. Members have a JSON representation and also accept * aliases when parsed from a string value. @@ -47,13 +49,18 @@ default void serialize(JsonGenerator generator, JsonpMapper params) { } class Deserializer extends JsonpDeserializerBase { + + private static final EnumSet acceptedEvents = EnumSet.of(Event.VALUE_STRING, Event.KEY_NAME); + private static final EnumSet nativeEvents = EnumSet.of(Event.VALUE_STRING); + private final Map lookupTable; public Deserializer(T[] values) { - super( - EnumSet.of(JsonParser.Event.VALUE_STRING, JsonParser.Event.KEY_NAME), - EnumSet.of(JsonParser.Event.VALUE_STRING) - ); + this(values, acceptedEvents); + } + + protected Deserializer(T[] values, EnumSet acceptedEvents) { + super(acceptedEvents, nativeEvents); // Use the same size calculation as in java.lang.Enum.enumConstantDirectory this.lookupTable = new HashMap<>((int)(values.length / 0.75f) + 1); @@ -69,7 +76,7 @@ public Deserializer(T[] values) { } @Override - public T deserialize(JsonParser parser, JsonpMapper mapper, JsonParser.Event event) { + public T deserialize(JsonParser parser, JsonpMapper mapper, Event event) { String value = parser.getString(); return deserialize(value, parser); } @@ -104,5 +111,33 @@ public T parse(String value) { } return result; } + + /** + * An enum deserializer that also accepts boolean values. Used for a few properties that started as two-state booleans + * and evolved into enums over time. + */ + public static class AllowingBooleans extends Deserializer { + + private static final EnumSet acceptedEventsAndBoolean = + EnumSet.of(Event.VALUE_STRING, Event.KEY_NAME, Event.VALUE_TRUE, Event.VALUE_FALSE); + + public AllowingBooleans(T[] values) { + super(values, acceptedEventsAndBoolean); + } + + @Override + public T deserialize(JsonParser parser, JsonpMapper mapper, Event event) { + String value; + if (event == Event.VALUE_TRUE) { + value = "true"; + } else if (event == Event.VALUE_FALSE) { + value = "false"; + } else { + value = parser.getString(); + } + + return deserialize(value, parser); + } + } } } diff --git a/java-client/src/test/java/co/elastic/clients/elasticsearch/model/EnumTest.java b/java-client/src/test/java/co/elastic/clients/elasticsearch/model/EnumTest.java index f02ebd2b2..a6f5cf4f4 100644 --- a/java-client/src/test/java/co/elastic/clients/elasticsearch/model/EnumTest.java +++ b/java-client/src/test/java/co/elastic/clients/elasticsearch/model/EnumTest.java @@ -20,13 +20,13 @@ package co.elastic.clients.elasticsearch.model; import co.elastic.clients.elasticsearch._types.Bytes; +import co.elastic.clients.elasticsearch._types.Refresh; import co.elastic.clients.elasticsearch._types.mapping.GeoOrientation; -import org.junit.Assert; import org.junit.Test; import java.util.Arrays; -public class EnumTest extends Assert { +public class EnumTest extends ModelTestCase { @Test public void testSimpleEnum() { @@ -43,4 +43,18 @@ public void testEnumWithAliases() { assertEquals(GeoOrientation.Right, GeoOrientation._DESERIALIZER.parse(alias)); }); } + + @Test + public void testBooleanEnum() { + // Quoted value + assertEquals(Refresh.WaitFor, checkJsonRoundtrip(Refresh.WaitFor, "\"wait_for\"")); + + // Unquoted boolean values + assertEquals(Refresh.True, checkJsonRoundtrip(Refresh.True, "true")); + assertEquals(Refresh.False, checkJsonRoundtrip(Refresh.False, "false")); + + // true/false as strings + assertEquals(Refresh.True, fromJson("\"true\"", Refresh.class)); + assertEquals(Refresh.False, fromJson("\"false\"", Refresh.class)); + } }