Support builders
This commit is contained in:
parent
cf795cdedc
commit
47c77a116b
|
@ -10,6 +10,11 @@ public @interface GSerializable {
|
|||
*/
|
||||
Class<?> with() default void.class;
|
||||
|
||||
/**
|
||||
* @return The builder class to use for creating this type. Incompatible with custom serialization
|
||||
*/
|
||||
Class<?> builder() default void.class;
|
||||
|
||||
/**
|
||||
* @return Whether to generate an adapter class to use with normal gson adapter resolution
|
||||
*/
|
||||
|
|
|
@ -53,4 +53,30 @@ public class Main {
|
|||
this(yes, null);
|
||||
}
|
||||
}
|
||||
|
||||
@GSerializable(builder = Example4.Builder.class)
|
||||
public static class Example4 {
|
||||
public String someField;
|
||||
public boolean shesh;
|
||||
|
||||
public static class Builder {
|
||||
private String someField;
|
||||
private boolean shesh;
|
||||
|
||||
public Builder(String someField) {
|
||||
this.someField = someField;
|
||||
}
|
||||
|
||||
public Builder setShesh(boolean shesh) {
|
||||
this.shesh = shesh;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Example4 build() {
|
||||
Example4 e = new Example4();
|
||||
e.someField = someField;
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -50,30 +50,39 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
for (TypeElement annotation : annotations) {
|
||||
for (Element element : roundEnvironment.getElementsAnnotatedWith(annotation)) {
|
||||
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
|
||||
if (mirror.getAnnotationType().toString().equals(GSerializable.class.getCanonicalName())) {
|
||||
var bld = new Object() {
|
||||
TypeMirror with = null;
|
||||
Boolean generateAdapter = null;
|
||||
};
|
||||
elements.getElementValuesWithDefaults(mirror).forEach((executableElement, value) -> {
|
||||
String name = executableElement.getSimpleName().toString();
|
||||
switch (name) {
|
||||
case "with" -> {
|
||||
if (bld.with != null) throw new IllegalArgumentException("Duplicate annotation parameter: with");
|
||||
bld.with = (TypeMirror) value.getValue();
|
||||
try {
|
||||
if (mirror.getAnnotationType().toString().equals(GSerializable.class.getCanonicalName())) {
|
||||
var bld = new Object() {
|
||||
TypeMirror with = null;
|
||||
TypeMirror builder = null;
|
||||
Boolean generateAdapter = null;
|
||||
};
|
||||
elements.getElementValuesWithDefaults(mirror).forEach((executableElement, value) -> {
|
||||
String name = executableElement.getSimpleName().toString();
|
||||
switch (name) {
|
||||
case "with" -> {
|
||||
if (bld.with != null) throw new IllegalArgumentException("Duplicate annotation parameter: with");
|
||||
bld.with = (TypeMirror) value.getValue();
|
||||
}
|
||||
case "builder" -> {
|
||||
if (bld.builder != null) throw new IllegalArgumentException("Duplicate annotation parameter: builder");
|
||||
bld.builder = (TypeMirror) value.getValue();
|
||||
}
|
||||
case "generateAdapter" -> {
|
||||
if (bld.generateAdapter != null) throw new IllegalArgumentException("Duplicate annotation parameter: generateAdapter");
|
||||
bld.generateAdapter = (Boolean) value.getValue();
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unexpected annotation parameter: " + name);
|
||||
}
|
||||
case "generateAdapter" -> {
|
||||
if (bld.generateAdapter != null) throw new IllegalArgumentException("Duplicate annotation parameter: generateAdapter");
|
||||
bld.generateAdapter = (Boolean) value.getValue();
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unexpected annotation parameter: " + name);
|
||||
}
|
||||
});
|
||||
if (bld.with == null) throw new IllegalArgumentException("Missing annotation parameter: with");
|
||||
if (bld.generateAdapter == null) throw new IllegalArgumentException("Missing annotation parameter: generateAdapter");
|
||||
if (bld.with.toString().equals("void")) bld.with = null;
|
||||
});
|
||||
if (bld.with == null) throw new IllegalArgumentException("Missing annotation parameter: with");
|
||||
if (bld.builder == null) throw new IllegalArgumentException("Missing annotation parameter: with");
|
||||
if (bld.generateAdapter == null) throw new IllegalArgumentException("Missing annotation parameter: generateAdapter");
|
||||
|
||||
toGenerate.add(SerializableClass.of((TypeElement) element, bld.with, bld.generateAdapter));
|
||||
toGenerate.add(SerializableClass.of((TypeElement) element, bld.with, bld.builder, bld.generateAdapter));
|
||||
}
|
||||
} catch (ElementException e) {
|
||||
e.printMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,8 +93,10 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
for (SerializableClass toProcess : toGenerate) {
|
||||
try {
|
||||
process(toProcess, toGenerate);
|
||||
} catch (IOException | ElementException e) {
|
||||
} catch (IOException e) {
|
||||
message.printMessage(Diagnostic.Kind.ERROR, "GsonCompile threw an exception: " + StringFormatter.toString(e), toProcess.classElement());
|
||||
} catch (ElementException e) {
|
||||
e.printMessage(message);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -114,7 +125,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
if (toProcess.generateAdapter()) {
|
||||
generateDelegatingAdapter(spec, classType, toProcess.generatedClassName());
|
||||
}
|
||||
generateSerialisation(spec, classType, toProcess.classElement(), typeVariables, other);
|
||||
generateSerialisation(spec, toProcess, typeVariables, other);
|
||||
}
|
||||
|
||||
generateAuxiliary(spec, classType);
|
||||
|
@ -256,8 +267,8 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
);
|
||||
}
|
||||
|
||||
private void generateSerialisation(TypeSpec.Builder spec, TypeName classType, TypeElement classElement, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters) throws ElementException {
|
||||
Value value = valueCreator.from(classElement, false);
|
||||
private void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters) throws ElementException {
|
||||
Value value = self.builder() == null ? valueCreator.from(self.classElement(), false) : valueCreator.from(TypeHelper.asDeclaredType(self.builder()).asElement(), true);
|
||||
ConstructionSource constructionSource = value.getConstructionSource();
|
||||
Properties properties = value.getProperties();
|
||||
|
||||
|
@ -303,7 +314,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
spec.addMethod(MethodSpec.methodBuilder("write")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.addParameter(Cl.GSON_WRITER, "writer")
|
||||
.addParameter(classType, "value")
|
||||
.addParameter(self.getTypeName(), "value")
|
||||
.addException(IOException.class)
|
||||
.addCode(code.build())
|
||||
.build());
|
||||
|
@ -358,7 +369,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
if (constructionSource.isConstructor()) {
|
||||
code.add("return new $T($L)", builder.getBuilderClass(), args);
|
||||
} else {
|
||||
code.add("return $T.$N($L)", creatorName, classElement.getSimpleName(), args);
|
||||
code.add("return $T.$N($L)", creatorName, self.classElement().getSimpleName(), args);
|
||||
}
|
||||
code.add("\n").indent();
|
||||
for (Property.BuilderParam param : properties.builderParams) {
|
||||
|
@ -368,7 +379,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
} else {
|
||||
String args = properties.params.stream().map(s -> "_" + s.getName()).collect(Collectors.joining(", "));
|
||||
if (constructionSource.isConstructor()) {
|
||||
code.addStatement("return new $T($L)", classType, args);
|
||||
code.addStatement("return new $T($L)", self.getTypeName(), args);
|
||||
} else {
|
||||
code.addStatement("return $T.$N($L)", creatorName, constructionSource.getConstructionElement().getSimpleName(), args);
|
||||
}
|
||||
|
@ -377,7 +388,7 @@ public class GsonCompileProcessor extends AbstractProcessor2 {
|
|||
|
||||
spec.addMethod(MethodSpec.methodBuilder("read")
|
||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
||||
.returns(classType)
|
||||
.returns(self.getTypeName())
|
||||
.addParameter(Cl.GSON_READER, "reader")
|
||||
.addException(IOException.class)
|
||||
.addCode(code.build())
|
||||
|
|
|
@ -2,16 +2,17 @@ package io.gitlab.jfronny.gson.compile.processor;
|
|||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import io.gitlab.jfronny.gson.compile.processor.util.valueprocessor.ElementException;
|
||||
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, boolean generateAdapter) {
|
||||
public static SerializableClass of(TypeElement element, @Nullable TypeMirror with, boolean generateAdapter) {
|
||||
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 {
|
||||
ClassName className = ClassName.get(element);
|
||||
ClassName generatedClassName = ClassName.get(className.packageName(), "GC_" + String.join("_", className.simpleNames()));
|
||||
return new SerializableClass(element, generatedClassName, with, generateAdapter);
|
||||
return new SerializableClass(element, generatedClassName, voidToNull(with), voidToNull(builder), generateAdapter).validate();
|
||||
}
|
||||
|
||||
public ClassName getClassName() {
|
||||
|
@ -21,4 +22,13 @@ public record SerializableClass(TypeElement classElement, ClassName generatedCla
|
|||
public TypeName getTypeName() {
|
||||
return TypeName.get(classElement.asType());
|
||||
}
|
||||
|
||||
private SerializableClass validate() throws ElementException {
|
||||
if (adapter != null && builder != null) throw new ElementException("@Serializable with both an adapter and a builder. This is unsupported!", classElement);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static TypeMirror voidToNull(TypeMirror type) {
|
||||
return type == null || type.toString().equals("void") ? null : type;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue