Add data inizializer/upgrader declarative context parameters

This commit is contained in:
Andrea Cavalli 2024-09-02 12:47:49 +02:00
parent 73d24bf13f
commit 5afe301750
17 changed files with 295 additions and 112 deletions

View File

@ -82,7 +82,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<version>3.11.0</version>
<configuration>
<release>21</release>
<encoding>UTF-8</encoding>

View File

@ -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,
ParsedClass.FieldInfo prevDef = transformClass.insert(
Objects.requireNonNullElse(t.index, definition.get().getKey()),
t.to,
definition.get().getValue(),
t.index
new ParsedClass.InputFieldInfo(definition.get().getValue().typeName(), List.of())
);
} else {
prevDef = tryInsertAtIndex(transformClass.data,
t.to,
definition.get().getValue(),
definition.get().getKey()
);
}
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<ComputedType> versionBaseTypes = computedClassConfig.get(versionIndexF).entrySet().stream()
.map(e -> {
var data = new LinkedHashMap<String, VersionedType>();
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<String, String> data, String key, String value, int index) {
var before = new LinkedHashMap<String, String>();
var after = new LinkedHashMap<String, String>();
int i = 0;
for (Entry<String, String> 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<Entry<Integer, String>> removeAndGetIndex(LinkedHashMap<String, String> data, String find) {
int foundIndex = -1;
{
int i = 0;
for (Entry<String, String> 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<String, String> 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());
}
);
}

View File

@ -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 {

View File

@ -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<String> contextParameters;
@Override
public String getTransformClass() {
@ -27,6 +32,11 @@ public class NewDataConfiguration implements TransformationConfiguration {
return JInterfaceLocation.parse(initializer, initializerInstance);
}
@NotNull
public List<String> 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;
}
}

View File

@ -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<String> contextParams) {}
public record FieldInfo(@NotNull String typeName, @NotNull LinkedHashMap<String, String> contextFieldsData) {}
public String stringRepresenter;
public LinkedHashMap<String, String> data;
public LinkedHashMap<String, FieldInfo> data;
public List<TransformationConfiguration> 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<String, String> getData() {
public LinkedHashMap<String, FieldInfo> 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<String, String> computeContextParametersTypes(
LinkedHashMap<String, ParsedClass.FieldInfo> data, @NotNull List<String> 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<Entry<Integer, FieldInfo>> 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<String, ParsedClass.FieldInfo> data, String key,
FieldInfo value, int index) {
var before = new LinkedHashMap<String, ParsedClass.FieldInfo>(index);
var after = new LinkedHashMap<String, ParsedClass.FieldInfo>(data.size() - index);
int i = 0;
for (Entry<String, ParsedClass.FieldInfo> 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;
}
}

View File

@ -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);
}

View File

@ -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<String> contextParameters;
@Override
public String getTransformClass() {
@ -24,6 +30,11 @@ public class UpgradeDataConfiguration implements TransformationConfiguration {
return JInterfaceLocation.parse(upgrader, upgraderInstance);
}
@NotNull
public List<String> 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;
}
}

View File

@ -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<String, String> initializerStaticFieldNames = new HashMap<>();
HashMap<String, ContextInfo> contextStaticFieldCodeBlocks = new HashMap<>();
AtomicInteger nextUpgraderStaticFieldId = new AtomicInteger();
HashMap<String, String> upgraderStaticFieldNames = new HashMap<>();
List<TransformationConfiguration> 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.<ResultField>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);
@ -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<String, ContextInfo> contextStaticFieldCodeBlocks,
Builder classBuilder,
JInterfaceLocation initializerLocation,
@NotNull List<String> 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<String, String> upgraderStaticFieldNames,
Builder classBuilder,

View File

@ -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)
));

View File

@ -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);

View File

@ -0,0 +1,4 @@
package it.cavallium.datagen;
public interface DataContext {
}

View File

@ -0,0 +1,9 @@
package it.cavallium.datagen;
public final class DataContextNone implements DataContext {
public static final DataContextNone INSTANCE = new DataContextNone();
private DataContextNone() {}
}

View File

@ -2,7 +2,7 @@ package it.cavallium.datagen;
import org.jetbrains.annotations.NotNull;
public interface DataInitializer<T> {
public interface DataInitializer<C extends DataContext, T> {
@NotNull T initialize();
@NotNull T initialize(C context);
}

View File

@ -0,0 +1,13 @@
package it.cavallium.datagen;
import org.jetbrains.annotations.NotNull;
public abstract class DataInitializerSimple<T> implements DataInitializer<DataContextNone, T> {
@Override
public final @NotNull T initialize(DataContextNone context) {
return initialize();
}
public abstract @NotNull T initialize();
}

View File

@ -2,7 +2,7 @@ package it.cavallium.datagen;
import org.jetbrains.annotations.NotNull;
public interface DataUpgrader<T, U> {
public interface DataUpgrader<C extends DataContext, T, U> {
@NotNull U upgrade(@NotNull T data);
@NotNull U upgrade(@NotNull C context, @NotNull T data);
}

View File

@ -0,0 +1,13 @@
package it.cavallium.datagen;
import org.jetbrains.annotations.NotNull;
public abstract class DataUpgraderSimple<T, U> implements DataUpgrader<DataContextNone, T, U> {
@Override
public final @NotNull U upgrade(@NotNull DataContextNone context, @NotNull T data) {
return this.upgrade(data);
}
public abstract @NotNull U upgrade(@NotNull T data);
}

View File

@ -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 <A, B> List<B> upgradeArray(List<A> from, DataUpgraderSimple<A, B> upgrader) {
return upgradeArray(DataContextNone.INSTANCE, from, upgrader);
}
@SuppressWarnings("unchecked")
public static <A, B> List<B> upgradeArray(List<A> from, DataUpgrader<A, B> upgrader) {
public static <C extends DataContext, A, B> List<B> upgradeArray(C context, List<A> from, DataUpgrader<C, A, B> 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<B>) ImmutableWrappedArrayList.of(array);
}
public static <A, B> B upgradeNullable(A nullableValue, DataUpgrader<A, B> upgrader) {
public static <A, B> B upgradeNullable(A nullableValue, DataUpgraderSimple<A, B> upgrader) {
return upgradeNullable(DataContextNone.INSTANCE, nullableValue, upgrader);
}
public static <C extends DataContext, A, B> B upgradeNullable(C context, A nullableValue, DataUpgrader<C, A, B> upgrader) {
if (nullableValue == null) {
return null;
} else {
return upgrader.upgrade(nullableValue);
return upgrader.upgrade(context, nullableValue);
}
}
}