ServiceStack.Java UUID/Guid conversion/inversion

We’re working with an API that has a lot of Guids, and using ServiceStack.Java and the Android Client.

Here’s an example of the type of issue we’re seeing with Guids:

We call a service that gives us a a list of members:

Sample response

{"members":[{"id":"4f5e73f72bb2492b9ffa7b12d55111f3", ... }],"pageIndex":0,"pageSize":250,"pageCount":1,"itemCount":1}

But in Android Client, when we do “response.getMembers().getId()”, it says: f7735e4f-b22b-2b49-9ffa-7b12d55111f3

Only the last 16 characters seem to be correct, the 1st 16 have some odd inversions …

Environment:

  1. net.servicestack:android:1.0.12
  2. emulator nexus 5 api 21

As a follow up, if this is by design, what is the recommended approach.

We use IDs extensively across systems, and often as a way to create/format “key” strings, like for naming files, or in NoSQL keys, etc…) So having a UUID stored outside of the ServiceStack context that doesn’t map to it’s original Guid without using ServiceStack to/from string utility methods, can become a bit of an issue.

Can we make UUIDs match up with their equivalent Guid? or do we have to use Utils.toGuidString and Utils.fromGuidString? If we use those methods it works (see: https://ideone.com/mk5H4V), but then we have a dependency on ServiceStack to work with UUIDs that might need to be used outside of a ServiceStack serialization context.

OR

Can we inject our own custom serializer UUID/string/Guid type serializer into the android/java client, would that be the right approach?

The GUID byte[] doesn’t map cleanly to Java UUID bytes, marc refers to GUID’s byte[] behavior as “crazy endianness”, I believe the Java client is using this implementation to covert a GUID’s bytes into a Java UUID.

But you should be able to easily override serialization/deserialization of GUID data types by just getting the JsonServiceClient to use a custom Gson instance configured with custom Type serializers, this is the default configuration for JsonServiceClient Gson instance:

public GsonBuilder getGsonBuilder() {
  return new GsonBuilder()
  .registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer())
  .registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer())
  .registerTypeAdapter(TimeSpan.class,JsonSerializer.getTimeSerializer())
  .registerTypeAdapter(TimeSpan.class,JsonSerializer.getTimeDeserializer())
  .registerTypeAdapter(UUID.class, JsonSerializers.getGuidSerializer())
  .registerTypeAdapter(UUID.class, JsonSerializers.getGuidDeserializer());
}

public Gson getGson() {
    if (gson == null) {
        gson = getGsonBuilder().create();
    }
    return gson;
}

Which you could change by registering your own Gson instance, e.g:

Gson customGson = new GsonBuilder()
.registerTypeAdapter(Date.class, JsonSerializers.getDateSerializer())
.registerTypeAdapter(Date.class, JsonSerializers.getDateDeserializer())
.registerTypeAdapter(TimeSpan.class,JsonSerializer.getTimeSpanSerializer())
.registerTypeAdapter(TimeSpan.class,JsonSerializer.getTimeSpanDeserializer())
.registerTypeAdapter(UUID.class, Custom.getGuidSerializer())
.registerTypeAdapter(UUID.class, Custom.getGuidDeserializer())
.create();

And initialize the Service Client to use it, i.e:

client.setGson(customGson);

Although if you are overriding it, I’d be interested into knowing what you’re using instead.

Thanks for the explanation, I will let you know how we move forward if we decide to override the serialization, but I’m not sure I want to tackle that :blush: . I imagine we will just isolate our usage of UUIDs internally to the app(s) where we work with .NET Guid DTO properties in Java and use the ServiceStack Utils methods to store the Guid properties as strings so that when we communicate with other systems that need these IDs, we are just referring to them in their String format which would then always be correct …

It would almost make sense I think to provide an “option” to create the Java DTOs with String properties instead of UUID (maybe make it an option inside the AppHost config on the server, options to override defaults for the AddReference services types/java, types/swift, etc… ). :smile: Because we are just using http(s), the server wouldn’t know the difference and the Java client would work fine then for us without UUIDs, and that would mitigate the risks of bad casting somewhere.

FYI I just added this option in this commit which will let you change which Value Types should be emitted as strings in the generated models by commenting out this option:

/* Options:
...
TreatTypesAsStrings: Guid

*/

Which will emit String data types for Guid properties, deserializing .NET Guid’s as strings.

This change is available from v4.0.43+ that’s now available on MyGet.

1 Like

Very cool! Thanks! The Utils methods work, but this is even better for our situation!