Skip to content

Commit

Permalink
Support generic records (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZacSweers authored Jan 27, 2021
1 parent 7ad4bba commit ea8c44f
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

Expand All @@ -32,7 +35,23 @@ public JsonAdapter<?> create(
Type type, Set<? extends Annotation> annotations, Moshi moshi) {
if (!annotations.isEmpty()) { return null; }

if (!(type instanceof Class) && !(type instanceof ParameterizedType)) {
return null;
}

var rawType = Types.getRawType(type);

Map<String, Type> mappedTypeArgs = null;
if (type instanceof ParameterizedType parameterizedType) {
Type[] typeArgs = parameterizedType.getActualTypeArguments();
var typeVars = rawType.getTypeParameters();
mappedTypeArgs = new LinkedHashMap<>(typeArgs.length);
for (int i = 0; i < typeArgs.length; ++i) {
var typeVarName = typeVars[i].getName();
var materialized = typeArgs[i];
mappedTypeArgs.put(typeVarName, materialized);
}
}
if (!rawType.isRecord()) { return null; }
var components = rawType.getRecordComponents();
var bindings = new LinkedHashMap<String, ComponentBinding<?>>();
Expand All @@ -42,6 +61,17 @@ public JsonAdapter<?> create(
constructorParams[i] = component.getType();
var name = component.getName();
var componentType = component.getGenericType();
if (componentType instanceof TypeVariable<?> typeVariable) {
var typeVarName = typeVariable.getName();
if (mappedTypeArgs == null) {
throw new AssertionError("No mapped type arguments found for type '" + typeVarName + "'");
}
var mappedType = mappedTypeArgs.get(typeVarName);
if (mappedType == null) {
throw new AssertionError("No materialized type argument found for type '" + typeVarName + "'");
}
componentType = mappedType;
}
var jsonName = name;
Set<Annotation> qualifiers = null;
for (var annotation : component.getDeclaredAnnotations()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package dev.zacsweers.moshix.sealed.sample.java;

public record GenericRecord<T>(T value) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.zacsweers.moshix.sealed.sample.java;

import com.squareup.moshi.Moshi;
import com.squareup.moshi.Types;

import org.junit.Test;

import java.io.IOException;

import dev.zacsweers.moshix.records.RecordsJsonAdapterFactory;

import static com.google.common.truth.Truth.assertThat;

public final class RecordJsonAdapterFactoryTest {

private final Moshi moshi = new Moshi.Builder()
.add(new RecordsJsonAdapterFactory())
.build();

@Test
public void genericRecord() throws IOException {
var adapter = moshi.<GenericRecord<String>>adapter(Types.newParameterizedType(GenericRecord.class, String.class));
assertThat(adapter.fromJson("{\"value\":\"Okay!\"}"))
.isEqualTo(new GenericRecord<>("Okay!"));
}

}

0 comments on commit ea8c44f

Please sign in to comment.