feat(serialize-generator): try to support SerializerFor
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
This commit is contained in:
parent
1a436343da
commit
d0a14329b6
@ -0,0 +1,7 @@
|
||||
package io.gitlab.jfronny.commons.serialize.generator;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
public record AdapterRef(TypeElement in, TypeMirror[] targets, boolean nullSafe) {
|
||||
}
|
@ -3,6 +3,7 @@ package io.gitlab.jfronny.commons.serialize.generator;
|
||||
import com.squareup.javapoet.*;
|
||||
import io.gitlab.jfronny.commons.StringFormatter;
|
||||
import io.gitlab.jfronny.commons.serialize.databind.api.SerializeWithAdapter;
|
||||
import io.gitlab.jfronny.commons.serialize.databind.api.SerializerFor;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.Adapter;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.Adapters;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.annotations.GPrefer;
|
||||
@ -31,9 +32,10 @@ import javax.tools.StandardLocation;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SupportedSourceVersion(SourceVersion.RELEASE_17)
|
||||
@SupportedAnnotationTypes2({GSerializable.class, SerializeWithAdapter.class})
|
||||
@SupportedAnnotationTypes2({GSerializable.class, SerializeWithAdapter.class, SerializerFor.class})
|
||||
@SupportedOptions({"serializeProcessorNoReflect", "serializeProcessorDisableSafe"})
|
||||
public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
private Map<ClassName, TypeSpec.Builder> seen;
|
||||
@ -58,6 +60,7 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
|
||||
Set<SerializableClass> toGenerate = new LinkedHashSet<>();
|
||||
Set<AdapterRef> adapterRefs = new LinkedHashSet<>();
|
||||
// Gather all serializable types
|
||||
for (TypeElement annotation : annotations) {
|
||||
for (Element element : roundEnvironment.getElementsAnnotatedWith(annotation)) {
|
||||
@ -127,6 +130,28 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
if (bld.nullSafe == null) throw new IllegalArgumentException("Missing annotation parameter: nullSafe");
|
||||
|
||||
toGenerate.add(SerializableClass.of((TypeElement) element, bld.adapter, false, null, null, false, false, hasManifold));
|
||||
} else if (mirror.getAnnotationType().toString().equals(SerializerFor.class.getCanonicalName())) {
|
||||
var bld = new Object() {
|
||||
TypeMirror[] targets = null;
|
||||
Boolean nullSafe = null;
|
||||
};
|
||||
elements.getElementValuesWithDefaults(mirror).forEach((executableElement, value) -> {
|
||||
String name = executableElement.getSimpleName().toString();
|
||||
switch (name) {
|
||||
case "targets" -> {
|
||||
if (bld.targets != null) throw new IllegalArgumentException("Duplicate annotation parameter: targets");
|
||||
bld.targets = ((List<?>) value.getValue()).stream().map(o -> (TypeMirror) o).toArray(TypeMirror[]::new);
|
||||
}
|
||||
case "nullSafe" -> {
|
||||
if (bld.nullSafe != null) throw new IllegalArgumentException("Duplicate annotation parameter: nullSafe");
|
||||
bld.nullSafe = (Boolean) value.getValue();
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unexpected annotation parameter: " + name);
|
||||
}
|
||||
});
|
||||
if (bld.targets == null) throw new IllegalArgumentException("Missing annotation parameter: targets");
|
||||
if (bld.nullSafe == null) throw new IllegalArgumentException("Missing annotation parameter: nullSafe");
|
||||
adapterRefs.add(new AdapterRef((TypeElement) element, bld.targets, bld.nullSafe));
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unexpected annotation: " + mirror.getAnnotationType());
|
||||
}
|
||||
@ -138,10 +163,11 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
}
|
||||
// Do not allow mutation past this point, especially not from individual process tasks
|
||||
toGenerate = Set.copyOf(toGenerate);
|
||||
adapterRefs = Set.copyOf(adapterRefs);
|
||||
// Generate adapters
|
||||
for (SerializableClass toProcess : toGenerate) {
|
||||
try {
|
||||
process(toProcess, toGenerate);
|
||||
process(toProcess, toGenerate, adapterRefs);
|
||||
} catch (ElementException e) {
|
||||
e.printMessage(message);
|
||||
}
|
||||
@ -197,13 +223,12 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
}
|
||||
}
|
||||
if (!generatedAdapters.isEmpty()) {
|
||||
for (ClassName name : generatedAdapters) {
|
||||
|
||||
}
|
||||
try {
|
||||
filer.createResource(StandardLocation.SOURCE_OUTPUT, "", "META-INF/services/io.gitlab.jfronny.commons.serialize.databind.api.TypeAdapter")
|
||||
.openWriter()
|
||||
.append(generatedAdapters.stream().map(ClassName::canonicalName).collect(Collectors.joining("\n")))
|
||||
.append(Stream.concat(generatedAdapters.stream(), adapterRefs.stream().map(AdapterRef::in).map(ClassName::get))
|
||||
.map(ClassName::canonicalName)
|
||||
.collect(Collectors.joining("\n")))
|
||||
.close();
|
||||
} catch (IOException e) {
|
||||
message.printMessage(Diagnostic.Kind.ERROR, "Could not write service loader file: " + StringFormatter.toString(e));
|
||||
@ -219,7 +244,7 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void process(SerializableClass toProcess, Set<SerializableClass> other) throws ElementException {
|
||||
private void process(SerializableClass toProcess, Set<SerializableClass> other, Set<AdapterRef> refs) throws ElementException {
|
||||
if (seen.containsKey(toProcess.generatedClassName())) return; // Don't process the same class more than once
|
||||
|
||||
TypeName classType = toProcess.getTypeName();
|
||||
@ -245,7 +270,7 @@ public class SerializeGeneratorProcessor extends AbstractProcessor2 {
|
||||
if (toProcess.generateAdapter()) {
|
||||
generatedAdapters.add(processor.generateDelegatingAdapter(spec, classType, toProcess.generatedClassName()));
|
||||
}
|
||||
processor.generateSerialisation(spec, toProcess, typeVariables, other); //TODO fix type annotations
|
||||
processor.generateSerialisation(spec, toProcess, typeVariables, other, refs); //TODO fix type annotations
|
||||
}
|
||||
|
||||
processor.generateAuxiliary(spec, classType, toProcess.configure());
|
||||
|
@ -4,6 +4,7 @@ import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.SerializableClass;
|
||||
|
||||
import javax.annotation.processing.Messager;
|
||||
@ -29,11 +30,12 @@ public abstract class Adapter<T extends Adapter<T>.Hydrated> {
|
||||
this.options = env.getOptions();
|
||||
}
|
||||
|
||||
public final T hydrate(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement) {
|
||||
public final T hydrate(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, Set<AdapterRef> refs, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement) {
|
||||
T instance = instantiate();
|
||||
instance.klazz = klazz;
|
||||
instance.typeVariables = typeVariables;
|
||||
instance.other = other;
|
||||
instance.refs = refs;
|
||||
instance.type = type;
|
||||
instance.code = code;
|
||||
instance.unboxedType = instance.unbox(type);
|
||||
@ -51,6 +53,7 @@ public abstract class Adapter<T extends Adapter<T>.Hydrated> {
|
||||
protected TypeSpec.Builder klazz;
|
||||
protected List<TypeVariableName> typeVariables;
|
||||
protected Set<SerializableClass> other;
|
||||
protected Set<AdapterRef> refs;
|
||||
protected TypeMirror type;
|
||||
protected TypeMirror unboxedType;
|
||||
protected CodeBlock.Builder code;
|
||||
@ -67,11 +70,11 @@ public abstract class Adapter<T extends Adapter<T>.Hydrated> {
|
||||
protected void afterHydrate() {}
|
||||
|
||||
protected void generateRead(CodeBlock.Builder code, TypeMirror type, String name, List<? extends AnnotationMirror> annotations) {
|
||||
Adapters.generateRead(klazz, code, typeVariables, other, type, name, annotations, sourceElement, message);
|
||||
Adapters.generateRead(klazz, code, typeVariables, other, refs, type, name, annotations, sourceElement, message);
|
||||
}
|
||||
|
||||
protected void generateWrite(CodeBlock.Builder code, TypeMirror type, String name, List<? extends AnnotationMirror> annotations, Runnable writeGet) {
|
||||
Adapters.generateWrite(klazz, code, typeVariables, other, type, name, annotations, sourceElement, message, writeGet);
|
||||
Adapters.generateWrite(klazz, code, typeVariables, other, refs, type, name, annotations, sourceElement, message, writeGet);
|
||||
}
|
||||
|
||||
protected TypeMirror unbox(TypeMirror type) {
|
||||
|
@ -3,6 +3,7 @@ package io.gitlab.jfronny.commons.serialize.generator.adapter;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
import com.squareup.javapoet.TypeVariableName;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.SerializableClass;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.impl.*;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.core.value.Property;
|
||||
@ -19,6 +20,7 @@ import java.util.function.Consumer;
|
||||
public class Adapters {
|
||||
public static final List<Adapter<?>> ADAPTERS = List.of(
|
||||
new DeclaredAdapter(),
|
||||
new InferredAdapter(),
|
||||
new PrimitiveAdapter(),
|
||||
new StringAdapter(),
|
||||
new DateAdapter(),
|
||||
@ -30,29 +32,29 @@ public class Adapters {
|
||||
new ReflectAdapter()
|
||||
);
|
||||
|
||||
public static void generateRead(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Messager message) {
|
||||
withAdapter(prop, klazz, code, typeVariables, otherAdapters, message, Adapter.Hydrated::generateRead);
|
||||
public static void generateRead(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs, Messager message) {
|
||||
withAdapter(prop, klazz, code, typeVariables, otherAdapters, refs, message, Adapter.Hydrated::generateRead);
|
||||
}
|
||||
|
||||
public static void generateWrite(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Messager message, Runnable writeGet) {
|
||||
withAdapter(prop, klazz, code, typeVariables, otherAdapters, message, adapter -> adapter.generateWrite(writeGet));
|
||||
public static void generateWrite(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs, Messager message, Runnable writeGet) {
|
||||
withAdapter(prop, klazz, code, typeVariables, otherAdapters, refs, message, adapter -> adapter.generateWrite(writeGet));
|
||||
}
|
||||
|
||||
private static void withAdapter(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Messager message, Consumer<Adapter<?>.Hydrated> action) {
|
||||
withAdapter(klazz, code, typeVariables, otherAdapters, prop.getType(), prop.getName(), prop.getAnnotations(), prop.getElement(), message, action);
|
||||
private static void withAdapter(Property<?> prop, TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs, Messager message, Consumer<Adapter<?>.Hydrated> action) {
|
||||
withAdapter(klazz, code, typeVariables, otherAdapters, refs, prop.getType(), prop.getName(), prop.getAnnotations(), prop.getElement(), message, action);
|
||||
}
|
||||
|
||||
public static void generateRead(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message) {
|
||||
withAdapter(klazz, code, typeVariables, other, type, propName, annotations, sourceElement, message, Adapter.Hydrated::generateRead);
|
||||
public static void generateRead(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, Set<AdapterRef> refs, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message) {
|
||||
withAdapter(klazz, code, typeVariables, other, refs, type, propName, annotations, sourceElement, message, Adapter.Hydrated::generateRead);
|
||||
}
|
||||
|
||||
public static void generateWrite(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message, Runnable writeGet) {
|
||||
withAdapter(klazz, code, typeVariables, other, type, propName, annotations, sourceElement, message, adapter -> adapter.generateWrite(writeGet));
|
||||
public static void generateWrite(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, Set<AdapterRef> refs, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message, Runnable writeGet) {
|
||||
withAdapter(klazz, code, typeVariables, other, refs, type, propName, annotations, sourceElement, message, adapter -> adapter.generateWrite(writeGet));
|
||||
}
|
||||
|
||||
private static void withAdapter(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message, Consumer<Adapter<?>.Hydrated> action) {
|
||||
private static void withAdapter(TypeSpec.Builder klazz, CodeBlock.Builder code, List<TypeVariableName> typeVariables, Set<SerializableClass> other, Set<AdapterRef> refs, TypeMirror type, String propName, List<? extends AnnotationMirror> annotations, Element sourceElement, Messager message, Consumer<Adapter<?>.Hydrated> action) {
|
||||
for (Adapter<?> adapter : Adapters.ADAPTERS) {
|
||||
Adapter<?>.Hydrated hydrated = adapter.hydrate(klazz, code, typeVariables, other, type, propName, annotations, sourceElement);
|
||||
Adapter<?>.Hydrated hydrated = adapter.hydrate(klazz, code, typeVariables, other, refs, type, propName, annotations, sourceElement);
|
||||
if (hydrated.applies()) {
|
||||
action.accept(hydrated);
|
||||
return;
|
||||
|
@ -0,0 +1,53 @@
|
||||
package io.gitlab.jfronny.commons.serialize.generator.adapter.impl;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.AdapterAdapter;
|
||||
import io.gitlab.jfronny.commons.tuple.Tuple;
|
||||
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import java.util.Set;
|
||||
|
||||
public class InferredAdapter extends AdapterAdapter<InferredAdapter.Hydrated> {
|
||||
@Override
|
||||
public Hydrated instantiate() {
|
||||
return new Hydrated();
|
||||
}
|
||||
|
||||
public class Hydrated extends AdapterAdapter<Hydrated>.Hydrated {
|
||||
private TypeElement typeAdapterClass;
|
||||
|
||||
@Override
|
||||
public boolean applies() {
|
||||
return typeAdapterClass != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterHydrate() {
|
||||
var tmp = findTypeAdapterClass(type, refs);
|
||||
// Ignore nullSafe for now
|
||||
if (tmp != null) {
|
||||
this.typeAdapterClass = tmp.left();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TypeName createAdapter(String typeAdapterName) {
|
||||
return ClassName.get(typeAdapterClass);
|
||||
}
|
||||
|
||||
private static Tuple<TypeElement, Boolean> findTypeAdapterClass(TypeMirror type, Set<AdapterRef> refs) {
|
||||
TypeName tn = TypeName.get(type);
|
||||
for (AdapterRef ref : refs) {
|
||||
for (TypeMirror target : ref.targets()) {
|
||||
if (tn.equals(TypeName.get(target))) {
|
||||
return Tuple.of(ref.in(), ref.nullSafe());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package io.gitlab.jfronny.commons.serialize.generator.gprocessor;
|
||||
|
||||
import com.squareup.javapoet.*;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.Cl;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.SerializableClass;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.core.value.ElementException;
|
||||
@ -47,7 +48,7 @@ public abstract class GProcessor {
|
||||
}
|
||||
|
||||
public abstract ClassName generateDelegatingAdapter(TypeSpec.Builder spec, TypeName classType, ClassName generatedClassName);
|
||||
public abstract void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters) throws ElementException;
|
||||
public abstract void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs) throws ElementException;
|
||||
|
||||
protected boolean isIgnored(Property<?> property) {
|
||||
for (AnnotationMirror annotationMirror : property.getAnnotations()) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.gitlab.jfronny.commons.serialize.generator.gprocessor;
|
||||
|
||||
import com.squareup.javapoet.*;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.Cl;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.SerializableClass;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.Adapters;
|
||||
@ -59,7 +60,7 @@ public class InstanceProcessor extends GProcessor {
|
||||
// (Or, alternatively, create one common solution for these)
|
||||
// !!!WARNING!!!
|
||||
@Override
|
||||
public void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters) throws ElementException {
|
||||
public void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs) 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();
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.gitlab.jfronny.commons.serialize.generator.gprocessor;
|
||||
|
||||
import com.squareup.javapoet.*;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.AdapterRef;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.Cl;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.SerializableClass;
|
||||
import io.gitlab.jfronny.commons.serialize.generator.adapter.Adapters;
|
||||
@ -30,7 +31,7 @@ public class StaticProcessor extends GProcessor {
|
||||
// (Or, alternatively, create one common solution for these)
|
||||
// !!!WARNING!!!
|
||||
@Override
|
||||
public void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters) throws ElementException {
|
||||
public void generateSerialisation(TypeSpec.Builder spec, SerializableClass self, List<TypeVariableName> typeVariables, Set<SerializableClass> otherAdapters, Set<AdapterRef> refs) throws ElementException {
|
||||
Value value = valueCreator.fromStatic(self.classElement());
|
||||
Properties properties = value.getProperties();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user