diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java index 539fd6e..a94fdf7 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedType.java @@ -1,5 +1,6 @@ package it.cavallium.data.generator.plugin; +import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.TypeName; import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType; import java.util.stream.Stream; @@ -19,6 +20,10 @@ public sealed interface ComputedType permits VersionedComputedType, ComputedType FieldLocation getJUpgraderInstance(String basePackageName); + default CodeBlock wrapWithUpgrade(String basePackageName, CodeBlock content, ComputedType next) { + return content; + } + sealed interface VersionedComputedType extends ComputedType permits ComputedTypeArrayVersioned, ComputedTypeBase, ComputedTypeNullableVersioned, ComputedTypeSuper { diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeArrayVersioned.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeArrayVersioned.java index 34cb732..d1e6165 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeArrayVersioned.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeArrayVersioned.java @@ -1,8 +1,10 @@ package it.cavallium.data.generator.plugin; import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; +import it.cavallium.data.generator.nativedata.UpgradeUtil; import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType; import java.util.List; import java.util.Objects; @@ -30,8 +32,7 @@ public final class ComputedTypeArrayVersioned implements VersionedComputedType, } @Override - public ComputedTypeArrayVersioned withChangeAtVersion(ComputedVersion version, - VersionChangeChecker versionChangeChecker) { + public ComputedTypeArrayVersioned withChangeAtVersion(ComputedVersion version, VersionChangeChecker versionChangeChecker) { return new ComputedTypeArrayVersioned(baseType.withVersion(version), computedTypeSupplier ); @@ -99,14 +100,22 @@ public final class ComputedTypeArrayVersioned implements VersionedComputedType, @Override public TypeName getJUpgraderName(String basePackageName) { - return ClassName.get(baseType.version().getUpgradersPackage(basePackageName), "Array" + baseType.type() + "Upgrader"); + throw new UnsupportedOperationException("Not upgradable"); } @Override public FieldLocation getJUpgraderInstance(String basePackageName) { - var className = ClassName.get(baseType.version().getPackage(basePackageName), "Version"); - var upgraderFieldName = "Array" + baseType.type() + "UpgraderInstance"; - return new FieldLocation(className, upgraderFieldName); + throw new UnsupportedOperationException("Not upgradable"); + } + + @Override + public CodeBlock wrapWithUpgrade(String basePackageName, CodeBlock content, ComputedType next) { + var builder = CodeBlock.builder(); + builder.add("$T.upgradeArray(", UpgradeUtil.class); + builder.add(content); + var upgraderInstance = getBase().getJUpgraderInstance(basePackageName); + builder.add(", $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName()); + return builder.build(); } @Override diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeBase.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeBase.java index 52a82d1..f9c4294 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeBase.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeBase.java @@ -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.LinkedHashMap; import java.util.Objects; @@ -39,14 +39,12 @@ public final class ComputedTypeBase implements VersionedComputedType { } @Override - public ComputedTypeBase withChangeAtVersion(ComputedVersion version, - VersionChangeChecker versionChangeChecker) { + public ComputedTypeBase withChangeAtVersion(ComputedVersion version, VersionChangeChecker versionChangeChecker) { var newData = new LinkedHashMap(); data.forEach((k, v) -> newData.put(k, v.withVersionIfChanged(version, versionChangeChecker))); return new ComputedTypeBase(type.withVersion(version), stringRepresenter, - newData, - computedTypeSupplier + newData, computedTypeSupplier ); } @@ -115,7 +113,7 @@ public final class ComputedTypeBase implements VersionedComputedType { } @Override - public TypeName getJUpgraderName(String basePackageName) { + public ClassName getJUpgraderName(String basePackageName) { return ClassName.get(type.version().getUpgradersPackage(basePackageName), type.type() + "Upgrader"); } @@ -126,6 +124,16 @@ public final class ComputedTypeBase 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 Stream getDependencies() { return this.data.values().stream().map(computedTypeSupplier::get); diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeNullableVersioned.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeNullableVersioned.java index 7f8ae94..d2f5b92 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeNullableVersioned.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ComputedTypeNullableVersioned.java @@ -1,7 +1,9 @@ package it.cavallium.data.generator.plugin; import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.TypeName; +import it.cavallium.data.generator.nativedata.UpgradeUtil; import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType; import java.util.Objects; import java.util.stream.Stream; @@ -28,8 +30,7 @@ public final class ComputedTypeNullableVersioned implements ComputedTypeNullable } @Override - public ComputedTypeNullableVersioned withChangeAtVersion(ComputedVersion version, - VersionChangeChecker versionChangeChecker) { + public ComputedTypeNullableVersioned withChangeAtVersion(ComputedVersion version, VersionChangeChecker versionChangeChecker) { return new ComputedTypeNullableVersioned(baseType.withVersion(version), computedTypeSupplier ); @@ -75,7 +76,11 @@ public final class ComputedTypeNullableVersioned implements ComputedTypeNullable @Override public TypeName getJTypeName(String basePackageName) { - return ClassName.get(baseType.version().getDataNullablesPackage(basePackageName), + return getJTypeNameOfVersion(baseType.version(), basePackageName); + } + + private TypeName getJTypeNameOfVersion(ComputedVersion version, String basePackageName) { + return ClassName.get(version.getDataNullablesPackage(basePackageName), "Nullable" + baseType.type()); } @@ -94,15 +99,23 @@ public final class ComputedTypeNullableVersioned implements ComputedTypeNullable @Override public TypeName getJUpgraderName(String basePackageName) { - return ClassName.get(baseType.version().getSerializersPackage(basePackageName), - "Nullable" + baseType.type() + "Upgrader"); + throw new UnsupportedOperationException("Not upgradable"); } @Override public FieldLocation getJUpgraderInstance(String basePackageName) { - var className = ClassName.get(baseType.version().getPackage(basePackageName), "Version"); - var upgraderFieldName = "Nullable" + baseType.type() + "UpgraderInstance"; - return new FieldLocation(className, upgraderFieldName); + throw new UnsupportedOperationException("Not upgradable"); + } + + @Override + public CodeBlock wrapWithUpgrade(String basePackageName, CodeBlock content, ComputedType next) { + var builder = CodeBlock.builder(); + var upgraderInstance = getBase().getJUpgraderInstance(basePackageName); + builder.add("new $T($T.upgradeNullable(", next.getJTypeName(basePackageName), UpgradeUtil.class); + builder.add(content); + builder.add(".value(), $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName()); + builder.add(")"); + return builder.build(); } @Override diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java index 7878835..4cc72e0 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/DataModel.java @@ -51,6 +51,7 @@ public class DataModel { private final Int2ObjectMap> computedTypes; private final Map versionedTypePrevVersion; private final Map versionedTypeNextVersion; + private final Int2ObjectMap>> baseTypeDataChanges; public DataModel(int hash, String currentVersionKey, @@ -149,6 +150,8 @@ public class DataModel { throw new IllegalArgumentException("Type " + type + " has been defined more than once (check base, super, and custom types)!"); }); + record RawVersionedType(String type, int version) {} + // Compute the numeric versions map Int2ObjectMap parsedVersions = new Int2ObjectLinkedOpenHashMap<>(); rawVersions.forEach((k, v) -> parsedVersions.put(nameToVersion.getInt(k), new ParsedVersion(v))); @@ -187,7 +190,7 @@ public class DataModel { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.transformClass); } - transformClass.differentThanPrev = true; + transformClass.addDifferentThanPrev(transformation); var definition = removeAndGetIndex(transformClass.data, t.from); if (definition.isEmpty()) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown field: " + t.from); @@ -210,7 +213,7 @@ public class DataModel { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.transformClass); } - transformClass.differentThanPrev = true; + transformClass.addDifferentThanPrev(transformation); if (!allTypes.contains(extractTypeName(t.type))) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type); } @@ -233,7 +236,7 @@ public class DataModel { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.transformClass); } - transformClass.differentThanPrev = true; + transformClass.addDifferentThanPrev(transformation); var prevDef = transformClass.data.remove(t.from); if (prevDef == null) { throw new IllegalArgumentException(transformCoordinate + " tries to remove the nonexistent field \"" @@ -247,7 +250,7 @@ public class DataModel { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.transformClass); } - transformClass.differentThanPrev = true; + transformClass.addDifferentThanPrev(transformation); if (!allTypes.contains(extractTypeName(t.type))) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type); } @@ -283,12 +286,20 @@ public class DataModel { // Compute the types Int2ObjectMap> computedTypes = new Int2ObjectLinkedOpenHashMap<>(); Int2ObjectMap> randomComputedTypes = new Int2ObjectOpenHashMap<>(); + Int2ObjectMap>> baseTypeDataChanges = new Int2ObjectOpenHashMap<>(); ComputedTypeSupplier computedTypeSupplier = new ComputedTypeSupplier(randomComputedTypes, computedVersions.get(latestVersion)); { + for (int versionIndex = 0; versionIndex <= latestVersion; versionIndex++) { + var versionChanges = new HashMap>(); + baseTypeDataChanges.put(versionIndex, versionChanges); + computedClassConfig.get(versionIndex).forEach((dataType, data) -> { + versionChanges.put(dataType, Objects.requireNonNullElse(data.differentThanPrev, List.of())); + }); + } for (int versionNumber = latestVersion - 1; versionNumber >= 0; versionNumber--) { var version = computedClassConfig.get(versionNumber); computedClassConfig.get(versionNumber + 1).forEach((type, typeConfig) -> { - if (typeConfig.differentThanPrev) { + if (typeConfig.differentThanPrev != null) { version.get(type).differentThanNext = true; } }); @@ -514,6 +525,7 @@ public class DataModel { this.computedTypes = computedTypes; this.versionedTypePrevVersion = versionedTypePrevVersion; this.versionedTypeNextVersion = versionedTypeNextVersion; + this.baseTypeDataChanges = baseTypeDataChanges; } private String tryInsertAtIndex(LinkedHashMap data, String key, String value, int index) { @@ -867,4 +879,8 @@ public class DataModel { } return Stream.of(); } + + public List getChanges(ComputedTypeBase nextType) { + return baseTypeDataChanges.get(nextType.getVersion().getVersion()).get(nextType.getName()); + } } diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java index 604468e..f0bc1e0 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/ParsedClass.java @@ -2,7 +2,9 @@ package it.cavallium.data.generator.plugin; import static it.cavallium.data.generator.plugin.DataModel.fixType; +import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; @@ -13,7 +15,7 @@ public final class ParsedClass { public String stringRepresenter; public LinkedHashMap data; - public boolean differentThanPrev; + public List differentThanPrev; public boolean differentThanNext; public ParsedClass(ClassConfiguration baseTypesData) { @@ -67,4 +69,11 @@ public final class ParsedClass { cc.data = new LinkedHashMap<>(data); return cc; } + + public void addDifferentThanPrev(TransformationConfiguration transformation) { + if (differentThanPrev == null) { + differentThanPrev = new ArrayList<>(); + } + differentThanPrev.add(transformation); + } } diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/SourcesGenerator.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/SourcesGenerator.java index 279b4f3..e1e1ec2 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/SourcesGenerator.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/SourcesGenerator.java @@ -29,6 +29,7 @@ import it.cavallium.data.generator.plugin.classgen.GenSerializerBaseX; 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.GenVersion; import it.cavallium.data.generator.plugin.classgen.GenVersions; import it.unimi.dsi.fastutil.booleans.BooleanList; @@ -187,6 +188,8 @@ public class SourcesGenerator { new GenSerializerNullableX(genParams).run(); + new GenUpgraderBaseX(genParams).run(); + // Update the hash at the end Files.writeString(hashPath, basePackageName + '\n' + useRecordBuilders + '\n' + curHash + '\n', StandardCharsets.UTF_8, TRUNCATE_EXISTING, WRITE, CREATE); diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenNullableX.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenNullableX.java index d7923f6..69a2696 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenNullableX.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenNullableX.java @@ -122,16 +122,16 @@ public class GenNullableX extends ClassGenerator { .addParameter(ParameterSpec.builder(type, "fallback").addAnnotation(NotNull.class).build()) .addStatement("return this.value == null ? fallback : this") .build()); - - classBuilder.addMethod(MethodSpec - .methodBuilder("getNullable") - .addModifiers(Modifier.PUBLIC, Modifier.FINAL) - .addAnnotation(Nullable.class) - .returns(baseType) - .addStatement("return this.value") - .build()); } + classBuilder.addMethod(MethodSpec + .methodBuilder("getNullable") + .addModifiers(Modifier.PUBLIC, Modifier.FINAL) + .addAnnotation(Nullable.class) + .returns(baseType) + .addStatement("return this.value") + .build()); + return new GeneratedClass(type.packageName(), classBuilder); } } diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenUpgraderBaseX.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenUpgraderBaseX.java new file mode 100644 index 0000000..899ac3f --- /dev/null +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenUpgraderBaseX.java @@ -0,0 +1,215 @@ +package it.cavallium.data.generator.plugin.classgen; + +import static it.cavallium.data.generator.plugin.DataModel.fixType; + +import com.squareup.javapoet.ClassName; +import com.squareup.javapoet.CodeBlock; +import com.squareup.javapoet.FieldSpec; +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.ComputedTypeBase; +import it.cavallium.data.generator.plugin.ComputedVersion; +import it.cavallium.data.generator.plugin.MoveDataConfiguration; +import it.cavallium.data.generator.plugin.NewDataConfiguration; +import it.cavallium.data.generator.plugin.RemoveDataConfiguration; +import it.cavallium.data.generator.plugin.TransformationConfiguration; +import it.cavallium.data.generator.plugin.UpgradeDataConfiguration; +import java.io.IOException; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import java.util.stream.Stream; +import javax.lang.model.element.Modifier; +import org.jetbrains.annotations.NotNull; + +public class GenUpgraderBaseX extends ClassGenerator { + + public GenUpgraderBaseX(ClassGeneratorParams params) { + super(params); + } + + @Override + protected Stream generateClasses() { + return dataModel.getVersionsSet().parallelStream().flatMap(this::generateVersionClasses); + } + + private Stream generateVersionClasses(ComputedVersion version) { + return dataModel + .getBaseTypesComputed(version) + .filter(type -> !type.getVersion().isCurrent() && type.getVersion().equals(version)) + .map(type -> generateTypeVersioned(version, type)); + } + + private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeBase typeBase) { + ClassName upgraderClassName = typeBase.getJUpgraderName(basePackageName); + ClassName typeBaseClassName = typeBase.getJTypeName(basePackageName); + ComputedTypeBase nextTypeBase = dataModel.getNextVersion(typeBase); + + var classBuilder = TypeSpec.classBuilder(upgraderClassName.simpleName()); + + classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL); + + classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataUpgrader.class), + typeBaseClassName, + nextTypeBase.getJTypeName(basePackageName) + )); + + generateUpgradeMethod(version, typeBase, nextTypeBase, classBuilder); + + return new GeneratedClass(upgraderClassName.packageName(), classBuilder); + } + + private void generateUpgradeMethod(ComputedVersion version, ComputedTypeBase typeBase, + ComputedTypeBase nextTypeBase, + Builder classBuilder) { + var method = MethodSpec.methodBuilder("upgrade"); + + method.addModifiers(Modifier.PUBLIC, Modifier.FINAL); + method.addException(IOException.class); + + ClassName typeBaseClassName = typeBase.getJTypeName(basePackageName); + ClassName nextTypeBaseClassName = nextTypeBase.getJTypeName(basePackageName); + method.returns(nextTypeBaseClassName); + method.addAnnotation(NotNull.class); + + method.addParameter(ParameterSpec.builder(typeBaseClassName, "data").addAnnotation(NotNull.class).build()); + + nextTypeBase.getData().forEach((fieldName, fieldType) -> { + method.addStatement("$T $N", fieldType.getJTypeName(basePackageName), fieldName); + }); + + List expectedResultFields = nextTypeBase.getData().keySet().stream().toList(); + + AtomicInteger nextInitializerStaticFieldId = new AtomicInteger(); + HashMap initializerStaticFieldNames = new HashMap<>(); + List transformations = dataModel.getChanges(nextTypeBase); + method.addCode("return new $T(\n$>", nextTypeBaseClassName); + record ResultField(String name, ComputedType type, CodeBlock code) {} + Stream resultFields; + if (transformations.isEmpty()) { + resultFields = typeBase + .getData() + .entrySet() + .stream() + .map(e -> new ResultField(e.getKey(), e.getValue(), CodeBlock.of("data.$N()", e.getKey()))); + } else { + record Field(String name, ComputedType type, CodeBlock code, int processFromTx) {} + var fields = Stream.concat( + typeBase.getData().entrySet().stream() + .map(e -> new Field(e.getKey(), e.getValue(), CodeBlock.of("data.$N()", e.getKey()), 0)), + IntStream + .range(0, transformations.size()) + .mapToObj(i -> Map.entry(i, transformations.get(i))) + .filter(t -> t.getValue() instanceof NewDataConfiguration) + .map(t -> Map.entry(t.getKey(), (NewDataConfiguration) t.getValue())) + .map(e -> { + var i = e.getKey(); + var newDataConfiguration = e.getValue(); + var computedTypes = dataModel.getComputedTypes(version); + var newFieldType = Objects.requireNonNull(computedTypes.get(fixType(newDataConfiguration.type))); + var initializerClass = ClassName.bestGuess(newDataConfiguration.initializer); + + var initializerName = createInitializerStaticField(nextInitializerStaticFieldId, + initializerStaticFieldNames, + classBuilder, + initializerClass + ); + + return new Field(newDataConfiguration.to, newFieldType, CodeBlock.of("$N", initializerName), i); + }) + ); + resultFields = fields.mapMulti((field, consumer) -> { + String fieldName = field.name(); + ComputedType fieldType = field.type(); + CodeBlock codeBlock = CodeBlock.of("data.$N()", fieldName); + for (TransformationConfiguration transformation : transformations.subList(field.processFromTx(), + transformations.size() + )) { + if (transformation instanceof MoveDataConfiguration moveDataConfiguration) { + if (!moveDataConfiguration.from.equals(fieldName)) { + continue; + } + fieldName = moveDataConfiguration.to; + } else if (transformation instanceof NewDataConfiguration newDataConfiguration) { + continue; + } else if (transformation instanceof RemoveDataConfiguration removeDataConfiguration) { + if (!removeDataConfiguration.from.equals(fieldName)) { + continue; + } + return; + } else if (transformation instanceof UpgradeDataConfiguration upgradeDataConfiguration) { + if (!upgradeDataConfiguration.from.equals(fieldName)) { + continue; + } + var upgraderClass = ClassName.bestGuess(upgradeDataConfiguration.upgrader); + var cb = CodeBlock.builder(); + var newFieldType = Objects + .requireNonNull(dataModel.getComputedTypes(version).get(fixType(upgradeDataConfiguration.type))); + cb.add("($T) $T.upgrade(($T) ", + newFieldType.getJTypeName(basePackageName), + upgraderClass, + fieldType.getJTypeName(basePackageName) + ); + cb.add(codeBlock); + cb.add(")"); + codeBlock = cb.build(); + fieldType = newFieldType; + } else { + throw new UnsupportedOperationException("Unsupported transformation type: " + transformation); + } + } + consumer.accept(new ResultField(fieldName, fieldType, codeBlock)); + }).sorted(Comparator.comparingInt(f -> expectedResultFields.indexOf(f.name()))); + } + resultFields + .flatMap(e -> Stream.of(CodeBlock.of(",\n"), upgradeFieldToType(e.name(), e.type(), e.code(), nextTypeBase))) + .skip(1) + .forEach(method::addCode); + method.addCode("\n$<);\n"); + + classBuilder.addMethod(method.build()); + } + + private String createInitializerStaticField(AtomicInteger nextInitializerStaticFieldId, + HashMap initializerStaticFieldNames, + Builder classBuilder, + ClassName initializerClass) { + var ref = initializerClass.reflectionName(); + var initializerName = initializerStaticFieldNames.get(ref); + if (initializerName == null) { + initializerName = "I" + nextInitializerStaticFieldId.getAndIncrement(); + classBuilder.addField(FieldSpec.builder(initializerClass, initializerName).initializer("new $T()", initializerClass).build()); + initializerStaticFieldNames.put(ref, initializerName); + } + return initializerName; + } + + private CodeBlock upgradeFieldToType(String fieldName, + ComputedType fieldType, + CodeBlock codeBlock, + ComputedTypeBase nextTypeBase) { + while (fieldType instanceof VersionedComputedType versionedComputedType + && versionedComputedType.getVersion().compareTo(nextTypeBase.getVersion()) < 0) { + var currentFieldType = fieldType; + var nextFieldType = dataModel.getNextVersion(currentFieldType); + codeBlock = currentFieldType.wrapWithUpgrade(basePackageName, codeBlock, nextFieldType); + fieldType = nextFieldType; + } + return codeBlock; + } + + private String getFieldVarName(int totalTransformations, int transformationId) { + return null; + } +} diff --git a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenVersion.java b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenVersion.java index 29fd577..62b1a82 100644 --- a/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenVersion.java +++ b/data-generator-plugin/src/main/java/it/cavallium/data/generator/plugin/classgen/GenVersion.java @@ -13,6 +13,7 @@ import it.cavallium.data.generator.DataSerializer; import it.cavallium.data.generator.DataUpgrader; 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.ComputedVersion; import java.io.IOException; @@ -170,7 +171,7 @@ 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 VersionedComputedType versionedComputedType + boolean shouldCreateInstanceField = type instanceof ComputedTypeBase versionedComputedType && versionedComputedType.getVersion().equals(version) && !version.isCurrent(); if (!shouldCreateInstanceField) { return; diff --git a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/INullable.java b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/INullable.java index 7898213..a4fb8c6 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/INullable.java +++ b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/INullable.java @@ -1,5 +1,5 @@ package it.cavallium.data.generator.nativedata; public interface INullable { - Object $getNullable(); + Object getNullable(); } diff --git a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableInt52.java b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableInt52.java index d6bdae8..c5d60b4 100644 --- a/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableInt52.java +++ b/data-generator-runtime/src/main/java/it/cavallium/data/generator/nativedata/NullableInt52.java @@ -86,10 +86,6 @@ public class NullableInt52 implements Serializable, INullable, TypedNullable List upgradeArray(List from, DataUpgrader upgrader) + throws IOException { + Object[] array; + if (from instanceof ImmutableWrappedArrayList immutableWrappedArrayList) { + array = immutableWrappedArrayList.a; + } else { + array = from.toArray(); + } + for (int i = 0; i < array.length; i++) { + array[i] = (B) upgrader.upgrade((A) array[i]); + } + return (ImmutableWrappedArrayList) new ImmutableWrappedArrayList<>(array); + } + + public static B upgradeNullable(A nullableValue, DataUpgrader upgrader) throws IOException { + if (nullableValue == null) { + return null; + } else { + return upgrader.upgrade(nullableValue); + } + } +}