Search code examples
serializationgsonjest-client

Gson custom deserializer for DateTime


I have a JestClient (elasticsearch) response that I'm trying to deserialize into an object. The object contains two DateTime fields, whereas in the response, they're strings, so I'm getting:

com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 102 path $.createdTimeStamp
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:226) ~[gson-2.8.5.jar:?]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:131) ~[gson-2.8.5.jar:?]
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:222) ~[gson-2.8.5.jar:?]
    at com.google.gson.Gson.fromJson(Gson.java:927) ~[gson-2.8.5.jar:?]
    at com.google.gson.Gson.fromJson(Gson.java:892) ~[gson-2.8.5.jar:?]
    at com.google.gson.Gson.fromJson(Gson.java:841) ~[gson-2.8.5.jar:?]
    at com.google.gson.Gson.fromJson(Gson.java:813) ~[gson-2.8.5.jar:?]
    at io.searchbox.client.JestResult.createSourceObject(JestResult.java:271) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.access$000(SearchResult.java:17) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult$Hit.<init>(SearchResult.java:288) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.extractHit(SearchResult.java:163) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.getHits(SearchResult.java:92) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.getHits(SearchResult.java:73) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.getHits(SearchResult.java:65) ~[Jest-6.x.jar:?]
    at io.searchbox.core.SearchResult.getHits(SearchResult.java:61) ~[Jest-6.x.jar:?]

So, I have created a custom deserializer to solve this.. However, whatever I do, I keep getting the same error. Somehow it's not registering to use it?

public final class DateTimeConverter extends TypeAdapter<DateTime> {

    @Override
    public void write(JsonWriter jsonWriter, DateTime dateTime) throws IOException {
        if (Objects.isNull(dateTime)) {
            jsonWriter.nullValue();
            return;
        }
        jsonWriter.value(dateTime.toString());
    }

    @Override
    public DateTime read(JsonReader jsonReader) throws IOException {
        System.out.println("This statement doesn't print, so I'm assuming this method isn't being used during parsing");
        String dateTimeString = jsonReader.nextString();
        return DateTime.parse(dateTimeString);
    }
}

I'm also setting my typeAdapter when initializing my client:

    public JestClient getElasticsearchJestClient(@NonNull final AWSCredentialsProvider awsCredentialsProvider, @NonNull final Regions region) {
        Gson gson = new GsonBuilder().registerTypeAdapter(DateTime.class, new DateTimeConverter()).create();
        AESClientFactory factory = new AESClientFactory(awsCredentialsProvider, region.getName());
        factory.setHttpClientConfig(new HttpClientConfig.Builder(ENDPOINT)
                .multiThreaded(true)
                .gson(gson).build());
        return factory.getObject();
    }

And finally, the code where I'm trying to parse the response from jestclient:

  List<SearchResult.Hit<MyObject, Void>> hits;
  SearchResult result = elasticsearchAccessor.getElasticsearchRecords(search);
  hits = result.getHits(MyObject.class);
  final List<MyObject> objects = hits.stream()
       .map((hit) -> hit.source)
       .collect(Collectors.toList());

No matter what I try I keep getting the error above, I'm not even sure at this point what to investigate-- any ideas are appreciated, I'm not sure what else to try.


Solution

  • This implementation ended up being correct. The reason it wasn't working in my tests was because I needed to add the adapter to the Gson I was initializing:

        private static final Gson GSON = new GsonBuilder().registerTypeAdapter(ZonedDateTime.class, new DateTimeConverter()).create();