229 lines
8.4 KiB
Java
229 lines
8.4 KiB
Java
package it.cavallium.data.generator.plugin.classgen;
|
|
|
|
import com.squareup.javapoet.ClassName;
|
|
import com.squareup.javapoet.CodeBlock;
|
|
import com.squareup.javapoet.FieldSpec;
|
|
import com.squareup.javapoet.MethodSpec;
|
|
import com.squareup.javapoet.ParameterizedTypeName;
|
|
import com.squareup.javapoet.TypeName;
|
|
import com.squareup.javapoet.TypeSpec;
|
|
import com.squareup.javapoet.TypeSpec.Builder;
|
|
import com.squareup.javapoet.TypeVariableName;
|
|
import it.cavallium.data.generator.DataSerializer;
|
|
import it.cavallium.data.generator.plugin.ClassGenerator;
|
|
import it.cavallium.data.generator.plugin.ComputedType.VersionedComputedType;
|
|
import it.cavallium.data.generator.plugin.ComputedTypeCustom;
|
|
import it.cavallium.data.generator.plugin.ComputedVersion;
|
|
import java.io.IOException;
|
|
import java.util.stream.Stream;
|
|
import javax.lang.model.element.Modifier;
|
|
|
|
public class GenVersion extends ClassGenerator {
|
|
|
|
private static final boolean STRICT_SWITCH = false;
|
|
|
|
public GenVersion(ClassGeneratorParams params) {
|
|
super(params);
|
|
}
|
|
|
|
@Override
|
|
protected Stream<GeneratedClass> generateClasses() {
|
|
return dataModel.getVersionsSet().stream().map(this::generateClass);
|
|
}
|
|
|
|
private GeneratedClass generateClass(ComputedVersion version) {
|
|
var classBuilder = TypeSpec.classBuilder("Version");
|
|
|
|
classBuilder.addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
|
|
|
var iVersionClassName = ClassName.get(dataModel.getRootPackage(basePackageName), "IVersion");
|
|
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
|
classBuilder.addSuperinterface(ParameterizedTypeName.get(iVersionClassName, iBaseTypeClassName));
|
|
|
|
generateVersionField(version, classBuilder);
|
|
|
|
generateInstanceField(version, classBuilder);
|
|
|
|
generateUpgradeToNextVersion(version, classBuilder);
|
|
|
|
generateSerializerInstance(version, classBuilder);
|
|
|
|
generateUpgraderInstance(version, classBuilder);
|
|
|
|
generateGetSerializer(version, classBuilder);
|
|
|
|
generateGetVersion(version, classBuilder);
|
|
|
|
return new GeneratedClass(version.getPackage(basePackageName), classBuilder);
|
|
}
|
|
|
|
/**
|
|
* Add a static variable for the current version
|
|
*/
|
|
private void generateVersionField(ComputedVersion version, Builder classBuilder) {
|
|
var versionNumberXField = FieldSpec
|
|
.builder(TypeName.INT, "VERSION")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addModifiers(Modifier.STATIC)
|
|
.addModifiers(Modifier.FINAL)
|
|
.initializer("$T." + version.getVersionVarName(),
|
|
ClassName.get(dataModel.getRootPackage(basePackageName), "Versions")
|
|
)
|
|
.build();
|
|
classBuilder.addField(versionNumberXField);
|
|
}
|
|
|
|
/**
|
|
* Add a static instance for the current version
|
|
*/
|
|
private void generateInstanceField(ComputedVersion version, Builder classBuilder) {
|
|
var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version");
|
|
var versionInstanceField = FieldSpec
|
|
.builder(versionClassType, "INSTANCE")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.addModifiers(Modifier.STATIC)
|
|
.addModifiers(Modifier.FINAL)
|
|
.initializer("new $T()", versionClassType)
|
|
.build();
|
|
classBuilder.addField(versionInstanceField);
|
|
}
|
|
|
|
private void generateUpgradeToNextVersion(ComputedVersion version, Builder classBuilder) {
|
|
var nextVersion = dataModel.getNextVersion(version).orElse(null);
|
|
|
|
// Skip upgrade if it's the latest version
|
|
if (nextVersion == null) {
|
|
return;
|
|
}
|
|
|
|
var methodBuilder = MethodSpec.methodBuilder("upgradeToNextVersion");
|
|
|
|
methodBuilder.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
|
|
methodBuilder.addException(ClassName.get(IOException.class));
|
|
|
|
var nextIBaseType = ClassName.get(nextVersion.getDataPackage(basePackageName), "IBaseType");
|
|
methodBuilder.returns(nextIBaseType);
|
|
|
|
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
|
methodBuilder.addParameter(iBaseTypeClassName, "oldData");
|
|
|
|
methodBuilder.beginControlFlow( "return switch (oldData.getBaseType$$())");
|
|
dataModel.getBaseTypesComputed(version).forEach(baseType -> {
|
|
if (baseType.shouldUpgradeAfter(version)) {
|
|
var nextBaseType = dataModel.getNextVersion(baseType);
|
|
var versionType = ClassName.get(baseType.getVersion().getPackage(basePackageName), "Version");
|
|
methodBuilder.addStatement("case $N -> ($T) $T.$NUpgraderInstance.upgrade(($T) oldData)",
|
|
baseType.getName(),
|
|
nextBaseType.getJTypeName(basePackageName),
|
|
versionType,
|
|
baseType.getName(),
|
|
baseType.getJTypeName(basePackageName)
|
|
);
|
|
} else {
|
|
if (STRICT_SWITCH) {
|
|
methodBuilder.addStatement("case $N -> ($T) oldData",
|
|
baseType.getName(),
|
|
baseType.getJTypeName(basePackageName)
|
|
);
|
|
}
|
|
}
|
|
});
|
|
if (!STRICT_SWITCH) {
|
|
methodBuilder.addStatement("default -> ($T) oldData", nextIBaseType);
|
|
}
|
|
methodBuilder.addCode(CodeBlock.of("$<};"));
|
|
classBuilder.addMethod(methodBuilder.build());
|
|
}
|
|
|
|
private void generateSerializerInstance(ComputedVersion version, Builder classBuilder) {
|
|
var versionClassType = ClassName.get(version.getPackage(basePackageName), "Version");
|
|
dataModel.getComputedTypes(version).forEach((typeName, type) -> {
|
|
boolean shouldCreateInstanceField;
|
|
// Check if the type matches the current version
|
|
shouldCreateInstanceField = type instanceof VersionedComputedType versionedComputedType
|
|
&& versionedComputedType.getVersion().equals(version);
|
|
|
|
// Check if the type is custom, and this is the latest version
|
|
shouldCreateInstanceField |= version.isCurrent() && type instanceof ComputedTypeCustom;
|
|
|
|
if (!shouldCreateInstanceField) {
|
|
return;
|
|
}
|
|
|
|
var serializerFieldLocation = type.getJSerializerInstance(basePackageName);
|
|
if (!versionClassType.equals(serializerFieldLocation.className())) {
|
|
return;
|
|
}
|
|
|
|
var serializerClassName = type.getJSerializerName(basePackageName);
|
|
|
|
var fieldBuilder = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(DataSerializer.class),
|
|
type.getJTypeName(basePackageName)
|
|
), serializerFieldLocation.fieldName(), Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
|
|
fieldBuilder.initializer("new $T()", serializerClassName);
|
|
classBuilder.addField(fieldBuilder.build());
|
|
});
|
|
}
|
|
|
|
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
|
|
&& versionedComputedType.getVersion().equals(version);
|
|
if (!shouldCreateInstanceField) {
|
|
return;
|
|
}
|
|
|
|
var upgraderFieldLocation = type.getJUpgraderInstance(basePackageName);
|
|
if (!versionClassType.equals(upgraderFieldLocation.className())) {
|
|
return;
|
|
}
|
|
|
|
var upgraderClassName = type.getJUpgraderName(basePackageName);
|
|
|
|
var fieldBuilder = FieldSpec.builder(upgraderClassName,
|
|
upgraderFieldLocation.fieldName(),
|
|
Modifier.PUBLIC,
|
|
Modifier.STATIC,
|
|
Modifier.FINAL
|
|
);
|
|
fieldBuilder.initializer("new $T()", upgraderClassName);
|
|
classBuilder.addField(fieldBuilder.build());
|
|
});
|
|
}
|
|
|
|
private void generateGetSerializer(ComputedVersion version, Builder classBuilder) {
|
|
var methodBuilder = MethodSpec.methodBuilder("getSerializer");
|
|
|
|
methodBuilder.addModifiers(Modifier.PUBLIC);
|
|
methodBuilder.addAnnotation(Override.class);
|
|
methodBuilder.addException(ClassName.get(IOException.class));
|
|
|
|
var iBaseTypeClassName = ClassName.get(version.getDataPackage(basePackageName), "IBaseType");
|
|
methodBuilder.addTypeVariable(TypeVariableName.get("T", iBaseTypeClassName));
|
|
|
|
var baseTypeClassName = ClassName.get(dataModel.getRootPackage(basePackageName), "BaseType");
|
|
methodBuilder.addParameter(baseTypeClassName, "type");
|
|
|
|
methodBuilder.returns(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), TypeVariableName.get("T")));
|
|
|
|
methodBuilder.beginControlFlow("return switch (type)");
|
|
dataModel.getBaseTypesComputed(version).forEach(baseType -> {
|
|
var field = baseType.getJSerializerInstance(basePackageName);
|
|
methodBuilder.addStatement("case $N -> $T.$N", baseType.getName(), field.className(), field.fieldName());
|
|
});
|
|
methodBuilder.addCode(CodeBlock.of("$<};"));
|
|
classBuilder.addMethod(methodBuilder.build());
|
|
}
|
|
|
|
private void generateGetVersion(ComputedVersion version, Builder classBuilder) {
|
|
classBuilder.addMethod(MethodSpec
|
|
.methodBuilder("getVersion")
|
|
.addModifiers(Modifier.PUBLIC)
|
|
.returns(int.class)
|
|
.addStatement("return VERSION")
|
|
.addAnnotation(Override.class)
|
|
.build());
|
|
}
|
|
}
|