Use generic TypedNullable<?> instead of the specific implementation in records

This commit is contained in:
Andrea Cavalli 2024-09-04 17:46:50 +02:00
parent 5afe301750
commit ea4f6db7a9
20 changed files with 170 additions and 13 deletions

View File

@ -12,6 +12,7 @@ public sealed interface ComputedType permits VersionedComputedType, ComputedType
String getName(); String getName();
TypeName getJTypeName(String basePackageName); TypeName getJTypeName(String basePackageName);
TypeName getJTypeNameGeneric(String basePackageName);
TypeName getJSerializerName(String basePackageName); TypeName getJSerializerName(String basePackageName);

View File

@ -71,6 +71,11 @@ public final class ComputedTypeArrayFixed implements ComputedTypeArray {
computedTypeSupplier.get(baseType).getJTypeName(basePackageName)); computedTypeSupplier.get(baseType).getJTypeName(basePackageName));
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(currentVersion.getSerializersPackage(basePackageName), "Array" + baseType + "Serializer"); return ClassName.get(currentVersion.getSerializersPackage(basePackageName), "Array" + baseType + "Serializer");

View File

@ -3,6 +3,7 @@ package it.cavallium.datagen.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.ParameterizedTypeName; import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeName;
import it.cavallium.datagen.NativeNullable;
import it.cavallium.datagen.nativedata.ArrayInt52Serializer; import it.cavallium.datagen.nativedata.ArrayInt52Serializer;
import it.cavallium.datagen.nativedata.ArrayStringSerializer; import it.cavallium.datagen.nativedata.ArrayStringSerializer;
import it.cavallium.datagen.nativedata.ArraybooleanSerializer; import it.cavallium.datagen.nativedata.ArraybooleanSerializer;
@ -96,6 +97,11 @@ public final class ComputedTypeArrayNative implements ComputedTypeArray {
}; };
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return switch (baseType) { return switch (baseType) {

View File

@ -88,6 +88,11 @@ public final class ComputedTypeArrayVersioned implements VersionedComputedType,
computedTypeSupplier.get(baseType).getJTypeName(basePackageName)); computedTypeSupplier.get(baseType).getJTypeName(basePackageName));
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(baseType.version().getSerializersPackage(basePackageName), "Array" + baseType.type() + "Serializer"); return ClassName.get(baseType.version().getSerializersPackage(basePackageName), "Array" + baseType.type() + "Serializer");

View File

@ -2,6 +2,7 @@ package it.cavallium.datagen.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeName;
import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Objects; import java.util.Objects;
@ -101,6 +102,11 @@ public final class ComputedTypeBase implements VersionedComputedType {
return ClassName.get(getVersion().getDataPackage(basePackageName), type.type()); return ClassName.get(getVersion().getDataPackage(basePackageName), type.type());
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Serializer"); return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Serializer");

View File

@ -93,6 +93,11 @@ public final class ComputedTypeCustom implements ComputedType {
return typeName; return typeName;
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public TypeName getJSerializerName(String basePackageName) { public TypeName getJSerializerName(String basePackageName) {
return ClassName.bestGuess(serializer); return ClassName.bestGuess(serializer);

View File

@ -46,6 +46,11 @@ public final class ComputedTypeNative implements ComputedType {
}; };
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public TypeName getJSerializerName(String basePackageName) { public TypeName getJSerializerName(String basePackageName) {
return switch (type) { return switch (type) {

View File

@ -2,7 +2,9 @@ package it.cavallium.datagen.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeName;
import it.cavallium.datagen.TypedNullable;
import it.cavallium.datagen.nativedata.UpgradeUtil; import it.cavallium.datagen.nativedata.UpgradeUtil;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -68,11 +70,21 @@ public final class ComputedTypeNullableFixed implements ComputedTypeNullable {
return getJTypeNameOfVersion(currentVersion, basePackageName); return getJTypeNameOfVersion(currentVersion, basePackageName);
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeNameGenericOfVersion(currentVersion, basePackageName);
}
private TypeName getJTypeNameOfVersion(ComputedVersion version, String basePackageName) { private TypeName getJTypeNameOfVersion(ComputedVersion version, String basePackageName) {
return ClassName.get(version.getDataNullablesPackage(basePackageName), return ClassName.get(version.getDataNullablesPackage(basePackageName),
"Nullable" + baseType); "Nullable" + baseType);
} }
private TypeName getJTypeNameGenericOfVersion(ComputedVersion version, String basePackageName) {
return ParameterizedTypeName.get(ClassName.get(TypedNullable.class),
ClassName.get(version.getDataPackage(basePackageName), baseType));
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(currentVersion.getSerializersPackage(basePackageName), return ClassName.get(currentVersion.getSerializersPackage(basePackageName),
@ -102,7 +114,7 @@ public final class ComputedTypeNullableFixed implements ComputedTypeNullable {
var upgraderInstance = getBase().getJUpgraderInstance(basePackageName); var upgraderInstance = getBase().getJUpgraderInstance(basePackageName);
builder.add("new $T($T.upgradeNullable(", next.getJTypeName(basePackageName), UpgradeUtil.class); builder.add("new $T($T.upgradeNullable(", next.getJTypeName(basePackageName), UpgradeUtil.class);
builder.add(content); builder.add(content);
builder.add(".value(), $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName()); builder.add(".getNullable(), $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName());
builder.add(")"); builder.add(")");
return builder.build(); return builder.build();
} }

View File

@ -99,6 +99,11 @@ public final class ComputedTypeNullableNative implements ComputedTypeNullable {
}; };
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeName(basePackageName);
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return switch (baseType) { return switch (baseType) {

View File

@ -2,7 +2,9 @@ package it.cavallium.datagen.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName; import com.squareup.javapoet.TypeName;
import it.cavallium.datagen.TypedNullable;
import it.cavallium.datagen.nativedata.UpgradeUtil; import it.cavallium.datagen.nativedata.UpgradeUtil;
import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -81,11 +83,21 @@ public final class ComputedTypeNullableVersioned implements ComputedTypeNullable
return getJTypeNameOfVersion(baseType.version(), basePackageName); return getJTypeNameOfVersion(baseType.version(), basePackageName);
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return getJTypeNameGenericOfVersion(baseType.version(), basePackageName);
}
private TypeName getJTypeNameOfVersion(ComputedVersion version, String basePackageName) { private TypeName getJTypeNameOfVersion(ComputedVersion version, String basePackageName) {
return ClassName.get(version.getDataNullablesPackage(basePackageName), return ClassName.get(version.getDataNullablesPackage(basePackageName),
"Nullable" + baseType.type()); "Nullable" + baseType.type());
} }
private TypeName getJTypeNameGenericOfVersion(ComputedVersion version, String basePackageName) {
return ParameterizedTypeName.get(ClassName.get(TypedNullable.class),
ClassName.get(version.getDataPackage(basePackageName), baseType.type()));
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(baseType.version().getSerializersPackage(basePackageName), return ClassName.get(baseType.version().getSerializersPackage(basePackageName),
@ -115,7 +127,7 @@ public final class ComputedTypeNullableVersioned implements ComputedTypeNullable
var upgraderInstance = getBase().getJUpgraderInstance(basePackageName); var upgraderInstance = getBase().getJUpgraderInstance(basePackageName);
builder.add("new $T($T.upgradeNullable(", next.getJTypeName(basePackageName), UpgradeUtil.class); builder.add("new $T($T.upgradeNullable(", next.getJTypeName(basePackageName), UpgradeUtil.class);
builder.add(content); builder.add(content);
builder.add(".value(), $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName()); builder.add(".getNullable(), $T.$N)", upgraderInstance.className(), upgraderInstance.fieldName());
builder.add(")"); builder.add(")");
return builder.build(); return builder.build();
} }

View File

@ -2,6 +2,7 @@ package it.cavallium.datagen.plugin;
import com.squareup.javapoet.ClassName; import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.CodeBlock;
import com.squareup.javapoet.TypeName;
import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType; import it.cavallium.datagen.plugin.ComputedType.VersionedComputedType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -97,6 +98,11 @@ public final class ComputedTypeSuper implements VersionedComputedType {
return ClassName.get(getVersion().getDataPackage(basePackageName), type.type()); return ClassName.get(getVersion().getDataPackage(basePackageName), type.type());
} }
@Override
public TypeName getJTypeNameGeneric(String basePackageName) {
return ClassName.get(getVersion().getDataPackage(basePackageName), type.type());
}
@Override @Override
public ClassName getJSerializerName(String basePackageName) { public ClassName getJSerializerName(String basePackageName) {
return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Serializer"); return ClassName.get(type.version().getSerializersPackage(basePackageName), type.type() + "Serializer");

View File

@ -69,7 +69,7 @@ public class SourcesGenerator {
private static final Logger logger = LoggerFactory.getLogger(SourcesGenerator.class); private static final Logger logger = LoggerFactory.getLogger(SourcesGenerator.class);
private static final boolean OVERRIDE_ALL_NULLABLE_METHODS = false; private static final boolean OVERRIDE_ALL_NULLABLE_METHODS = false;
private static final String SERIAL_VERSION = "2"; private static final String SERIAL_VERSION = "5";
private final DataModel dataModel; private final DataModel dataModel;

View File

@ -68,7 +68,7 @@ public class GenDataBaseX extends ClassGenerator {
.addModifiers(Modifier.PUBLIC, Modifier.STATIC); .addModifiers(Modifier.PUBLIC, Modifier.STATIC);
base.getData().forEach((fieldName, fieldType) -> { base.getData().forEach((fieldName, fieldType) -> {
var fieldTypeName = fieldType.getJTypeName(basePackageName); var fieldTypeName = fieldType.getJTypeNameGeneric(basePackageName);
var param = ParameterSpec var param = ParameterSpec
.builder(fieldTypeName, fieldName) .builder(fieldTypeName, fieldName)

View File

@ -61,7 +61,7 @@ public class GenDataSuperX extends ClassGenerator {
Stream Stream
.concat(dataModel.getCommonInterfaceData(typeSuper), dataModel.getCommonInterfaceGetters(typeSuper)) .concat(dataModel.getCommonInterfaceData(typeSuper), dataModel.getCommonInterfaceGetters(typeSuper))
.forEach(superType -> { .forEach(superType -> {
var returnType = superType.getValue().getJTypeName(basePackageName); var returnType = superType.getValue().getJTypeNameGeneric(basePackageName);
var getter = MethodSpec var getter = MethodSpec
.methodBuilder(superType.getKey()) .methodBuilder(superType.getKey())
.addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT) .addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT)
@ -73,7 +73,7 @@ public class GenDataSuperX extends ClassGenerator {
}); });
dataModel.getCommonInterfaceData(typeSuper).forEach(superType -> { dataModel.getCommonInterfaceData(typeSuper).forEach(superType -> {
var returnType = superType.getValue().getJTypeName(basePackageName); var returnType = superType.getValue().getJTypeNameGeneric(basePackageName);
var setter = MethodSpec var setter = MethodSpec
.methodBuilder("set" + StringUtils.capitalize(superType.getKey())) .methodBuilder("set" + StringUtils.capitalize(superType.getKey()))

View File

@ -88,9 +88,10 @@ public class GenNullableX extends ClassGenerator {
classBuilder.addField(FieldSpec classBuilder.addField(FieldSpec
.builder(type, "NULL").addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).initializer("new $T(null)", type).build()); .builder(type, "NULL").addModifiers(Modifier.PRIVATE, Modifier.STATIC, Modifier.FINAL).initializer("new $T(null)", type).build());
if (version.isCurrent()) {
classBuilder.addSuperinterfaces(List.of(iNullableITypeClass, iNullableClass, typedNullable)); classBuilder.addSuperinterfaces(List.of(iNullableITypeClass, iNullableClass, typedNullable));
if (version.isCurrent()) {
classBuilder.addMethod(MethodSpec classBuilder.addMethod(MethodSpec
.methodBuilder("of") .methodBuilder("of")
.addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL) .addModifiers(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL)

View File

@ -42,7 +42,7 @@ public class GenSerializerNullableX extends ClassGenerator {
private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeNullable typeNullable) { private GeneratedClass generateTypeVersioned(ComputedVersion version, ComputedTypeNullable typeNullable) {
ClassName serializerClassName = typeNullable.getJSerializerName(basePackageName); ClassName serializerClassName = typeNullable.getJSerializerName(basePackageName);
var typeNullableClassName = typeNullable.getJTypeName(basePackageName); var typeNullableClassName = typeNullable.getJTypeNameGeneric(basePackageName);
var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName()); var classBuilder = TypeSpec.classBuilder(serializerClassName.simpleName());
@ -68,7 +68,7 @@ public class GenSerializerNullableX extends ClassGenerator {
method.addParameter(ParameterSpec.builder(SafeDataOutput.class, "out").build()); method.addParameter(ParameterSpec.builder(SafeDataOutput.class, "out").build());
method.addParameter(ParameterSpec method.addParameter(ParameterSpec
.builder(typeNullable.getJTypeName(basePackageName), "data") .builder(typeNullable.getJTypeNameGeneric(basePackageName), "data")
.addAnnotation(NotNull.class) .addAnnotation(NotNull.class)
.build()); .build());

View File

@ -286,7 +286,7 @@ public class GenUpgraderBaseX extends ClassGenerator {
boolean first = true; boolean first = true;
for (String contextParameter : contextParameters) { for (String contextParameter : contextParameters) {
var fieldType = typeBase.getData().get(contextParameter); var fieldType = typeBase.getData().get(contextParameter);
contextTypeClassBuilder.addRecordComponent(ParameterSpec.builder(fieldType.getJTypeName(basePackageName), contextParameter).build()); contextTypeClassBuilder.addRecordComponent(ParameterSpec.builder(fieldType.getJTypeNameGeneric(basePackageName), contextParameter).build());
if (first) { if (first) {
first = false; first = false;

View File

@ -165,7 +165,7 @@ public class GenVersion extends ClassGenerator {
var serializerClassName = type.getJSerializerName(basePackageName); var serializerClassName = type.getJSerializerName(basePackageName);
var fieldBuilder = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(DataSerializer.class), var fieldBuilder = FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(DataSerializer.class),
type.getJTypeName(basePackageName) type.getJTypeNameGeneric(basePackageName)
), serializerFieldLocation.fieldName(), Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL); ), serializerFieldLocation.fieldName(), Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL);
fieldBuilder.initializer("new $T()", serializerClassName); fieldBuilder.initializer("new $T()", serializerClassName);
classBuilder.addField(fieldBuilder.build()); classBuilder.addField(fieldBuilder.build());

View File

@ -34,10 +34,11 @@ public interface TypedNullable<T> extends NativeNullable<T> {
} }
@Override @Override
default @NotNull NativeNullable<? extends T> or(@NotNull NativeNullable<? extends T> fallback) { default @NotNull TypedNullable<T> or(@NotNull NativeNullable<? extends T> fallback) {
var value = getNullable(); var value = getNullable();
if (value == null) { if (value == null) {
return fallback; //noinspection unchecked
return (TypedNullable<T>) fallback;
} else { } else {
return this; return this;
} }

View File

@ -0,0 +1,87 @@
package it.cavallium.datagen.nativedata;
import it.cavallium.datagen.TypedNullable;
import org.jetbrains.annotations.Nullable;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class TestTypedNullable {
@Test
public void testNullableOr() {
class TypeA {
}
class TypeAB extends TypeA {
}
var a = new TypedNullable<TypeA>() {
@Override
public @Nullable TypeA getNullable() {
return new TypeA();
}
};
var aNull = new TypedNullable<TypeA>() {
@Override
public @Nullable TypeA getNullable() {
return null;
}
};
var ab = new TypedNullable<TypeAB>() {
@Override
public @Nullable TypeAB getNullable() {
return new TypeAB();
}
};
var abNull = new TypedNullable<TypeAB>() {
@Override
public @Nullable TypeAB getNullable() {
return null;
}
};
Assertions.assertDoesNotThrow(() -> {
a.or(ab).getNullable();
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(ab).getNullable();
});
Assertions.assertDoesNotThrow(() -> {
a.or(abNull).getNullable();
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(abNull).getNullable();
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(abNull).orElse(new TypeA());
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(ab).orElse(new TypeA());
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(ab).orElse(new TypeAB());
});
Assertions.assertDoesNotThrow(() -> {
aNull.or(abNull).orElse(new TypeAB());
});
Assertions.assertDoesNotThrow(() -> {
abNull.or(abNull).orElse(new TypeAB());
});
}
}