Skip to content

Commit c057764

Browse files
committed
add Gson type adapters
[Closes #3]
1 parent 9323e24 commit c057764

File tree

8 files changed

+224
-0
lines changed

8 files changed

+224
-0
lines changed

gradle/libs.versions.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ uuidGenerator = { module = "com.fasterxml.uuid:java-uuid-generator", version = "
1010
jetbrains-annotations = { module = "org.jetbrains:annotations", version = "26.0.2" }
1111
jackson-databind = { group = "com.fasterxml.jackson.core", name = "jackson-databind", version.ref = "jackson" }
1212
jackson-annotations = { group = "com.fasterxml.jackson.core", name = "jackson-annotations", version.ref = "jackson" }
13+
gson = { module = "com.google.code.gson:gson", version = "2.10.1" }
1314
autoService-processor = { group = "com.google.auto.service", name = "auto-service", version.ref = "googleAutoService" }
1415
autoService-annotations = { group = "com.google.auto.service", name = "auto-service-annotations", version.ref = "googleAutoService" }
1516
errorprone-annotations = { group = "com.google.errorprone", name = "error_prone_annotations", version.ref = "errorProne" }

modules/typed-ids/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ dependencies {
1414
annotationProcessor(libs.autoService.processor)
1515

1616
compileOnly(libs.jackson.databind)
17+
compileOnly(libs.gson)
1718
compileOnly(libs.kotlinx.serialization)
1819

1920
testImplementation(project(":typed-ids-testing"))
2021
testImplementation(libs.jackson.databind)
22+
testImplementation(libs.gson)
2123
testImplementation(libs.kotlinx.serialization)
2224
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
2325
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.framefork.typedIds.bigint.json.gson;
2+
3+
import com.google.gson.TypeAdapter;
4+
import com.google.gson.stream.JsonReader;
5+
import com.google.gson.stream.JsonWriter;
6+
import org.framefork.typedIds.bigint.ObjectBigIntId;
7+
import org.framefork.typedIds.bigint.ObjectBigIntIdTypeUtils;
8+
import org.framefork.typedIds.common.ReflectionHacks;
9+
10+
import java.io.IOException;
11+
import java.lang.invoke.MethodHandle;
12+
13+
public class ObjectBigIntIdTypeAdapter<T extends ObjectBigIntId<T>> extends TypeAdapter<T>
14+
{
15+
16+
private final MethodHandle constructor;
17+
18+
public ObjectBigIntIdTypeAdapter(final Class<T> identifierClass)
19+
{
20+
if (!ObjectBigIntId.class.isAssignableFrom(identifierClass)) {
21+
throw new IllegalArgumentException("Type %s is not a subtype of %s".formatted(identifierClass, ObjectBigIntId.class));
22+
}
23+
24+
this.constructor = ReflectionHacks.getMainConstructor(identifierClass, long.class);
25+
}
26+
27+
@Override
28+
public void write(final JsonWriter writer, final T value) throws IOException
29+
{
30+
writer.jsonValue(String.valueOf(value.toLong()));
31+
}
32+
33+
@SuppressWarnings("unchecked")
34+
@Override
35+
public T read(final JsonReader in) throws IOException
36+
{
37+
var raw = in.nextLong();
38+
return (T) ObjectBigIntIdTypeUtils.wrapBigIntToIdentifier(raw, constructor);
39+
}
40+
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.framefork.typedIds.bigint.json.gson;
2+
3+
import com.google.auto.service.AutoService;
4+
import com.google.gson.Gson;
5+
import com.google.gson.TypeAdapter;
6+
import com.google.gson.TypeAdapterFactory;
7+
import com.google.gson.reflect.TypeToken;
8+
import org.framefork.typedIds.bigint.ObjectBigIntId;
9+
import org.framefork.typedIds.bigint.ObjectBigIntIdTypeUtils;
10+
import org.jspecify.annotations.Nullable;
11+
12+
@SuppressWarnings("unchecked")
13+
@AutoService(TypeAdapterFactory.class)
14+
public class ObjectBigIntIdTypeAdapterFactory implements TypeAdapterFactory
15+
{
16+
17+
@Nullable
18+
@Override
19+
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken)
20+
{
21+
var rawType = (Class<T>) typeToken.getRawType();
22+
if (!ObjectBigIntIdTypeUtils.getObjectBigIntIdRawClass().isAssignableFrom(rawType)) {
23+
return null;
24+
}
25+
26+
return (TypeAdapter<T>) casted(rawType);
27+
}
28+
29+
private static <T extends ObjectBigIntId<T>> ObjectBigIntIdTypeAdapter<?> casted(final Class<?> rawType)
30+
{
31+
return new ObjectBigIntIdTypeAdapter<>((Class<T>) rawType);
32+
}
33+
34+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.framefork.typedIds.uuid.json.gson;
2+
3+
import com.google.gson.TypeAdapter;
4+
import com.google.gson.stream.JsonReader;
5+
import com.google.gson.stream.JsonWriter;
6+
import org.framefork.typedIds.common.ReflectionHacks;
7+
import org.framefork.typedIds.uuid.ObjectUuid;
8+
import org.framefork.typedIds.uuid.ObjectUuidTypeUtils;
9+
10+
import java.io.IOException;
11+
import java.lang.invoke.MethodHandle;
12+
import java.util.UUID;
13+
14+
public class ObjectUuidTypeAdapter<T extends ObjectUuid<T>> extends TypeAdapter<T>
15+
{
16+
17+
private final MethodHandle constructor;
18+
19+
public ObjectUuidTypeAdapter(final Class<T> identifierClass)
20+
{
21+
if (!ObjectUuid.class.isAssignableFrom(identifierClass)) {
22+
throw new IllegalArgumentException("Type %s is not a subtype of %s".formatted(identifierClass, ObjectUuid.class));
23+
}
24+
25+
this.constructor = ReflectionHacks.getMainConstructor(identifierClass, UUID.class);
26+
}
27+
28+
@Override
29+
public void write(final JsonWriter writer, final T value) throws IOException
30+
{
31+
writer.value(value.toNativeUuid().toString());
32+
}
33+
34+
@SuppressWarnings("unchecked")
35+
@Override
36+
public T read(final JsonReader in) throws IOException
37+
{
38+
var uuid = UUID.fromString(in.nextString());
39+
return (T) ObjectUuidTypeUtils.wrapUuidToIdentifier(uuid, constructor);
40+
}
41+
42+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package org.framefork.typedIds.uuid.json.gson;
2+
3+
import com.google.auto.service.AutoService;
4+
import com.google.gson.Gson;
5+
import com.google.gson.TypeAdapter;
6+
import com.google.gson.TypeAdapterFactory;
7+
import com.google.gson.reflect.TypeToken;
8+
import org.framefork.typedIds.uuid.ObjectUuid;
9+
import org.framefork.typedIds.uuid.ObjectUuidTypeUtils;
10+
import org.jspecify.annotations.Nullable;
11+
12+
@SuppressWarnings("unchecked")
13+
@AutoService(TypeAdapterFactory.class)
14+
public class ObjectUuidTypeAdapterFactory implements TypeAdapterFactory
15+
{
16+
17+
@Nullable
18+
@Override
19+
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken)
20+
{
21+
var rawType = (Class<T>) typeToken.getRawType();
22+
if (!ObjectUuidTypeUtils.getObjectUuidRawClass().isAssignableFrom(rawType)) {
23+
return null;
24+
}
25+
26+
return (TypeAdapter<T>) casted(rawType);
27+
}
28+
29+
private static <T extends ObjectUuid<T>> ObjectUuidTypeAdapter<?> casted(final Class<?> rawType)
30+
{
31+
return new ObjectUuidTypeAdapter<>((Class<T>) rawType);
32+
}
33+
34+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.framefork.typedIds.bigint.json.gson;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import org.framefork.typedIds.bigint.ObjectBigIntIdMock;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class ObjectBigIntIdGsonTest
11+
{
12+
13+
private final Gson gson = new GsonBuilder()
14+
.registerTypeAdapterFactory(new ObjectBigIntIdTypeAdapterFactory())
15+
.create();
16+
17+
@Test
18+
public void functional() throws Exception
19+
{
20+
var id42 = ObjectBigIntIdMock.from("42");
21+
var originalDto = new Dto(id42);
22+
23+
var dtoJson = gson.toJson(originalDto);
24+
assertThat(dtoJson).isEqualTo("{\"id\":42}");
25+
26+
var deserializedDto = gson.fromJson(dtoJson, Dto.class);
27+
assertThat(deserializedDto).isEqualTo(originalDto);
28+
}
29+
30+
record Dto(ObjectBigIntIdMock id)
31+
{
32+
33+
}
34+
35+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.framefork.typedIds.uuid.json.gson;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.GsonBuilder;
5+
import org.framefork.typedIds.uuid.ObjectUuidMock;
6+
import org.junit.jupiter.api.Test;
7+
8+
import static org.assertj.core.api.Assertions.assertThat;
9+
10+
class ObjectUuidGsonTest
11+
{
12+
13+
private final Gson gson = new GsonBuilder()
14+
.registerTypeAdapterFactory(new ObjectUuidTypeAdapterFactory())
15+
.create();
16+
17+
@Test
18+
public void functional() throws Exception
19+
{
20+
var id33 = ObjectUuidMock.from("33a7641c-811e-40b7-986e-ad109cfcf220");
21+
var originalDto = new Dto(id33);
22+
23+
var dtoJson = gson.toJson(originalDto);
24+
assertThat(dtoJson).isEqualTo("{\"id\":\"33a7641c-811e-40b7-986e-ad109cfcf220\"}");
25+
26+
var deserializedDto = gson.fromJson(dtoJson, Dto.class);
27+
assertThat(deserializedDto).isEqualTo(originalDto);
28+
}
29+
30+
record Dto(ObjectUuidMock id)
31+
{
32+
33+
}
34+
35+
}

0 commit comments

Comments
 (0)