From 5afe3017500d3d6993c7481d39c4fa74c94ef171 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Mon, 2 Sep 2024 12:47:49 +0200 Subject: [PATCH] Add data inizializer/upgrader declarative context parameters --- datagen-plugin/pom.xml | 2 +- .../cavallium/datagen/plugin/DataModel.java | 88 ++++---------- .../datagen/plugin/MoveDataConfiguration.java | 3 + .../datagen/plugin/NewDataConfiguration.java | 15 ++- .../cavallium/datagen/plugin/ParsedClass.java | 108 ++++++++++++++++-- .../datagen/plugin/SourcesGenerator.java | 2 +- .../plugin/UpgradeDataConfiguration.java | 16 ++- .../plugin/classgen/GenUpgraderBaseX.java | 100 ++++++++++++---- .../plugin/classgen/GenUpgraderSuperX.java | 3 +- .../datagen/plugin/classgen/GenVersion.java | 3 +- .../it/cavallium/datagen/DataContext.java | 4 + .../it/cavallium/datagen/DataContextNone.java | 9 ++ .../it/cavallium/datagen/DataInitializer.java | 4 +- .../datagen/DataInitializerSimple.java | 13 +++ .../it/cavallium/datagen/DataUpgrader.java | 4 +- .../cavallium/datagen/DataUpgraderSimple.java | 13 +++ .../datagen/nativedata/UpgradeUtil.java | 20 +++- 17 files changed, 295 insertions(+), 112 deletions(-) create mode 100644 datagen/src/main/java/it/cavallium/datagen/DataContext.java create mode 100644 datagen/src/main/java/it/cavallium/datagen/DataContextNone.java create mode 100644 datagen/src/main/java/it/cavallium/datagen/DataInitializerSimple.java create mode 100644 datagen/src/main/java/it/cavallium/datagen/DataUpgraderSimple.java diff --git a/datagen-plugin/pom.xml b/datagen-plugin/pom.xml index f8d5985..9bd04ee 100644 --- a/datagen-plugin/pom.xml +++ b/datagen-plugin/pom.xml @@ -82,7 +82,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.10.1 + 3.11.0 21 UTF-8 diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/DataModel.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/DataModel.java index 52b25b8..dbd08aa 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/DataModel.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/DataModel.java @@ -159,7 +159,7 @@ public class DataModel { .stream() .filter(x -> x.size() > 1) .forEach(x -> { - var type = x.get(0); + var type = x.getFirst(); throw new IllegalArgumentException("Type " + type + " has been defined more than once (check base, super, and custom types)!"); }); @@ -209,28 +209,19 @@ public class DataModel { + t.transformClass); } transformClass.addDifferentThanPrev(transformation); - var definition = removeAndGetIndex(transformClass.data, t.from); + var definition = transformClass.remove(t.from); if (definition.isEmpty()) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown field: " + t.from); } - String prevDef; - if (t.index != null) { - prevDef = tryInsertAtIndex(transformClass.data, - t.to, - definition.get().getValue(), - t.index - ); - } else { - prevDef = tryInsertAtIndex(transformClass.data, - t.to, - definition.get().getValue(), - definition.get().getKey() - ); - } + ParsedClass.FieldInfo prevDef = transformClass.insert( + Objects.requireNonNullElse(t.index, definition.get().getKey()), + t.to, + new ParsedClass.InputFieldInfo(definition.get().getValue().typeName(), List.of()) + ); if (prevDef != null) { throw new IllegalArgumentException( transformCoordinate + " tries to overwrite the existing field \"" + t.to + "\" of value \"" - + prevDef + "\" with the field \"" + t.from + "\" of type \"" + definition.orElse(null) + "\""); + + prevDef.typeName() + "\" with the field \"" + t.from + "\" of type \"" + definition.orElse(null) + "\""); } } case "new-data" -> { @@ -244,15 +235,12 @@ public class DataModel { if (!allTypes.contains(extractTypeName(t.type))) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type); } - String prevDef; - if (t.index != null) { - prevDef = tryInsertAtIndex(transformClass.data, t.to, fixType(t.type), t.index); - } else { - prevDef = transformClass.data.putIfAbsent(t.to, fixType(t.type)); - } + var type = fixType(t.type); + var fieldInfo = new ParsedClass.InputFieldInfo(type, t.getContextParameters()); + ParsedClass.FieldInfo prevDef = transformClass.insert(t.index, t.to, fieldInfo); if (prevDef != null) { throw new IllegalArgumentException(transformCoordinate + " tries to overwrite the existing field \"" - + t.to + "\" of value \"" + prevDef + + t.to + "\" of value \"" + prevDef.typeName() + "\" with the new type \"" + t.type + "\""); } } @@ -281,7 +269,7 @@ public class DataModel { if (!allTypes.contains(extractTypeName(t.type))) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown type: " + t.type); } - String prevDefinition = transformClass.data.replace(t.from, fixType(t.type)); + var prevDefinition = transformClass.replace(t.from, new ParsedClass.InputFieldInfo(fixType(t.type), t.getContextParameters())); if (prevDefinition == null) { throw new IllegalArgumentException(transformCoordinate + " refers to an unknown field: " + t.from); } @@ -340,7 +328,7 @@ public class DataModel { List versionBaseTypes = computedClassConfig.get(versionIndexF).entrySet().stream() .map(e -> { var data = new LinkedHashMap(); - e.getValue().getData().forEach((key, value) -> data.put(key, new VersionedType(value, version))); + e.getValue().getData().forEach((key, value) -> data.put(key, new VersionedType(value.typeName(), version))); return new ComputedTypeBase(new VersionedType(e.getKey(), version), e.getValue().stringRepresenter, data, computedTypeSupplier); }).collect(Collectors.toList()); @@ -357,8 +345,8 @@ public class DataModel { var nullableRawTypes = computedClassConfig.values().stream() .flatMap(x -> x.values().stream()) .flatMap(x -> x.getData().values().stream()) - .filter(x -> x.startsWith("-")) - .map(nullableName -> nullableName.substring(1)) + .filter(x -> x.typeName().startsWith("-")) + .map(nullableName -> nullableName.typeName().substring(1)) .toList(); // Compute nullable versioned types nullableRawTypes.stream() @@ -383,8 +371,8 @@ public class DataModel { var arrayRawTypes = computedClassConfig.values().stream() .flatMap(x -> x.values().stream()) .flatMap(x -> x.getData().values().stream()) - .filter(x -> x.startsWith("§")) - .map(nullableName -> nullableName.substring(1)) + .filter(x -> x.typeName().startsWith("§")) + .map(nullableName -> nullableName.typeName().substring(1)) .toList(); // Compute array versioned types arrayRawTypes.stream() @@ -450,7 +438,7 @@ public class DataModel { .entrySet() .stream() .collect(Collectors.toMap(Entry::getKey, e -> { - var fieldTypeName = e.getValue(); + var fieldTypeName = e.getValue().typeName(); return new VersionedType(fieldTypeName, computedVersions.get(currentOrNewerTypeVersion.getInt(fieldTypeName))); }, (a, b) -> { throw new IllegalStateException(); @@ -591,40 +579,6 @@ public class DataModel { this.baseTypeDataChanges = baseTypeDataChanges; } - private String tryInsertAtIndex(LinkedHashMap data, String key, String value, int index) { - var before = new LinkedHashMap(); - var after = new LinkedHashMap(); - int i = 0; - for (Entry entry : data.entrySet()) { - if (i < index) { - before.put(entry.getKey(), entry.getValue()); - } else { - after.put(entry.getKey(), entry.getValue()); - } - i++; - } - data.clear(); - data.putAll(before); - var prev = data.putIfAbsent(key, value); - data.putAll(after); - return prev; - } - - private Optional> removeAndGetIndex(LinkedHashMap data, String find) { - int foundIndex = -1; - { - int i = 0; - for (Entry entry : data.entrySet()) { - if (entry.getKey().equals(find)) { - foundIndex = i; - } - i++; - } - } - if (foundIndex == -1) return Optional.empty(); - return Optional.of(Map.entry(foundIndex, requireNonNull(data.remove(find)))); - } - @Nullable public static String getNextVersion(Map versionsSequence, String version) { return versionsSequence.get(version); @@ -650,7 +604,7 @@ public class DataModel { if (list.size() != 1) { throw exceptionGenerator.apply(list); } - return list.get(0); + return list.getFirst(); } ); } @@ -669,7 +623,7 @@ public class DataModel { if (list.isEmpty()) { return Optional.empty(); } - return Optional.of(list.get(0)); + return Optional.of(list.getFirst()); } ); } diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/MoveDataConfiguration.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/MoveDataConfiguration.java index fdd9d8e..d864b71 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/MoveDataConfiguration.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/MoveDataConfiguration.java @@ -1,6 +1,9 @@ package it.cavallium.datagen.plugin; +import java.util.List; import java.util.Objects; + +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public final class MoveDataConfiguration implements TransformationConfiguration { diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/NewDataConfiguration.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/NewDataConfiguration.java index e40ffb7..26e0974 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/NewDataConfiguration.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/NewDataConfiguration.java @@ -1,6 +1,9 @@ package it.cavallium.datagen.plugin; +import java.util.List; import java.util.Objects; + +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class NewDataConfiguration implements TransformationConfiguration { @@ -12,6 +15,8 @@ public class NewDataConfiguration implements TransformationConfiguration { public String initializerInstance; @Nullable public Integer index; + @Nullable + public List contextParameters; @Override public String getTransformClass() { @@ -27,6 +32,11 @@ public class NewDataConfiguration implements TransformationConfiguration { return JInterfaceLocation.parse(initializer, initializerInstance); } + @NotNull + public List getContextParameters() { + return Objects.requireNonNullElse(contextParameters, List.of()); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -39,7 +49,8 @@ public class NewDataConfiguration implements TransformationConfiguration { return Objects.equals(transformClass, that.transformClass) && Objects.equals(to, that.to) && Objects.equals(type, that.type) && Objects.equals(initializer, that.initializer) && Objects.equals(initializerInstance, that.initializerInstance) - && Objects.equals(index, that.index); + && Objects.equals(index, that.index) + && Objects.equals(contextParameters, that.contextParameters); } @Override @@ -51,6 +62,7 @@ public class NewDataConfiguration implements TransformationConfiguration { hash += ConfigUtils.hashCode(initializer); hash += ConfigUtils.hashCode(initializerInstance); hash += ConfigUtils.hashCode(index); + hash += ConfigUtils.hashCode(contextParameters); return hash; } @@ -62,6 +74,7 @@ public class NewDataConfiguration implements TransformationConfiguration { if (this.to != null) c.to = this.to; if (this.type != null) c.type = this.type; if (this.index != null) c.index = this.index; + if (this.contextParameters != null) c.contextParameters = this.contextParameters; return c; } } diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/ParsedClass.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/ParsedClass.java index fce005d..c0ae03d 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/ParsedClass.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/ParsedClass.java @@ -1,20 +1,26 @@ package it.cavallium.datagen.plugin; -import static it.cavallium.datagen.plugin.DataModel.fixType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import static it.cavallium.datagen.plugin.DataModel.fixType; +import static it.cavallium.datagen.plugin.DataModel.joinPackage; +import static java.util.Objects.requireNonNull; + +import java.util.*; import java.util.Map.Entry; -import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; public final class ParsedClass { + public record InputFieldInfo(@NotNull String typeName, @NotNull List contextParams) {} + + public record FieldInfo(@NotNull String typeName, @NotNull LinkedHashMap contextFieldsData) {} + public String stringRepresenter; - public LinkedHashMap data; + public LinkedHashMap data; public List differentThanPrev; public boolean differentThanNext; @@ -23,9 +29,11 @@ public final class ParsedClass { if (baseTypesData.data != null) { this.data = baseTypesData.data.entrySet().stream() .map(e -> Map.entry(e.getKey(), fixType(e.getValue()))) - .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (a, b) -> { - throw new IllegalStateException(); - }, LinkedHashMap::new)); + .collect(Collectors.toMap(Entry::getKey, + v -> new FieldInfo(v.getValue(), + new LinkedHashMap<>(0)), + (a, b) -> {throw new IllegalStateException();}, + LinkedHashMap::new)); } } @@ -37,7 +45,7 @@ public final class ParsedClass { return stringRepresenter; } - public LinkedHashMap getData() { + public LinkedHashMap getData() { return data; } @@ -76,4 +84,82 @@ public final class ParsedClass { } differentThanPrev.add(transformation); } + + public static final class NoContextParameterException extends RuntimeException { + private final String contextParameter; + + public NoContextParameterException(String contextParameter) { + this.contextParameter = contextParameter; + } + + public String getContextParameter() { + return contextParameter; + } + } + + private static LinkedHashMap computeContextParametersTypes( + LinkedHashMap data, @NotNull List contextParameters) + throws NoContextParameterException { + return contextParameters.stream().collect(Collectors.toMap(Function.identity(), param -> { + var type = data.get(param); + if (type == null) { + throw new NoContextParameterException(param); + } + return type.typeName(); + }, (c, a) -> { + throw new IllegalStateException("Unreachable"); + }, LinkedHashMap::new)); + } + + public FieldInfo insert(@Nullable Integer index, String to, InputFieldInfo fieldInfo) throws NoContextParameterException { + var value = convertFieldInfo(fieldInfo); + if (index == null) { + return data.putIfAbsent(to, value); + } else { + return tryInsertAtIndex(data, to, value, index); + } + } + + public Optional> remove(String find) { + int foundIndex = -1; + { + int i = 0; + for (var entry : data.entrySet()) { + if (entry.getKey().equals(find)) { + foundIndex = i; + } + i++; + } + } + if (foundIndex == -1) return Optional.empty(); + return Optional.of(Map.entry(foundIndex, requireNonNull(data.remove(find)))); + } + + public FieldInfo replace(String from, InputFieldInfo fieldInfo) { + return data.replace(from, convertFieldInfo(fieldInfo)); + } + + private FieldInfo convertFieldInfo(InputFieldInfo fieldInfo) { + return new FieldInfo(fieldInfo.typeName, computeContextParametersTypes(data, fieldInfo.contextParams)); + } + + private static ParsedClass.FieldInfo tryInsertAtIndex(LinkedHashMap data, String key, + FieldInfo value, int index) { + var before = new LinkedHashMap(index); + var after = new LinkedHashMap(data.size() - index); + int i = 0; + for (Entry entry : data.entrySet()) { + if (i < index) { + before.put(entry.getKey(), entry.getValue()); + } else { + after.put(entry.getKey(), entry.getValue()); + } + i++; + } + data.clear(); + data.putAll(before); + var prev = data.putIfAbsent(key, value); + data.putAll(after); + return prev; + } } diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/SourcesGenerator.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/SourcesGenerator.java index ea44e0b..c07c14c 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/SourcesGenerator.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/SourcesGenerator.java @@ -405,7 +405,7 @@ public class SourcesGenerator { return i; } - private String capitalize(String field) { + public static String capitalize(String field) { return Character.toUpperCase(field.charAt(0)) + field.substring(1); } diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/UpgradeDataConfiguration.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/UpgradeDataConfiguration.java index b03041c..b06e176 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/UpgradeDataConfiguration.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/UpgradeDataConfiguration.java @@ -1,5 +1,9 @@ package it.cavallium.datagen.plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; import java.util.Objects; public class UpgradeDataConfiguration implements TransformationConfiguration { @@ -9,6 +13,8 @@ public class UpgradeDataConfiguration implements TransformationConfiguration { public String type; public String upgrader; public String upgraderInstance; + @Nullable + public List contextParameters; @Override public String getTransformClass() { @@ -24,6 +30,11 @@ public class UpgradeDataConfiguration implements TransformationConfiguration { return JInterfaceLocation.parse(upgrader, upgraderInstance); } + @NotNull + public List getContextParameters() { + return Objects.requireNonNullElse(contextParameters, List.of()); + } + @Override public boolean equals(Object o) { if (this == o) { @@ -35,7 +46,8 @@ public class UpgradeDataConfiguration implements TransformationConfiguration { UpgradeDataConfiguration that = (UpgradeDataConfiguration) o; return Objects.equals(transformClass, that.transformClass) && Objects.equals(from, that.from) && Objects.equals(type, that.type) && Objects.equals(upgrader, that.upgrader) - && Objects.equals(upgraderInstance, that.upgraderInstance); + && Objects.equals(upgraderInstance, that.upgraderInstance) + && Objects.equals(contextParameters, that.contextParameters); } @Override @@ -46,6 +58,7 @@ public class UpgradeDataConfiguration implements TransformationConfiguration { hash += ConfigUtils.hashCode(type); hash += ConfigUtils.hashCode(upgrader); hash += ConfigUtils.hashCode(upgraderInstance); + hash += ConfigUtils.hashCode(contextParameters); return hash; } @@ -56,6 +69,7 @@ public class UpgradeDataConfiguration implements TransformationConfiguration { if (this.type != null) c.type = this.type; if (this.upgrader != null) c.upgrader = this.upgrader; if (this.upgraderInstance != null) c.upgraderInstance = this.upgraderInstance; + if (this.contextParameters != null) c.contextParameters = this.contextParameters; return c; } } diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderBaseX.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderBaseX.java index d5dd7e7..0e37736 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderBaseX.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderBaseX.java @@ -9,22 +9,12 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec.Builder; -import it.cavallium.datagen.DataInitializer; -import it.cavallium.datagen.DataUpgrader; -import it.cavallium.datagen.plugin.ClassGenerator; -import it.cavallium.datagen.plugin.ComputedType; +import it.cavallium.datagen.*; +import it.cavallium.datagen.plugin.*; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; -import it.cavallium.datagen.plugin.ComputedTypeBase; -import it.cavallium.datagen.plugin.ComputedVersion; -import it.cavallium.datagen.plugin.JInterfaceLocation; import it.cavallium.datagen.plugin.JInterfaceLocation.JInterfaceLocationClassName; import it.cavallium.datagen.plugin.JInterfaceLocation.JInterfaceLocationInstanceField; -import it.cavallium.datagen.plugin.MoveDataConfiguration; -import it.cavallium.datagen.plugin.NewDataConfiguration; -import it.cavallium.datagen.plugin.RemoveDataConfiguration; -import it.cavallium.datagen.plugin.TransformationConfiguration; -import it.cavallium.datagen.plugin.UpgradeDataConfiguration; -import it.cavallium.datagen.plugin.DataModel; + import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -36,6 +26,7 @@ import java.util.stream.IntStream; import java.util.stream.Stream; import javax.lang.model.element.Modifier; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class GenUpgraderBaseX extends ClassGenerator { @@ -64,7 +55,7 @@ public class GenUpgraderBaseX extends ClassGenerator { classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL); - classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataUpgrader.class), + classBuilder.superclass(ParameterizedTypeName.get(ClassName.get(DataUpgraderSimple.class), typeBaseClassName, nextTypeBase.getJTypeName(basePackageName) )); @@ -92,6 +83,7 @@ public class GenUpgraderBaseX extends ClassGenerator { AtomicInteger nextInitializerStaticFieldId = new AtomicInteger(); HashMap initializerStaticFieldNames = new HashMap<>(); + HashMap contextStaticFieldCodeBlocks = new HashMap<>(); AtomicInteger nextUpgraderStaticFieldId = new AtomicInteger(); HashMap upgraderStaticFieldNames = new HashMap<>(); List transformations = dataModel.getChanges(nextTypeBase); @@ -120,7 +112,16 @@ public class GenUpgraderBaseX extends ClassGenerator { var computedTypes = dataModel.getComputedTypes(nextTypeBase.getVersion()); var newFieldType = Objects.requireNonNull(computedTypes.get(DataModel.fixType(newDataConfiguration.type))); var initializerLocation = newDataConfiguration.getInitializerLocation(); + + var contextInfo = createContextStaticClass(typeBase, e.getValue().to, + contextStaticFieldCodeBlocks, + classBuilder, + initializerLocation, + newDataConfiguration.getContextParameters() + ); + var genericInitializerClass = ParameterizedTypeName.get(ClassName.get(DataInitializer.class), + contextInfo.typeName(), newFieldType.getJTypeName(basePackageName).box() ); @@ -131,7 +132,7 @@ public class GenUpgraderBaseX extends ClassGenerator { genericInitializerClass ); - return new Field(newDataConfiguration.to, newFieldType, CodeBlock.of("$N.initialize()", initializerName), i + 1); + return new Field(newDataConfiguration.to, newFieldType, CodeBlock.of("$N.initialize($L)", initializerName, contextInfo.contextApply), i + 1); }) ); resultFields = fields.mapMulti((field, consumer) -> { @@ -170,7 +171,16 @@ public class GenUpgraderBaseX extends ClassGenerator { var cb = CodeBlock.builder(); var newFieldType = Objects .requireNonNull(dataModel.getComputedTypes(nextTypeBase.getVersion()).get(DataModel.fixType(upgradeDataConfiguration.type))); + + var contextInfo = createContextStaticClass(typeBase, upgradeDataConfiguration.from, + contextStaticFieldCodeBlocks, + classBuilder, + upgraderImplementationLocation, + upgradeDataConfiguration.getContextParameters() + ); + var genericUpgraderClass = ParameterizedTypeName.get(ClassName.get(DataUpgrader.class), + contextInfo.typeName(), fieldType.getJTypeName(basePackageName).box(), newFieldType.getJTypeName(basePackageName).box() ); @@ -182,9 +192,10 @@ public class GenUpgraderBaseX extends ClassGenerator { genericUpgraderClass ); - cb.add("($T) $N.upgrade(($T) ", + cb.add("($T) $N.upgrade($L, ($T) ", newFieldType.getJTypeName(basePackageName), upgraderName, + contextInfo.contextApply, fieldType.getJTypeName(basePackageName) ); cb.add(codeBlock); @@ -223,10 +234,10 @@ public class GenUpgraderBaseX extends ClassGenerator { } private String createInitializerStaticField(AtomicInteger nextInitializerStaticFieldId, - HashMap initializerStaticFieldNames, - Builder classBuilder, - JInterfaceLocation initializerLocation, - TypeName genericInitializerClass) { + HashMap initializerStaticFieldNames, + Builder classBuilder, + JInterfaceLocation initializerLocation, + TypeName genericInitializerClass) { var identifier = initializerLocation.getIdentifier(); var initializerName = initializerStaticFieldNames.get(identifier); if (initializerName == null) { @@ -247,6 +258,55 @@ public class GenUpgraderBaseX extends ClassGenerator { return initializerName; } + record ContextInfo(TypeName typeName, CodeBlock contextApply) {} + + private ContextInfo createContextStaticClass(ComputedTypeBase typeBase, + String fieldName, + HashMap contextStaticFieldCodeBlocks, + Builder classBuilder, + JInterfaceLocation initializerLocation, + @NotNull List contextParameters) { + var identifier = initializerLocation.getIdentifier(); + var contextStaticFieldCodeBlock = contextStaticFieldCodeBlocks.get(identifier); + if (contextStaticFieldCodeBlock == null) { + var codeBlockBuilder = CodeBlock.builder(); + TypeName typeName; + + if (contextParameters.isEmpty()) { + typeName = ClassName.get(DataContextNone.class); + codeBlockBuilder.add("$T.INSTANCE", typeName); + } else { + var name = "Context" + SourcesGenerator.capitalize(fieldName); + var contextTypeClassBuilder = TypeSpec.recordBuilder(name) + .addSuperinterface(ClassName.get(DataContext.class)) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + typeName = typeBase.getJUpgraderName(basePackageName).nestedClass(name); + + codeBlockBuilder.add("new $T(", typeName); + boolean first = true; + for (String contextParameter : contextParameters) { + var fieldType = typeBase.getData().get(contextParameter); + contextTypeClassBuilder.addRecordComponent(ParameterSpec.builder(fieldType.getJTypeName(basePackageName), contextParameter).build()); + + if (first) { + first = false; + } else { + codeBlockBuilder.add(", "); + } + codeBlockBuilder.add("data.$N()", contextParameter); + } + codeBlockBuilder.add(")"); + + var clazz = contextTypeClassBuilder.build(); + classBuilder.addType(clazz); + } + + contextStaticFieldCodeBlock = new ContextInfo(typeName, codeBlockBuilder.build()); + contextStaticFieldCodeBlocks.put(identifier, contextStaticFieldCodeBlock); + } + return contextStaticFieldCodeBlock; + } + private String createUpgraderStaticField(AtomicInteger nextUpgraderStaticFieldId, HashMap upgraderStaticFieldNames, Builder classBuilder, diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderSuperX.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderSuperX.java index 6672a23..f775c56 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderSuperX.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenUpgraderSuperX.java @@ -8,6 +8,7 @@ import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.TypeSpec; import com.squareup.javapoet.TypeSpec.Builder; import it.cavallium.datagen.DataUpgrader; +import it.cavallium.datagen.DataUpgraderSimple; import it.cavallium.datagen.plugin.ClassGenerator; import it.cavallium.datagen.plugin.ComputedType; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; @@ -44,7 +45,7 @@ public class GenUpgraderSuperX extends ClassGenerator { classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL); - classBuilder.addSuperinterface(ParameterizedTypeName.get(ClassName.get(DataUpgrader.class), + classBuilder.superclass(ParameterizedTypeName.get(ClassName.get(DataUpgraderSimple.class), typeBaseClassName, nextTypeSuper.getJTypeName(basePackageName) )); diff --git a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenVersion.java b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenVersion.java index 53e9ba8..e6cf23f 100644 --- a/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenVersion.java +++ b/datagen-plugin/src/main/java/it/cavallium/datagen/plugin/classgen/GenVersion.java @@ -11,6 +11,7 @@ import com.squareup.javapoet.TypeSpec.Builder; import com.squareup.javapoet.TypeVariableName; import it.cavallium.datagen.DataSerializer; import it.cavallium.datagen.DataUpgrader; +import it.cavallium.datagen.DataUpgraderSimple; import it.cavallium.datagen.plugin.ClassGenerator; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; import it.cavallium.datagen.plugin.ComputedTypeArrayFixed; @@ -188,7 +189,7 @@ public class GenVersion extends ClassGenerator { return; } - var genericClassName = ParameterizedTypeName.get(ClassName.get(DataUpgrader.class), + var genericClassName = ParameterizedTypeName.get(ClassName.get(DataUpgraderSimple.class), type.getJTypeName(basePackageName), nextVersion.getJTypeName(basePackageName) ); var upgraderClassName = type.getJUpgraderName(basePackageName); diff --git a/datagen/src/main/java/it/cavallium/datagen/DataContext.java b/datagen/src/main/java/it/cavallium/datagen/DataContext.java new file mode 100644 index 0000000..4861bcb --- /dev/null +++ b/datagen/src/main/java/it/cavallium/datagen/DataContext.java @@ -0,0 +1,4 @@ +package it.cavallium.datagen; + +public interface DataContext { +} diff --git a/datagen/src/main/java/it/cavallium/datagen/DataContextNone.java b/datagen/src/main/java/it/cavallium/datagen/DataContextNone.java new file mode 100644 index 0000000..823583a --- /dev/null +++ b/datagen/src/main/java/it/cavallium/datagen/DataContextNone.java @@ -0,0 +1,9 @@ +package it.cavallium.datagen; + +public final class DataContextNone implements DataContext { + + public static final DataContextNone INSTANCE = new DataContextNone(); + + private DataContextNone() {} + +} diff --git a/datagen/src/main/java/it/cavallium/datagen/DataInitializer.java b/datagen/src/main/java/it/cavallium/datagen/DataInitializer.java index 7d422ba..6e396f8 100644 --- a/datagen/src/main/java/it/cavallium/datagen/DataInitializer.java +++ b/datagen/src/main/java/it/cavallium/datagen/DataInitializer.java @@ -2,7 +2,7 @@ package it.cavallium.datagen; import org.jetbrains.annotations.NotNull; -public interface DataInitializer { +public interface DataInitializer { - @NotNull T initialize(); + @NotNull T initialize(C context); } diff --git a/datagen/src/main/java/it/cavallium/datagen/DataInitializerSimple.java b/datagen/src/main/java/it/cavallium/datagen/DataInitializerSimple.java new file mode 100644 index 0000000..cbcfb40 --- /dev/null +++ b/datagen/src/main/java/it/cavallium/datagen/DataInitializerSimple.java @@ -0,0 +1,13 @@ +package it.cavallium.datagen; + +import org.jetbrains.annotations.NotNull; + +public abstract class DataInitializerSimple implements DataInitializer { + + @Override + public final @NotNull T initialize(DataContextNone context) { + return initialize(); + } + + public abstract @NotNull T initialize(); +} diff --git a/datagen/src/main/java/it/cavallium/datagen/DataUpgrader.java b/datagen/src/main/java/it/cavallium/datagen/DataUpgrader.java index 3179a32..0255efc 100644 --- a/datagen/src/main/java/it/cavallium/datagen/DataUpgrader.java +++ b/datagen/src/main/java/it/cavallium/datagen/DataUpgrader.java @@ -2,7 +2,7 @@ package it.cavallium.datagen; import org.jetbrains.annotations.NotNull; -public interface DataUpgrader { +public interface DataUpgrader { - @NotNull U upgrade(@NotNull T data); + @NotNull U upgrade(@NotNull C context, @NotNull T data); } diff --git a/datagen/src/main/java/it/cavallium/datagen/DataUpgraderSimple.java b/datagen/src/main/java/it/cavallium/datagen/DataUpgraderSimple.java new file mode 100644 index 0000000..70cb504 --- /dev/null +++ b/datagen/src/main/java/it/cavallium/datagen/DataUpgraderSimple.java @@ -0,0 +1,13 @@ +package it.cavallium.datagen; + +import org.jetbrains.annotations.NotNull; + +public abstract class DataUpgraderSimple implements DataUpgrader { + + @Override + public final @NotNull U upgrade(@NotNull DataContextNone context, @NotNull T data) { + return this.upgrade(data); + } + + public abstract @NotNull U upgrade(@NotNull T data); +} diff --git a/datagen/src/main/java/it/cavallium/datagen/nativedata/UpgradeUtil.java b/datagen/src/main/java/it/cavallium/datagen/nativedata/UpgradeUtil.java index 5e48ea8..bd9de4e 100644 --- a/datagen/src/main/java/it/cavallium/datagen/nativedata/UpgradeUtil.java +++ b/datagen/src/main/java/it/cavallium/datagen/nativedata/UpgradeUtil.java @@ -1,11 +1,19 @@ package it.cavallium.datagen.nativedata; +import it.cavallium.datagen.DataContext; +import it.cavallium.datagen.DataContextNone; import it.cavallium.datagen.DataUpgrader; +import it.cavallium.datagen.DataUpgraderSimple; + import java.util.List; public class UpgradeUtil { + public static List upgradeArray(List from, DataUpgraderSimple upgrader) { + return upgradeArray(DataContextNone.INSTANCE, from, upgrader); + } + @SuppressWarnings("unchecked") - public static List upgradeArray(List from, DataUpgrader upgrader) { + public static List upgradeArray(C context, List from, DataUpgrader upgrader) { Object[] array; if (from.getClass() == ImmutableWrappedArrayList.class && ((ImmutableWrappedArrayList) from).a.getClass() == Object[].class) { @@ -14,16 +22,20 @@ public class UpgradeUtil { array = from.toArray(); } for (int i = 0; i < array.length; i++) { - array[i] = (B) upgrader.upgrade((A) array[i]); + array[i] = (B) upgrader.upgrade(context, (A) array[i]); } return (ImmutableWrappedArrayList) ImmutableWrappedArrayList.of(array); } - public static B upgradeNullable(A nullableValue, DataUpgrader upgrader) { + public static B upgradeNullable(A nullableValue, DataUpgraderSimple upgrader) { + return upgradeNullable(DataContextNone.INSTANCE, nullableValue, upgrader); + } + + public static B upgradeNullable(C context, A nullableValue, DataUpgrader upgrader) { if (nullableValue == null) { return null; } else { - return upgrader.upgrade(nullableValue); + return upgrader.upgrade(context, nullableValue); } } }