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; package it.cavallium.data.generator.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.TypeName; import com.squareup.javapoet.CodeBlock;
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType; import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -110,7 +110,7 @@ public final class ComputedTypeSuper implements VersionedComputedType {
} }
@Override @Override
public TypeName getJUpgraderName(String basePackageName) { public ClassName getJUpgraderName(String basePackageName) {
return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Upgrader"); 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); 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 @Override
public String toString() { public String toString() {
return type.type() + " (super, v" + getVersion() + ")"; 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.GenSerializerSuperX;
import it.cavallium.data.generator.plugin.classgen.GenSuperType; import it.cavallium.data.generator.plugin.classgen.GenSuperType;
import it.cavallium.data.generator.plugin.classgen.GenUpgraderBaseX; 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.GenVersion;
import it.cavallium.data.generator.plugin.classgen.GenVersions; import it.cavallium.data.generator.plugin.classgen.GenVersions;
import it.unimi.dsi.fastutil.booleans.BooleanList; import it.unimi.dsi.fastutil.booleans.BooleanList;
@ -190,6 +191,8 @@ public class SourcesGenerator {
new GenUpgraderBaseX(genParams).run(); new GenUpgraderBaseX(genParams).run();
new GenUpgraderSuperX(genParams).run();
// Update the hash at the end // Update the hash at the end
Files.writeString(hashPath, basePackageName + '\n' + useRecordBuilders + '\n' + curHash + '\n', Files.writeString(hashPath, basePackageName + '\n' + useRecordBuilders + '\n' + curHash + '\n',
StandardCharsets.UTF_8, TRUNCATE_EXISTING, WRITE, CREATE); StandardCharsets.UTF_8, TRUNCATE_EXISTING, WRITE, CREATE);

View File

@ -51,7 +51,7 @@ public class GenDataBaseX extends ClassGenerator {
dataModel.getSuperTypesOf(base, false).forEach(superType -> { dataModel.getSuperTypesOf(base, false).forEach(superType -> {
classBuilder.addMethod(MethodSpec classBuilder.addMethod(MethodSpec
.methodBuilder("getMetaId$" + superType.getName()) .methodBuilder("getMetaId$" + superType.getName())
.addModifiers(Modifier.PUBLIC, Modifier.FINAL) .addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class) .addAnnotation(Override.class)
.returns(int.class) .returns(int.class)
.addStatement("return " + superType.subTypes().indexOf(base)) .addStatement("return " + superType.subTypes().indexOf(base))
@ -60,7 +60,7 @@ public class GenDataBaseX extends ClassGenerator {
var ofMethod = MethodSpec var ofMethod = MethodSpec
.methodBuilder("of") .methodBuilder("of")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL); .addModifiers(Modifier.PUBLIC, Modifier.STATIC);
base.getData().forEach((fieldName, fieldType) -> { base.getData().forEach((fieldName, fieldType) -> {
var fieldTypeName = fieldType.getJTypeName(basePackageName); 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.MethodSpec;
import com.squareup.javapoet.ParameterSpec; import com.squareup.javapoet.ParameterSpec;
import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec;
import com.squareup.javapoet.TypeSpec.Builder; import com.squareup.javapoet.TypeSpec.Builder;
import it.cavallium.data.generator.DataInitializer;
import it.cavallium.data.generator.DataUpgrader; import it.cavallium.data.generator.DataUpgrader;
import it.cavallium.data.generator.plugin.ClassGenerator; import it.cavallium.data.generator.plugin.ClassGenerator;
import it.cavallium.data.generator.plugin.ComputedType; 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()); 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(); List<String> expectedResultFields = nextTypeBase.getData().keySet().stream().toList();
AtomicInteger nextInitializerStaticFieldId = new AtomicInteger(); AtomicInteger nextInitializerStaticFieldId = new AtomicInteger();
@ -122,11 +120,15 @@ public class GenUpgraderBaseX extends ClassGenerator {
var computedTypes = dataModel.getComputedTypes(nextTypeBase.getVersion()); var computedTypes = dataModel.getComputedTypes(nextTypeBase.getVersion());
var newFieldType = Objects.requireNonNull(computedTypes.get(fixType(newDataConfiguration.type))); var newFieldType = Objects.requireNonNull(computedTypes.get(fixType(newDataConfiguration.type)));
var initializerClass = ClassName.bestGuess(newDataConfiguration.initializer); var initializerClass = ClassName.bestGuess(newDataConfiguration.initializer);
var genericInitializerClass = ParameterizedTypeName.get(ClassName.get(DataInitializer.class),
newFieldType.getJTypeName(basePackageName).box()
);
var initializerName = createInitializerStaticField(nextInitializerStaticFieldId, var initializerName = createInitializerStaticField(nextInitializerStaticFieldId,
initializerStaticFieldNames, initializerStaticFieldNames,
classBuilder, classBuilder,
initializerClass initializerClass,
genericInitializerClass
); );
return new Field(newDataConfiguration.to, newFieldType, CodeBlock.of("$N.initialize()", initializerName), i + 1); 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 cb = CodeBlock.builder();
var newFieldType = Objects var newFieldType = Objects
.requireNonNull(dataModel.getComputedTypes(version).get(fixType(upgradeDataConfiguration.type))); .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, var upgraderName = createUpgraderStaticField(nextUpgraderStaticFieldId,
upgraderStaticFieldNames, upgraderStaticFieldNames,
classBuilder, classBuilder,
upgraderClass upgraderClass,
genericUpgraderClass
); );
cb.add("($T) $N.upgrade(($T) ", cb.add("($T) $N.upgrade(($T) ",
@ -219,13 +226,14 @@ public class GenUpgraderBaseX extends ClassGenerator {
private String createInitializerStaticField(AtomicInteger nextInitializerStaticFieldId, private String createInitializerStaticField(AtomicInteger nextInitializerStaticFieldId,
HashMap<String, String> initializerStaticFieldNames, HashMap<String, String> initializerStaticFieldNames,
Builder classBuilder, Builder classBuilder,
ClassName initializerClass) { ClassName initializerClass,
TypeName genericInitializerClass) {
var ref = initializerClass.reflectionName(); var ref = initializerClass.reflectionName();
var initializerName = initializerStaticFieldNames.get(ref); var initializerName = initializerStaticFieldNames.get(ref);
if (initializerName == null) { if (initializerName == null) {
initializerName = "I" + nextInitializerStaticFieldId.getAndIncrement(); initializerName = "I" + nextInitializerStaticFieldId.getAndIncrement();
classBuilder.addField(FieldSpec classBuilder.addField(FieldSpec
.builder(initializerClass, initializerName) .builder(genericInitializerClass, initializerName)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.initializer("new $T()", initializerClass) .initializer("new $T()", initializerClass)
.build()); .build());
@ -237,13 +245,14 @@ public class GenUpgraderBaseX extends ClassGenerator {
private String createUpgraderStaticField(AtomicInteger nextUpgraderStaticFieldId, private String createUpgraderStaticField(AtomicInteger nextUpgraderStaticFieldId,
HashMap<String, String> upgraderStaticFieldNames, HashMap<String, String> upgraderStaticFieldNames,
Builder classBuilder, Builder classBuilder,
ClassName upgraderClass) { ClassName upgraderClass,
TypeName genericUpgraderClass) {
var ref = upgraderClass.reflectionName(); var ref = upgraderClass.reflectionName();
var upgraderName = upgraderStaticFieldNames.get(ref); var upgraderName = upgraderStaticFieldNames.get(ref);
if (upgraderName == null) { if (upgraderName == null) {
upgraderName = "U" + nextUpgraderStaticFieldId.getAndIncrement(); upgraderName = "U" + nextUpgraderStaticFieldId.getAndIncrement();
classBuilder.addField(FieldSpec classBuilder.addField(FieldSpec
.builder(upgraderClass, upgraderName) .builder(genericUpgraderClass, upgraderName)
.addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL) .addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL)
.initializer("new $T()", upgraderClass) .initializer("new $T()", upgraderClass)
.build()); .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.ComputedType.VersionedComputedType;
import it.cavallium.data.generator.plugin.ComputedTypeBase; import it.cavallium.data.generator.plugin.ComputedTypeBase;
import it.cavallium.data.generator.plugin.ComputedTypeCustom; import it.cavallium.data.generator.plugin.ComputedTypeCustom;
import it.cavallium.data.generator.plugin.ComputedTypeSuper;
import it.cavallium.data.generator.plugin.ComputedVersion; import it.cavallium.data.generator.plugin.ComputedVersion;
import java.io.IOException; import java.io.IOException;
import java.util.Objects; import java.util.Objects;
@ -171,7 +172,8 @@ public class GenVersion extends ClassGenerator {
private void generateUpgraderInstance(ComputedVersion version, Builder classBuilder) { private void generateUpgraderInstance(ComputedVersion version, Builder classBuilder) {
var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version"); var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version");
dataModel.getComputedTypes(version).forEach((typeName, type) -> { 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(); && versionedComputedType.getVersion().equals(version) && !version.isCurrent();
if (!shouldCreateInstanceField) { if (!shouldCreateInstanceField) {
return; return;