Add support for collections
This commit is contained in:
parent
7f08e5a8a3
commit
f0f9a171fd
|
@ -15,9 +15,9 @@ The goal of this AP is to
|
|||
- Records
|
||||
- Nested serializable types
|
||||
- Arrays
|
||||
- Collections (Sets, Lists, Queues, Deques)
|
||||
|
||||
## TODO
|
||||
- Collections (Sets, Lists, Queues, Deques)
|
||||
- Maps with string, primitive or enum keys
|
||||
- Date via ISO8601Utils
|
||||
- Enums
|
||||
|
|
|
@ -4,6 +4,8 @@ import io.gitlab.jfronny.gson.annotations.SerializedName;
|
|||
import io.gitlab.jfronny.gson.compile.annotations.GComment;
|
||||
import io.gitlab.jfronny.gson.compile.annotations.GSerializable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello world!");
|
||||
|
@ -23,6 +25,19 @@ public class Main {
|
|||
}
|
||||
|
||||
public ExamplePojo2 nested;
|
||||
|
||||
public Set<ExamplePojo> recursive1;
|
||||
|
||||
public LinkedList<ExampleRecord> recursive2;
|
||||
|
||||
public Queue<String> queue;
|
||||
|
||||
public void setJoe(String joe) {
|
||||
}
|
||||
|
||||
public String getJoe() {
|
||||
return "A";
|
||||
}
|
||||
}
|
||||
|
||||
@GSerializable
|
||||
|
|
|
@ -380,6 +380,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
code.addStatement("return $T.$N($L)", creatorName, constructionSource.getConstructionElement().getSimpleName(), args);
|
||||
}
|
||||
}
|
||||
//TODO manually set fields and setters if not in constructor
|
||||
|
||||
spec.addMethod(MethodSpec.methodBuilder("read")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
|
|
|
@ -20,6 +20,7 @@ public class Adapters {
|
|||
new PrimitiveAdapter(),
|
||||
new StringAdapter(),
|
||||
new ArrayAdapter(),
|
||||
new CollectionAdapter(),
|
||||
new OtherSerializableAdapter(),
|
||||
new ReflectAdapter()
|
||||
);
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
package io.gitlab.jfronny.gson.compile.processor.adapter.impl;
|
||||
|
||||
import com.squareup.javapoet.*;
|
||||
import io.gitlab.jfronny.gson.compile.processor.Cl;
|
||||
import io.gitlab.jfronny.gson.compile.processor.TypeHelper;
|
||||
import io.gitlab.jfronny.gson.compile.processor.adapter.Adapter;
|
||||
import io.gitlab.jfronny.gson.compile.processor.util.ValUtils;
|
||||
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.type.*;
|
||||
import javax.tools.Diagnostic;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
public class CollectionAdapter extends Adapter<CollectionAdapter.Hydrated> {
|
||||
@Override
|
||||
public Hydrated instantiate() {
|
||||
return new Hydrated();
|
||||
}
|
||||
|
||||
public class Hydrated extends Adapter<CollectionAdapter.Hydrated>.Hydrated {
|
||||
private static final Map<Class<?>, List<Class<?>>> SUPPORTED = ValUtils.mapOf(
|
||||
Set.class, List.of(LinkedHashSet.class, HashSet.class, TreeSet.class),
|
||||
List.class, List.of(ArrayList.class, LinkedList.class),
|
||||
Queue.class, List.of(ArrayDeque.class, LinkedList.class),
|
||||
Deque.class, List.of(ArrayDeque.class)
|
||||
);
|
||||
|
||||
private DeclaredType type;
|
||||
private TypeName implType;
|
||||
private TypeMirror componentType;
|
||||
|
||||
@Override
|
||||
public boolean applies() {
|
||||
return type != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterHydrate() {
|
||||
type = TypeHelper.asDeclaredType(super.type);
|
||||
componentType = null;
|
||||
if (type == null) return;
|
||||
List<? extends TypeMirror> typeArguments = type.getTypeArguments();
|
||||
if (typeArguments.size() == 0) {
|
||||
type = null;
|
||||
} else {
|
||||
componentType = typeArguments.get(0);
|
||||
String ts = TypeHelper.asDeclaredType(typeUtils.erasure(type)).asElement().toString();
|
||||
for (Map.Entry<Class<?>, List<Class<?>>> entry : SUPPORTED.entrySet()) {
|
||||
if (entry.getKey().getCanonicalName().equals(ts)) {
|
||||
implType = TypeName.get(entry.getValue().get(0));
|
||||
return;
|
||||
}
|
||||
for (Class<?> klazz : entry.getValue()) {
|
||||
if (klazz.getCanonicalName().equals(ts)) {
|
||||
implType = TypeName.get(klazz);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
type = null;
|
||||
componentType = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateWrite(Runnable writeGet) {
|
||||
code.addStatement("writer.beginArray()");
|
||||
code.add("for ($T $N : ", componentType, argName);
|
||||
writeGet.run();
|
||||
code.beginControlFlow(")")
|
||||
.beginControlFlow("if ($N == null)", argName)
|
||||
.addStatement("if (writer.getSerializeNulls()) writer.nullValue()")
|
||||
.nextControlFlow("else");
|
||||
generateWrite(code, componentType, argName, componentType.getAnnotationMirrors(), () -> code.add(argName));
|
||||
code.endControlFlow().endControlFlow().addStatement("writer.endArray()");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateRead() {
|
||||
CodeBlock.Builder kode = CodeBlock.builder();
|
||||
kode.addStatement("$T list = new $T<>()", typeName, implType);
|
||||
// Coerce
|
||||
kode.beginControlFlow("if (reader.isLenient() && reader.peek() != $T.BEGIN_ARRAY)", Cl.GSON_TOKEN)
|
||||
.add("list.add(");
|
||||
generateRead(kode, componentType, argName, componentType.getAnnotationMirrors());
|
||||
kode.add(");\n").addStatement("return list").endControlFlow();
|
||||
|
||||
kode.addStatement("reader.beginArray()")
|
||||
.beginControlFlow("while (reader.hasNext())")
|
||||
.beginControlFlow("if (reader.peek() == $T.NULL)", Cl.GSON_TOKEN)
|
||||
.addStatement("reader.nextNull()")
|
||||
.addStatement("list.add(null)")
|
||||
.nextControlFlow("else")
|
||||
.add("list.add(");
|
||||
generateRead(kode, componentType, argName, componentType.getAnnotationMirrors());
|
||||
kode.add(");\n")
|
||||
.endControlFlow()
|
||||
.endControlFlow()
|
||||
.addStatement("reader.endArray()")
|
||||
.addStatement("return list");
|
||||
|
||||
String methodName = "read$" + name;
|
||||
klazz.addMethod(
|
||||
MethodSpec.methodBuilder(methodName)
|
||||
.addModifiers(Modifier.PRIVATE, Modifier.STATIC)
|
||||
.returns(typeName)
|
||||
.addParameter(Cl.GSON_READER, "reader")
|
||||
.addException(IOException.class)
|
||||
.addCode(kode.build())
|
||||
.build()
|
||||
);
|
||||
code.add("$N(reader)", methodName);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package io.gitlab.jfronny.gson.compile.processor.util;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ValUtils {
|
||||
public static <K, V> Map<K, V> mapOf() {
|
||||
return new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1) {
|
||||
Map<K, V> map = mapOf();
|
||||
map.put(k1, v1);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2) {
|
||||
Map<K, V> map = mapOf(k1, v1);
|
||||
map.put(k2, v2);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2);
|
||||
map.put(k3, v3);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3);
|
||||
map.put(k4, v4);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4);
|
||||
map.put(k5, v5);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
|
||||
map.put(k6, v6);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6);
|
||||
map.put(k7, v7);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7);
|
||||
map.put(k8, v8);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8);
|
||||
map.put(k9, v9);
|
||||
return map;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5, K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
|
||||
Map<K, V> map = mapOf(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7, k8, v8, k9, v9);
|
||||
map.put(k10, v10);
|
||||
return map;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue