This commit is contained in:
Andrea Cavalli 2023-01-21 21:44:05 +01:00
parent 68ce3b6d7e
commit ed2b51d0b0
6 changed files with 137 additions and 15 deletions

View File

@ -1,7 +1,7 @@
package it.cavallium.data.generator.plugin;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.CodeBlock;
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
import java.util.ArrayList;
import java.util.LinkedHashMap;
@ -110,7 +110,7 @@ public final class ComputedTypeSuper implements VersionedComputedType {
}
@Override
public TypeName getJUpgraderName(String basePackageName) {
public ClassName getJUpgraderName(String basePackageName) {
return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Upgrader");
}
@ -121,6 +121,16 @@ public final class ComputedTypeSuper implements VersionedComputedType {
return new FieldLocation(className, upgraderFieldName);
}
@Override
public CodeBlock wrapWithUpgrade(String basePackageName, CodeBlock content, ComputedType next) {
var upgraderInstance = getJUpgraderInstance(basePackageName);
var cb = CodeBlock.builder();
cb.add(CodeBlock.of("$T.$N.upgrade(", upgraderInstance.className(), upgraderInstance.fieldName()));
cb.add(content);
cb.add(")");
return VersionedComputedType.super.wrapWithUpgrade(basePackageName, cb.build(), next);
}
@Override
public String toString() {
return type.type() + " (super, v" + getVersion() + ")";

View File

@ -30,6 +30,7 @@ import it.cavallium.data.generator.plugin.classgen.GenSerializerNullableX;
import it.cavallium.data.generator.plugin.classgen.GenSerializerSuperX;
import it.cavallium.data.generator.plugin.classgen.GenSuperType;
import it.cavallium.data.generator.plugin.classgen.GenUpgraderBaseX;
import it.cavallium.data.generator.plugin.classgen.GenUpgraderSuperX;
import it.cavallium.data.generator.plugin.classgen.GenVersion;
import it.cavallium.data.generator.plugin.classgen.GenVersions;
import it.unimi.dsi.fastutil.booleans.BooleanList;
@ -190,6 +191,8 @@ public class SourcesGenerator {
new GenUpgraderBaseX(genParams).run();
new GenUpgraderSuperX(genParams).run();
// Update the hash at the end
Files.writeString(hashPath, basePackageName + '\n' + useRecordBuilders + '\n' + curHash + '\n',
StandardCharsets.UTF_8, TRUNCATE_EXISTING, WRITE, CREATE);

View File

@ -51,7 +51,7 @@ public class GenDataBaseX extends ClassGenerator {
dataModel.getSuperTypesOf(base, false).forEach(superType -> {
classBuilder.addMethod(MethodSpec
.methodBuilder("getMetaId$" + superType.getName())
.addModifiers(Modifier.PUBLIC, Modifier.FINAL)
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.returns(int.class)
.addStatement("return " + superType.subTypes().indexOf(base))
@ -60,7 +60,7 @@ public class GenDataBaseX extends ClassGenerator {
var ofMethod = MethodSpec
.methodBuilder("of")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
base.getData().forEach((fieldName, fieldType) -> {
var fieldTypeName = fieldType.getJTypeName(basePackageName);

View File

@ -8,8 +8,10 @@ import com.squareup.javapoet.FieldSpec;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder;
import it.cavallium.data.generator.DataInitializer;
import it.cavallium.data.generator.DataUpgrader;
import it.cavallium.data.generator.plugin.ClassGenerator;
import it.cavallium.data.generator.plugin.ComputedType;
@ -86,10 +88,6 @@ public class GenUpgraderBaseX extends ClassGenerator {
method.addParameter(ParameterSpec.builder(typeBaseClassName, "data").addAnnotation(NotNull.class).build());
nextTypeBase.getData().forEach((fieldName, fieldType) -> {
method.addStatement("$T $N", fieldType.getJTypeName(basePackageName), fieldName);
});
List<String> expectedResultFields = nextTypeBase.getData().keySet().stream().toList();
AtomicInteger nextInitializerStaticFieldId = new AtomicInteger();
@ -122,11 +120,15 @@ public class GenUpgraderBaseX extends ClassGenerator {
var computedTypes = dataModel.getComputedTypes(nextTypeBase.getVersion());
var newFieldType = Objects.requireNonNull(computedTypes.get(fixType(newDataConfiguration.type)));
var initializerClass = ClassName.bestGuess(newDataConfiguration.initializer);
var genericInitializerClass = ParameterizedTypeName.get(ClassName.get(DataInitializer.class),
newFieldType.getJTypeName(basePackageName).box()
);
var initializerName = createInitializerStaticField(nextInitializerStaticFieldId,
initializerStaticFieldNames,
classBuilder,
initializerClass
initializerClass,
genericInitializerClass
);
return new Field(newDataConfiguration.to, newFieldType, CodeBlock.of("$N.initialize()", initializerName), i + 1);
@ -168,11 +170,16 @@ public class GenUpgraderBaseX extends ClassGenerator {
var cb = CodeBlock.builder();
var newFieldType = Objects
.requireNonNull(dataModel.getComputedTypes(version).get(fixType(upgradeDataConfiguration.type)));
var genericUpgraderClass = ParameterizedTypeName.get(ClassName.get(DataUpgrader.class),
fieldType.getJTypeName(basePackageName).box(),
newFieldType.getJTypeName(basePackageName).box()
);
var upgraderName = createUpgraderStaticField(nextUpgraderStaticFieldId,
upgraderStaticFieldNames,
classBuilder,
upgraderClass
upgraderClass,
genericUpgraderClass
);
cb.add("($T) $N.upgrade(($T) ",
@ -219,13 +226,14 @@ public class GenUpgraderBaseX extends ClassGenerator {
private String createInitializerStaticField(AtomicInteger nextInitializerStaticFieldId,
HashMap<String, String> initializerStaticFieldNames,
Builder classBuilder,
ClassName initializerClass) {
ClassName initializerClass,
TypeName genericInitializerClass) {
var ref = initializerClass.reflectionName();
var initializerName = initializerStaticFieldNames.get(ref);
if (initializerName == null) {
initializerName = "I" + nextInitializerStaticFieldId.getAndIncrement();
classBuilder.addField(FieldSpec
.builder(initializerClass, initializerName)
.builder(genericInitializerClass, initializerName)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.initializer("new $T()", initializerClass)
.build());
@ -237,13 +245,14 @@ public class GenUpgraderBaseX extends ClassGenerator {
private String createUpgraderStaticField(AtomicInteger nextUpgraderStaticFieldId,
HashMap<String, String> upgraderStaticFieldNames,
Builder classBuilder,
ClassName upgraderClass) {
ClassName upgraderClass,
TypeName genericUpgraderClass) {
var ref = upgraderClass.reflectionName();
var upgraderName = upgraderStaticFieldNames.get(ref);
if (upgraderName == null) {
upgraderName = "U" + nextUpgraderStaticFieldId.getAndIncrement();
classBuilder.addField(FieldSpec
.builder(upgraderClass, upgraderName)
.builder(genericUpgraderClass, upgraderName)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.initializer("new $T()", upgraderClass)
.build());

View File

@ -0,0 +1,98 @@
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.io.IOException;
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);
method.addException(IOException.class);
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;
}
}

View File

@ -15,6 +15,7 @@ import it.cavallium.data.generator.plugin.ClassGenerator;
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
import it.cavallium.data.generator.plugin.ComputedTypeBase;
import it.cavallium.data.generator.plugin.ComputedTypeCustom;
import it.cavallium.data.generator.plugin.ComputedTypeSuper;
import it.cavallium.data.generator.plugin.ComputedVersion;
import java.io.IOException;
import java.util.Objects;
@ -171,7 +172,8 @@ public class GenVersion extends ClassGenerator {
private void generateUpgraderInstance(ComputedVersion version, Builder classBuilder) {
var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version");
dataModel.getComputedTypes(version).forEach((typeName, type) -> {
boolean shouldCreateInstanceField = type instanceof ComputedTypeBase versionedComputedType
boolean shouldCreateInstanceField = type instanceof VersionedComputedType versionedComputedType
&& (type instanceof ComputedTypeBase || type instanceof ComputedTypeSuper)
&& versionedComputedType.getVersion().equals(version) && !version.isCurrent();
if (!shouldCreateInstanceField) {
return;