From 9bd7d40edd3b828623b387fc30f7eb2aa1b48b3c Mon Sep 17 00:00:00 2001 From: Sylvain Wallez Date: Fri, 5 May 2023 20:53:34 +0200 Subject: [PATCH] Add buffered JsonData implementation for Jackson (#567) --- .../clients/json/BufferingJsonParser.java | 32 ++++++ .../co/elastic/clients/json/JsonBuffer.java | 33 ++++++ .../co/elastic/clients/json/JsonData.java | 17 ++- .../co/elastic/clients/json/JsonDataImpl.java | 10 -- .../co/elastic/clients/json/JsonpUtils.java | 7 ++ .../json/jackson/JacksonJsonBuffer.java | 102 ++++++++++++++++++ .../json/jackson/JacksonJsonProvider.java | 21 ++-- .../json/jackson/JacksonJsonpMapper.java | 7 +- .../json/jackson/JacksonJsonpParser.java | 41 +++++-- .../elasticsearch/model/ModelTestCase.java | 37 +++++-- .../co/elastic/clients/json/JsonDataTest.java | 71 +++++++++--- 11 files changed, 322 insertions(+), 56 deletions(-) create mode 100644 java-client/src/main/java/co/elastic/clients/json/BufferingJsonParser.java create mode 100644 java-client/src/main/java/co/elastic/clients/json/JsonBuffer.java create mode 100644 java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonBuffer.java diff --git a/java-client/src/main/java/co/elastic/clients/json/BufferingJsonParser.java b/java-client/src/main/java/co/elastic/clients/json/BufferingJsonParser.java new file mode 100644 index 000000000..fa90c879e --- /dev/null +++ b/java-client/src/main/java/co/elastic/clients/json/BufferingJsonParser.java @@ -0,0 +1,32 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package co.elastic.clients.json; + +import jakarta.json.stream.JsonParser; + +public interface BufferingJsonParser extends JsonParser { + + /** + * Get the value at the current parser position as a JsonData object. + * @return + */ + JsonData getJsonData(); + +} diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonBuffer.java b/java-client/src/main/java/co/elastic/clients/json/JsonBuffer.java new file mode 100644 index 000000000..d813697aa --- /dev/null +++ b/java-client/src/main/java/co/elastic/clients/json/JsonBuffer.java @@ -0,0 +1,33 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package co.elastic.clients.json; + +import jakarta.json.stream.JsonParser; + +/** + * A buffer of JSON events. + */ +public interface JsonBuffer { + + /** + * Get the contents of this buffer as a JSON parser. Can be called multiple times. + */ + JsonParser asParser(); +} diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonData.java b/java-client/src/main/java/co/elastic/clients/json/JsonData.java index 1016b9ffd..5680a2d93 100644 --- a/java-client/src/main/java/co/elastic/clients/json/JsonData.java +++ b/java-client/src/main/java/co/elastic/clients/json/JsonData.java @@ -58,7 +58,9 @@ public interface JsonData extends JsonpSerializable { * * @throws IllegalStateException if no mapper was provided at creation time. */ - T to(Class clazz); + default T to(Class clazz) { + return to((Type)clazz); + } /** * Converts this object to a target type. A mapper must have been provided at creation time. @@ -70,7 +72,9 @@ public interface JsonData extends JsonpSerializable { /** * Converts this object to a target class. */ - T to(Class clazz, JsonpMapper mapper); + default T to(Class clazz, JsonpMapper mapper) { + return to((Type)clazz, mapper); + } /** * Converts this object to a target type. @@ -145,8 +149,7 @@ static JsonData from(InputStream json) { * {@link #deserialize(JsonpDeserializer)}. */ static JsonData from(JsonParser parser, JsonpMapper mapper) { - parser.next(); // Need to be at the beginning of the value to read - return of(parser.getValue(), mapper); + return from(parser, mapper, parser.next()); } /** @@ -155,7 +158,11 @@ static JsonData from(JsonParser parser, JsonpMapper mapper) { * {@link #deserialize(JsonpDeserializer)}. */ static JsonData from(JsonParser parser, JsonpMapper mapper, JsonParser.Event event) { - return of(parser.getValue(), mapper); + if (parser instanceof BufferingJsonParser) { + return ((BufferingJsonParser)parser).getJsonData(); + } else { + return of(parser.getValue(), mapper); + } } JsonpDeserializer _DESERIALIZER = JsonpDeserializer.of( diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonDataImpl.java b/java-client/src/main/java/co/elastic/clients/json/JsonDataImpl.java index 0697fb3d7..e063e2974 100644 --- a/java-client/src/main/java/co/elastic/clients/json/JsonDataImpl.java +++ b/java-client/src/main/java/co/elastic/clients/json/JsonDataImpl.java @@ -64,21 +64,11 @@ public JsonValue toJson(JsonpMapper mapper) { return parser.getValue(); } - @Override - public T to(Class clazz) { - return to((Type)clazz, null); - } - @Override public T to(Type clazz) { return to(clazz, null); } - @Override - public T to(Class clazz, JsonpMapper mapper) { - return to((Type)clazz, mapper); - } - @Override public T to(Type type, JsonpMapper mapper) { if (type instanceof Class && ((Class)type).isAssignableFrom(value.getClass())) { diff --git a/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java b/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java index a8449b870..7975c0c6b 100644 --- a/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java +++ b/java-client/src/main/java/co/elastic/clients/json/JsonpUtils.java @@ -150,6 +150,13 @@ public static void skipValue(JsonParser parser, Event event) { } } + /** + * Copy the JSON value at the current parser location to a JSON generator. + */ + public static void copy(JsonParser parser, JsonGenerator generator) { + copy(parser, generator, parser.next()); + } + /** * Copy the JSON value at the current parser location to a JSON generator. */ diff --git a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonBuffer.java b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonBuffer.java new file mode 100644 index 000000000..c6656937e --- /dev/null +++ b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonBuffer.java @@ -0,0 +1,102 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package co.elastic.clients.json.jackson; + +import co.elastic.clients.json.JsonBuffer; +import co.elastic.clients.json.JsonData; +import co.elastic.clients.json.JsonpDeserializer; +import co.elastic.clients.json.JsonpMapper; +import co.elastic.clients.json.JsonpUtils; +import com.fasterxml.jackson.databind.util.TokenBuffer; +import jakarta.json.JsonValue; +import jakarta.json.stream.JsonGenerator; +import jakarta.json.stream.JsonParser; + +import java.io.IOException; +import java.lang.reflect.Type; + +class JacksonJsonBuffer implements JsonBuffer, JsonData { + private final TokenBuffer buffer; + private final JacksonJsonpMapper mapper; + + JacksonJsonBuffer(TokenBuffer buffer, JacksonJsonpMapper mapper) { + this.buffer = buffer; + this.mapper = mapper; + } + + @Override + public JsonParser asParser() { + return new JacksonJsonpParser(buffer.asParser(), mapper); + } + + @Override + public JsonValue toJson() { + try (JsonParser parser = asParser()) { + parser.next(); // move to first event + return parser.getValue(); + } + } + + @Override + public JsonValue toJson(JsonpMapper mapper) { + // We don't need the mapper + return toJson(); + } + + @Override + public T to(Type type) { + return to(type, this.mapper); + } + + @Override + public T to(Type type, JsonpMapper mapper) { + try (JsonParser parser = asParser()) { + return mapper.deserialize(parser, type); + } + } + + @Override + public T deserialize(JsonpDeserializer deserializer) { + return deserialize(deserializer, this.mapper); + } + + @Override + public T deserialize(JsonpDeserializer deserializer, JsonpMapper mapper) { + try (JsonParser parser = asParser()) { + return deserializer.deserialize(parser, mapper); + } + } + + @Override + public void serialize(JsonGenerator generator, JsonpMapper mapper) { + if (generator instanceof JacksonJsonpGenerator) { + JacksonJsonpGenerator jkGenerator = (JacksonJsonpGenerator) generator; + try { + buffer.serialize(jkGenerator.jacksonGenerator()); + } catch (IOException e) { + throw JacksonUtils.convertException(e); + } + } else { + try (JsonParser parser = asParser()) { + JsonpUtils.copy(parser, generator); + } + } + } +} diff --git a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonProvider.java b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonProvider.java index e919ab726..37590afb6 100644 --- a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonProvider.java +++ b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonProvider.java @@ -52,21 +52,20 @@ */ public class JacksonJsonProvider extends JsonProvider { + private final JacksonJsonpMapper mapper; private final JsonFactory jsonFactory; - public JacksonJsonProvider(JsonFactory jsonFactory) { - this.jsonFactory = jsonFactory; + public JacksonJsonProvider(JacksonJsonpMapper mapper) { + this.mapper = mapper; + this.jsonFactory = mapper.objectMapper().getFactory(); } public JacksonJsonProvider() { - this(new JsonFactory()); + this(new JacksonJsonpMapper()); } - /** - * Return the underlying Jackson {@link JsonFactory}. - */ - public JsonFactory jacksonJsonFactory() { - return this.jsonFactory; + public JacksonJsonpMapper mapper() { + return this.mapper; } //--------------------------------------------------------------------------------------------- @@ -105,7 +104,7 @@ private class ParserFactory implements JsonParserFactory { @Override public JsonParser createParser(Reader reader) { try { - return new JacksonJsonpParser(jsonFactory.createParser(reader)); + return new JacksonJsonpParser(jsonFactory.createParser(reader), mapper); } catch (IOException ioe) { throw JacksonUtils.convertException(ioe); } @@ -114,7 +113,7 @@ public JsonParser createParser(Reader reader) { @Override public JsonParser createParser(InputStream in) { try { - return new JacksonJsonpParser(jsonFactory.createParser(in)); + return new JacksonJsonpParser(jsonFactory.createParser(in), mapper); } catch (IOException ioe) { throw JacksonUtils.convertException(ioe); } @@ -123,7 +122,7 @@ public JsonParser createParser(InputStream in) { @Override public JsonParser createParser(InputStream in, Charset charset) { try { - return new JacksonJsonpParser(jsonFactory.createParser(new InputStreamReader(in, charset))); + return new JacksonJsonpParser(jsonFactory.createParser(new InputStreamReader(in, charset)), mapper); } catch (IOException ioe) { throw JacksonUtils.convertException(ioe); } diff --git a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpMapper.java b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpMapper.java index ffa352240..6df9c6c85 100644 --- a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpMapper.java +++ b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpMapper.java @@ -46,10 +46,9 @@ private JacksonJsonpMapper(ObjectMapper objectMapper, JacksonJsonProvider provid } public JacksonJsonpMapper(ObjectMapper objectMapper) { - this(objectMapper, - // Creating the json factory from the mapper ensures it will be returned by JsonParser.getCodec() - new JacksonJsonProvider(objectMapper.getFactory()) - ); + this.objectMapper = objectMapper; + // Order is important as JacksonJsonProvider(this) will get ObjectMapper + this.provider = new JacksonJsonProvider(this); } public JacksonJsonpMapper() { diff --git a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpParser.java b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpParser.java index 4ce1778d6..22c841a26 100644 --- a/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpParser.java +++ b/java-client/src/main/java/co/elastic/clients/json/jackson/JacksonJsonpParser.java @@ -19,6 +19,8 @@ package co.elastic.clients.json.jackson; +import co.elastic.clients.json.BufferingJsonParser; +import co.elastic.clients.json.JsonData; import co.elastic.clients.json.LookAheadJsonParser; import co.elastic.clients.json.UnexpectedJsonEventException; import com.fasterxml.jackson.core.JsonToken; @@ -47,9 +49,10 @@ * getter method (e.g. {@link #getInt()} or {@link #getString()} should be called until the next call to {@link #next()}. * Such calls will throw an {@code IllegalStateException}. */ -public class JacksonJsonpParser implements LookAheadJsonParser { +public class JacksonJsonpParser implements LookAheadJsonParser, BufferingJsonParser { private final com.fasterxml.jackson.core.JsonParser parser; + private final JacksonJsonpMapper mapper; private boolean hasNextWasCalled = false; @@ -74,8 +77,9 @@ public class JacksonJsonpParser implements LookAheadJsonParser { // - NOT_AVAILABLE } - public JacksonJsonpParser(com.fasterxml.jackson.core.JsonParser parser) { + public JacksonJsonpParser(com.fasterxml.jackson.core.JsonParser parser, JacksonJsonpMapper mapper) { this.parser = parser; + this.mapper = mapper; } /** @@ -337,7 +341,10 @@ public Map.Entry lookAheadFieldValue(String name, String def return new AbstractMap.SimpleImmutableEntry<>( parser.getText(), - new JacksonJsonpParser(JsonParserSequence.createFlattened(false, tb.asParser(), parser)) + new JacksonJsonpParser( + JsonParserSequence.createFlattened(false, tb.asParser(), parser), + mapper + ) ); } else { tb.copyCurrentStructure(parser); @@ -352,7 +359,10 @@ public Map.Entry lookAheadFieldValue(String name, String def // Field not found return new AbstractMap.SimpleImmutableEntry<>( defaultValue, - new JacksonJsonpParser(JsonParserSequence.createFlattened(false, tb.asParser(), parser)) + new JacksonJsonpParser( + JsonParserSequence.createFlattened(false, tb.asParser(), parser), + mapper + ) ); } @@ -374,7 +384,10 @@ public Map.Entry findVariant(Map tb.copyCurrentEvent(parser); return new AbstractMap.SimpleImmutableEntry<>( variant, - new JacksonJsonpParser(JsonParserSequence.createFlattened(false, tb.asParser(), parser)) + new JacksonJsonpParser( + JsonParserSequence.createFlattened(false, tb.asParser(), parser), + mapper + ) ); } else { tb.copyCurrentStructure(parser); @@ -389,7 +402,10 @@ public Map.Entry findVariant(Map // No variant found: return the buffered parser and let the caller decide what to do. return new AbstractMap.SimpleImmutableEntry<>( null, - new JacksonJsonpParser(JsonParserSequence.createFlattened(false, tb.asParser(), parser)) + new JacksonJsonpParser( + JsonParserSequence.createFlattened(false, tb.asParser(), parser), + mapper + ) ); } @@ -406,5 +422,18 @@ private void expectEvent(JsonToken expected) { throw new UnexpectedJsonEventException(this, tokenToEvent.get(event), tokenToEvent.get(expected)); } } + + //----- Buffering methods + + @Override + public JsonData getJsonData() { + try { + TokenBuffer buffer = new TokenBuffer(parser); + buffer.copyCurrentStructure(parser); + return new JacksonJsonBuffer(buffer, mapper); + } catch (IOException e) { + throw JacksonUtils.convertException(e); + } + } } diff --git a/java-client/src/test/java/co/elastic/clients/elasticsearch/model/ModelTestCase.java b/java-client/src/test/java/co/elastic/clients/elasticsearch/model/ModelTestCase.java index f8e10a643..797350741 100644 --- a/java-client/src/test/java/co/elastic/clients/elasticsearch/model/ModelTestCase.java +++ b/java-client/src/test/java/co/elastic/clients/elasticsearch/model/ModelTestCase.java @@ -33,6 +33,7 @@ import java.io.StringWriter; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.EnumSet; import java.util.Random; /** @@ -40,15 +41,22 @@ */ public abstract class ModelTestCase extends Assertions { + protected enum JsonImpl { Jsonb, Jackson, Simple }; + // Same value for all tests in a test run private static final int RAND = new Random().nextInt(100); + protected final JsonImpl jsonImpl; protected final JsonpMapper mapper; - private JsonpMapper setupMapper(int rand) { - // Randomly choose json-b or jackson - switch(rand % 3) { - case 0: + private static JsonImpl chooseJsonImpl(EnumSet jsonImplCandidates, int rand) { + // Converting an EnumSet to an array always uses the same order. + return jsonImplCandidates.toArray(new JsonImpl[jsonImplCandidates.size()])[rand % jsonImplCandidates.size()]; + } + + private static JsonpMapper createMapper(JsonImpl jsonImpl, int rand) { + switch(jsonImpl) { + case Jsonb: System.out.println("Using a JsonB mapper (rand = " + rand + ")."); return new JsonbJsonpMapper() { @Override @@ -57,7 +65,7 @@ public boolean ignoreUnknownFields() { } }; - case 1: + case Jackson: System.out.println("Using a Jackson mapper (rand = " + rand + ")."); return new JacksonJsonpMapper() { @Override @@ -72,12 +80,25 @@ public boolean ignoreUnknownFields() { } } - protected ModelTestCase() { - this(RAND); + protected ModelTestCase(EnumSet jsonImplCandidates, int rand) { + jsonImpl = chooseJsonImpl(jsonImplCandidates, rand); + mapper = createMapper(jsonImpl, rand); + } + + protected ModelTestCase(EnumSet jsonImplCandidates) { + this(jsonImplCandidates, RAND); + } + + protected ModelTestCase(JsonImpl jsonImpl) { + this(EnumSet.of(jsonImpl), RAND); } protected ModelTestCase(int rand) { - mapper = setupMapper(rand); + this(EnumSet.allOf(JsonImpl.class), rand); + } + + protected ModelTestCase() { + this(EnumSet.allOf(JsonImpl.class), RAND); } protected String toJson(T value) { diff --git a/java-client/src/test/java/co/elastic/clients/json/JsonDataTest.java b/java-client/src/test/java/co/elastic/clients/json/JsonDataTest.java index 74effed44..d6204cc35 100644 --- a/java-client/src/test/java/co/elastic/clients/json/JsonDataTest.java +++ b/java-client/src/test/java/co/elastic/clients/json/JsonDataTest.java @@ -19,28 +19,26 @@ package co.elastic.clients.json; -import co.elastic.clients.elasticsearch.ElasticsearchClient; +import co.elastic.clients.elasticsearch.core.search.Hit; import co.elastic.clients.elasticsearch.indices.CreateIndexRequest; +import co.elastic.clients.elasticsearch.model.ModelTestCase; import co.elastic.clients.json.jackson.JacksonJsonpMapper; -import co.elastic.clients.json.jsonb.JsonbJsonpMapper; import co.elastic.clients.util.ObjectBuilder; import jakarta.json.JsonString; import jakarta.json.JsonValue; import jakarta.json.stream.JsonGenerator; import jakarta.json.stream.JsonParser; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; -public class JsonDataTest extends Assertions { +public class JsonDataTest extends ModelTestCase { - - public static > B withJson(B builder, Reader json, ElasticsearchClient client) { - return withJson(builder, json, client._transport().jsonpMapper()); - } +// public JsonDataTest() { +// super(JsonImpl.Jackson); +// } public static > B withJson(B builder, Reader json, JsonpMapper mapper) { JsonpDeserializer classDeser = JsonpMapperBase.findDeserializer(builder.getClass().getEnclosingClass()); @@ -69,13 +67,17 @@ public void testBuilderDeserializerHack() { @Test public void testParsing() { - JsonpMapper mapper = new JsonbJsonpMapper(); + if (jsonImpl == JsonImpl.Simple) { + return; // Doesn't support user-defined object mapping + } + String json = "{\"children\":[{\"doubleValue\":3.2,\"intValue\":2}],\"doubleValue\":2.1,\"intValue\":1," + "\"stringValue\":\"foo\"}"; JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json)); JsonData data = JsonData.from(parser, mapper); + checkClass(data); assertEquals("foo", data.toJson().asJsonObject().getString("stringValue")); JsonpMapperTest.SomeClass to = data.to(JsonpMapperTest.SomeClass.class); @@ -83,9 +85,11 @@ public void testParsing() { } @Test - public void testSerialize() { + public void testSerializeObject() { + if (jsonImpl == JsonImpl.Simple) { + return; // Doesn't support user-defined object mapping + } - JsonpMapper mapper = new JsonbJsonpMapper(); String json = "{\"children\":[{\"doubleValue\":3.2,\"intValue\":2}],\"doubleValue\":2.1,\"intValue\":1," + "\"stringValue\":\"foo\"}"; @@ -109,14 +113,57 @@ public void testSerialize() { assertEquals(json, sw.toString()); } + @Test + public void testSerializeValueOrBuffer() { + String json = "{\"children\":[{\"doubleValue\":3.2,\"intValue\":2}],\"doubleValue\":2.1,\"intValue\":1," + + "\"stringValue\":\"foo\"}"; + + JsonParser parser = mapper.jsonProvider().createParser(new StringReader(json)); + + JsonData data = JsonData.from(parser, mapper); + checkClass(data); + + assertEquals(json, toJson(data, mapper)); + } + @Test public void testConvert() { JsonData json = JsonData.of("foo"); - final JsonValue value = json.toJson(new JsonbJsonpMapper()); + final JsonValue value = json.toJson(mapper); assertEquals(JsonValue.ValueType.STRING, value.getValueType()); assertEquals("foo", ((JsonString)value).getString()); } + + @Test + public void testFieldValues() { + // Specific test for https://github.com/elastic/elasticsearch-java/issues/548 which led to buffered JsonData + + String json = "{\"_index\":\"idx\",\"_id\":\"doc_id\",\"fields\":{\"bar\":\"Bar value\",\"foo\":1}}"; + + Hit hit = fromJson(json, Hit.createHitDeserializer(JsonpDeserializer.voidDeserializer())); + + assertEquals(1, hit.fields().get("foo").to(Integer.class)); + assertEquals("Bar value", hit.fields().get("bar").to(String.class)); + + checkClass(hit.fields().get("foo")); + checkClass(hit.fields().get("bar")); + + assertEquals(json, toJson(hit)); + } + + private void checkClass(JsonData data) { + String name = data.getClass().getName(); + switch (jsonImpl) { + case Jackson: + assertEquals(name, "co.elastic.clients.json.jackson.JacksonJsonBuffer"); + break; + + case Jsonb: + case Simple: + assertEquals(name, "co.elastic.clients.json.JsonDataImpl"); + } + } }