data-generator/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenUpgraderSuperX.java

97 lines
3.8 KiB
Java

package it.cavallium.data.generator.plugin.classgen;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import it.cavallium.data.generator.DataUpgrader;
import it.cavallium.data.generator.plugin.ClassGenerator;
import it.cavallium.data.generator.plugin.ComputedType;
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
import it.cavallium.data.generator.plugin.ComputedTypeSuper;
import it.cavallium.data.generator.plugin.ComputedVersion;
import java.util.stream.Stream;
import javax.lang.model.element.Modifier;
import org.jetbrains.annotations.NotNull;
public class GenUpgraderSuperX extends ClassGenerator {
public GenUpgraderSuperX(ClassGeneratorParams params) {
super(params);
}
@Override
protected Stream<GeneratedClass> generateClasses() {
return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses);
}
private Stream<GeneratedClass> generateVersionClasses(ComputedVersion version) {
return dataModel
.getSuperTypesComputed(version)
.filter(type -> !type.getVersion().isCurrent() && type.getVersion().equals(version))
.map(type -> generateTypeVersioned(version, type));
}
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeSuper typeSuper) {
ClassName upgraderClassName = typeSuper.getJUpgraderName(basePackageName);
ClassName typeBaseClassName = typeSuper.getJTypeName(basePackageName);
ComputedTypeSuper nextTypeSuper = dataModel.getNextVersion(typeSuper);
var classBuilder = TypeSpec.classBuilder(upgraderClassName.simpleName());
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataUpgrader.class),
typeBaseClassName,
nextTypeSuper.getJTypeName(basePackageName)
));
generateUpgradeMethod(version, typeSuper, nextTypeSuper, classBuilder);
return new GeneratedClass(upgraderClassName.packageName(), classBuilder);
}
private void generateUpgradeMethod(ComputedVersion version, ComputedTypeSuper typeSuper,
ComputedTypeSuper nextTypeSuper,
Builder classBuilder) {
var method = MethodSpec.methodBuilder("upgrade");
method.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
ClassName typeSuperClassName = typeSuper.getJTypeName(basePackageName);
ClassName nextTypeSuperClassName = nextTypeSuper.getJTypeName(basePackageName);
method.returns(nextTypeSuperClassName);
method.addAnnotation(NotNull.class);
method.addParameter(ParameterSpec.builder(typeSuperClassName, "data").addAnnotation(NotNull.class).build());
method.beginControlFlow("return switch (data.getMetaId$$$N())", typeSuper.getName());
int i = 0;
for (ComputedType subType : typeSuper.subTypes()) {
method.addCode("case $L -> ", i);
method.addStatement(upgradeSubTypeToType(subType, CodeBlock.of("($T) data", subType.getJTypeName(basePackageName)), nextTypeSuper));
i++;
}
method.addStatement("default -> throw new $T(data.getMetaId$$$N())", IndexOutOfBoundsException.class, typeSuper.getName());
method.addCode("$<};\n");
classBuilder.addMethod(method.build());
}
private CodeBlock upgradeSubTypeToType(ComputedType subType,
CodeBlock codeBlock,
ComputedTypeSuper nextTypeSuper) {
while (subType instanceof VersionedComputedType versionedComputedType
&& versionedComputedType.getVersion().compareTo(nextTypeSuper.getVersion()) < 0) {
var currentFieldType = subType;
var nextFieldType = dataModel.getNextVersion(currentFieldType);
codeBlock = currentFieldType.wrapWithUpgrade(basePackageName, codeBlock, nextFieldType);
subType = nextFieldType;
}
return codeBlock;
}
}