Java convert Fauna Time to Java 'Date' types

Hi,

I have a collection where the documents contain a Time value in them such as the following simplified document:

{
  "ref": Ref(Collection("dateexamples"), "101"),
  "ts": 1646429154220000,
  "data": {
    "creationDate": Time("2022-03-04T21:25:54.106843Z")
  }
}

And I have a Java object that the data and specifically the creationDate should be transformed into as follows (without the usual boilerplate):

public class DateExample {

    private ZonedDateTime creationDate;

}

So when I do something like (abbreviated for readability)

Value result = client.query( ... ).get();
DateExample dateExample = result.to(DateExample.class).get();

I would expect the Fauna Time to be converted to a ZonedDateTime however this doesn’t work; in fact I have been through the different Java Date like classes and have found the following:

Library Class Result
Core Java java.time.ZonedDateTime com.faunadb.client.errors.FaunaException: No suitable constructor or factory method found for type java.time.ZonedDateTime. Ensure that a factory method or constructor is annotated with @FaunaConstructor at com.faunadb.client.types.Constructors.createDecoder(Constructors.java:37)
Core Java java.time.LocalDateTime com.faunadb.client.errors.FaunaException: No suitable constructor or factory method found for type java.time.LocalDateTime. Ensure that a factory method or constructor is annotated with @FaunaConstructor at com.faunadb.client.types.Constructors.createDecoder(Constructors.java:37)
Core Java java.util.GregorianCalendar java.lang.ClassCastException: class com.faunadb.client.types.Value$TimeV cannot be cast to class com.faunadb.client.types.Value$ObjectV (com.faunadb.client.types.Value$TimeV and com.faunadb.client.types.Value$ObjectV are in unnamed module of loader 'app') at com.faunadb.client.types.Constructors$AbstractConstructorDecoder.apply(Constructors.java:144)
Core Java java.util.Date java.lang.ClassCastException: class com.faunadb.client.types.Value$TimeV cannot be cast to class com.faunadb.client.types.Value$ObjectV (com.faunadb.client.types.Value$TimeV and com.faunadb.client.types.Value$ObjectV are in unnamed module of loader 'app') at com.faunadb.client.types.Constructors$AbstractConstructorDecoder.apply(Constructors.java:144)
JodaTime org.joda.time.DateTime java.lang.ClassCastException: class com.faunadb.client.types.Value$TimeV cannot be cast to class com.faunadb.client.types.Value$ObjectV (com.faunadb.client.types.Value$TimeV and com.faunadb.client.types.Value$ObjectV are in unnamed module of loader 'app') at com.faunadb.client.types.Constructors$AbstractConstructorDecoder.apply(Constructors.java:144)

I think the native Java date type types should be supported out of the box (at least the java.time.* ones). However I would also be happy to write a converter (is this a Codec/Encoder/Decoder?) and register them with the Fauna Java driver but I can’t figure out how to accomplish this.

So I guess the questions are:
Am I missing something and the above types should work with the correct configuration?
If not:
How can I register some kind of custom converter with the Fauna driver?
Could the Jackson De/Serialisers help?

Any help/pointers would be appreciated. Thanks in advance.

I’m not a Java expert, so I asked one of our engineers for help in answering your question.

Here’s an example that demonstrates how to make it work.

For your DateExample class, define is as follows:

package example;

import java.time.Instant;
import com.faunadb.client.types.FaunaField;

public class DateExample {
    @FaunaField private Instant creationDate;

    @Override public String toString() {
      return "DateExample: " + this.creationDate.toString();
    }
}

Fauna uses java.time.Instant internally, so this is the ideal class to base your own date values upon.

For Fauna response fields that need to be mapped to native class fields, annotate them with @FaunaField. That assists with the type conversion.

In your main client code:

        Value result = client.query(
            Obj("data", Obj("creationDate", Now()))
        ).get();
        System.out.println(result);

        DateExample dateExample = result.at("data").to(DateExample.class).get();
        System.out.println(dateExample);

By asking for an object in the response, result.at() can target a specific value. Since the name used in the object matches the name in your DateExample class, the appropriate value is fetched and assigned.

When this code is executed, the output is:

{data: {creationDate: 2022-05-12T17:49:24.765Z}}
DateExample: 2022-05-12T17:49:24.765Z

You would have to do a bit more work to convert the timestamp into a date-only value:

package example;

import java.time.*;
import java.time.format.*;
import com.faunadb.client.types.FaunaField;

public class DateExample {
    @FaunaField private Instant creationDate;

    @Override public String toString() {
        return "DateExample: " +
            DateTimeFormatter.ofPattern("yyyy-MM-dd")
                .withZone(ZoneId.of("UTC"))
                .format(this.creationDate);
    }
}

With those changes, the output is:

{data: {creationDate: 2022-05-12T17:52:42.100Z}}
DateExample: 2022-05-12

I hope that helps!

1 Like

That’s perfect thank you

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.