Support configuration of auxiliary readers/writers through configure parameter
ci/woodpecker/push/woodpecker Pipeline failed Details

This commit is contained in:
Johannes Frohnmeyer 2022-11-13 10:59:19 +01:00
parent ed0fd6003d
commit df71bbc227
Signed by: Johannes
GPG Key ID: E76429612C2929F4
4 changed files with 75 additions and 42 deletions

View File

@ -15,6 +15,11 @@ public @interface GSerializable {
*/
Class<?> builder() default void.class;
/**
* @return The class to use for configuring JsonReader/JsonWriter instances from convenience methods in the generated class. Must have static configure methods for both.
*/
Class<?> configure() default void.class;
/**
* @return Whether to generate an adapter class to use with normal gson adapter resolution
*/

View File

@ -2,6 +2,8 @@ package io.gitlab.jfronny.gson;
import io.gitlab.jfronny.gson.annotations.SerializedName;
import io.gitlab.jfronny.gson.compile.annotations.*;
import io.gitlab.jfronny.gson.stream.JsonReader;
import io.gitlab.jfronny.gson.stream.JsonWriter;
import java.util.*;
@ -53,7 +55,7 @@ public class Main {
}
}
@GSerializable
@GSerializable(configure = Configuration.class)
public static class ExamplePojo2 {
@GComment("Yes!")
public boolean primitive;
@ -113,4 +115,14 @@ public class Main {
this.text = text;
}
}
public static class Configuration {
public static void configure(JsonWriter writer) {
}
public static void configure(JsonReader reader) {
}
}
}

View File

@ -19,6 +19,7 @@ import javax.tools.Diagnostic;
import java.io.*;
import java.nio.file.*;
import java.util.*;
import java.util.function.Function;
@SupportedSourceVersion(SourceVersion.RELEASE_17)
@SupportedAnnotationTypes2({GSerializable.class})
@ -55,6 +56,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
var bld = new Object() {
TypeMirror with = null;
TypeMirror builder = null;
TypeMirror configure = null;
Boolean generateAdapter = null;
};
elements.getElementValuesWithDefaults(mirror).forEach((executableElement, value) -> {
@ -68,6 +70,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
if (bld.builder != null) throw new IllegalArgumentException("Duplicate annotation parameter: builder");
bld.builder = (TypeMirror) value.getValue();
}
case "configure" -> {
if (bld.configure != null) throw new IllegalArgumentException("Duplicate annotation parameter: configure");
bld.configure = (TypeMirror) value.getValue();
}
case "generateAdapter" -> {
if (bld.generateAdapter != null) throw new IllegalArgumentException("Duplicate annotation parameter: generateAdapter");
bld.generateAdapter = (Boolean) value.getValue();
@ -76,10 +82,11 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
}
});
if (bld.with == null) throw new IllegalArgumentException("Missing annotation parameter: with");
if (bld.builder == null) throw new IllegalArgumentException("Missing annotation parameter: with");
if (bld.builder == null) throw new IllegalArgumentException("Missing annotation parameter: builder");
if (bld.configure == null) throw new IllegalArgumentException("Missing annotation parameter: configure");
if (bld.generateAdapter == null) throw new IllegalArgumentException("Missing annotation parameter: generateAdapter");
toGenerate.add(SerializableClass.of((TypeElement) element, bld.with, bld.builder, bld.generateAdapter));
toGenerate.add(SerializableClass.of((TypeElement) element, bld.with, bld.builder, bld.configure, bld.generateAdapter));
}
} catch (ElementException e) {
e.printMessage(message);
@ -128,7 +135,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
generateSerialisation(spec, toProcess, typeVariables, other);
}
generateAuxiliary(spec, classType);
generateAuxiliary(spec, classType, toProcess.configure());
JavaFile javaFile = JavaFile.builder(className.packageName(), spec.build())
.skipJavaLangImports(true)
@ -184,17 +191,26 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
);
}
private static void generateAuxiliary(TypeSpec.Builder spec, TypeName classType) {
private static void generateAuxiliary(TypeSpec.Builder spec, TypeName classType, TypeMirror configure) {
Function<CodeBlock.Builder, CodeBlock.Builder> configureReader = cb -> {
if (configure != null) cb.addStatement("$T.configure(reader)", configure);
return cb;
};
Function<CodeBlock.Builder, CodeBlock.Builder> configureWriter = cb -> {
if (configure != null) cb.addStatement("$T.configure(writer)", configure);
return cb;
};
spec.addMethod(
MethodSpec.methodBuilder("read")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.addParameter(TypeName.get(Reader.class), "in")
.addException(IOException.class)
.returns(classType)
.addCode("""
try ($T reader = $T.HOLDER.getGson().newJsonReader(in)) {
return read(reader);
}""", Cl.GSON_READER, Cl.CCORE)
.addCode(configureReader.apply(CodeBlock.builder().beginControlFlow("try ($1T reader = new $1T(in))", Cl.GSON_READER))
.addStatement("return read(reader)")
.endControlFlow()
.build())
.build()
);
@ -204,10 +220,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(TypeName.get(String.class), "json")
.addException(IOException.class)
.returns(classType)
.addCode("""
try ($1T reader = new $1T(json)) {
return read(reader);
}""", StringReader.class)
.addCode(CodeBlock.builder().beginControlFlow("try ($1T reader = new $1T(json))", StringReader.class)
.addStatement("return read(reader)")
.endControlFlow()
.build())
.build()
);
@ -217,10 +233,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(Cl.GSON_ELEMENT, "tree")
.addException(IOException.class)
.returns(classType)
.addCode("""
try ($1T reader = new $1T(tree)) {
return read(reader);
}""", Cl.GSON_TREE_READER)
.addCode(configureReader.apply(CodeBlock.builder().beginControlFlow("try ($1T reader = new $1T(tree))", Cl.GSON_TREE_READER))
.addStatement("return read(reader)")
.endControlFlow()
.build())
.build()
);
@ -230,10 +246,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(Path.class, "path")
.addException(IOException.class)
.returns(classType)
.addCode("""
try ($T br = $T.newBufferedReader(path)) {
return read(br);
}""", BufferedReader.class, Files.class)
.addCode(CodeBlock.builder().beginControlFlow("try ($T br = $T.newBufferedReader(path))", BufferedReader.class, Files.class)
.addStatement("return read(br)")
.endControlFlow()
.build())
.build()
);
@ -243,10 +259,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(Writer.class, "out")
.addParameter(classType, "value")
.addException(IOException.class)
.addCode("""
try ($T writer = $T.HOLDER.getGson().newJsonWriter(out)) {
write(writer, value);
}""", Cl.GSON_WRITER, Cl.CCORE)
.addCode(configureWriter.apply(CodeBlock.builder().beginControlFlow("try ($1T writer = new $1T(out))", Cl.GSON_WRITER))
.addStatement("write(writer, value)")
.endControlFlow()
.build())
.build()
);
@ -256,10 +272,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(Path.class, "path")
.addParameter(classType, "value")
.addException(IOException.class)
.addCode("""
try ($1T bw = $2T.newBufferedWriter(path, $3T.CREATE, $3T.WRITE, $3T.TRUNCATE_EXISTING)) {
write(bw, value);
}""", BufferedWriter.class, Files.class, StandardOpenOption.class)
.addCode(CodeBlock.builder().beginControlFlow("try ($1T bw = $2T.newBufferedWriter(path, $3T.CREATE, $3T.WRITE, $3T.TRUNCATE_EXISTING))", BufferedWriter.class, Files.class, StandardOpenOption.class)
.addStatement("write(bw, value)")
.endControlFlow()
.build())
.build()
);
@ -269,11 +285,11 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(classType, "value")
.addException(IOException.class)
.returns(String.class)
.addCode("""
try ($1T writer = new $1T()) {
write(writer, value);
return writer.toString();
}""", StringWriter.class)
.addCode(CodeBlock.builder().beginControlFlow("try ($1T writer = new $1T())", StringWriter.class)
.addStatement("write(writer, value)")
.addStatement("return writer.toString()")
.endControlFlow()
.build())
.build()
);
@ -283,11 +299,11 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
.addParameter(classType, "value")
.addException(IOException.class)
.returns(Cl.GSON_ELEMENT)
.addCode("""
try ($1T writer = new $1T()) {
write(writer, value);
return writer.get();
}""", Cl.GSON_TREE_WRITER)
.addCode(configureWriter.apply(CodeBlock.builder().beginControlFlow("try ($1T writer = new $1T())", Cl.GSON_TREE_WRITER))
.addStatement("write(writer, value)")
.addStatement("return writer.get()")
.endControlFlow()
.build())
.build()
);
}

View File

@ -8,11 +8,11 @@ import org.jetbrains.annotations.Nullable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.TypeMirror;
public record SerializableClass(TypeElement classElement, ClassName generatedClassName, @Nullable TypeMirror adapter, @Nullable TypeMirror builder, boolean generateAdapter) {
public static SerializableClass of(TypeElement element, @Nullable TypeMirror with, @Nullable TypeMirror builder, boolean generateAdapter) throws ElementException {
public record SerializableClass(TypeElement classElement, ClassName generatedClassName, @Nullable TypeMirror adapter, @Nullable TypeMirror builder, @Nullable TypeMirror configure, boolean generateAdapter) {
public static SerializableClass of(TypeElement element, @Nullable TypeMirror with, @Nullable TypeMirror builder, @Nullable TypeMirror configure, boolean generateAdapter) throws ElementException {
ClassName className = ClassName.get(element);
ClassName generatedClassName = ClassName.get(className.packageName(), "GC_" + String.join("_", className.simpleNames()));
return new SerializableClass(element, generatedClassName, voidToNull(with), voidToNull(builder), generateAdapter).validate();
return new SerializableClass(element, generatedClassName, voidToNull(with), voidToNull(builder), voidToNull(configure), generateAdapter).validate();
}
public ClassName getClassName() {