Skip to content

Commit

Permalink
Merge pull request #32 from edward3h/specialise_kiwi_primitive
Browse files Browse the repository at this point in the history
refactor to use a separate kiwi type for primitive/boxed types
  • Loading branch information
edward3h authored Aug 30, 2024
2 parents 0623ae9 + 45dd605 commit 9b0f878
Show file tree
Hide file tree
Showing 31 changed files with 422 additions and 172 deletions.
2 changes: 0 additions & 2 deletions catalog.settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ dependencyResolutionManagement {
version("junit", "5.11.0")
version("recordbuilder", "42")
version("mapstruct", "1.6.0")
version("ethelred-util", "2.2")

library("avaje-json", "io.avaje", "avaje-jsonb").versionRef("avaje-json")
library("avaje-json-processor", "io.avaje", "avaje-jsonb-generator").versionRef("avaje-json")
Expand Down Expand Up @@ -38,7 +37,6 @@ dependencyResolutionManagement {
library("compile-testing", "com.google.testing.compile:compile-testing:0.21.0")
library("compile-testing-extension", "io.github.kiskae:compile-testing-extension:1.0.2")

library("ethelred-util", "org.ethelred.util", "common").versionRef("ethelred-util")
library("yaml", "org.yaml:snakeyaml:2.2")

bundle("compile-testing", listOf("guava", "compile-testing", "compile-testing-extension"))
Expand Down
1 change: 0 additions & 1 deletion processor/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ dependencies {
implementation(libs.recordbuilder.core)
implementation(libs.mapstruct.processor)
implementation(libs.javapoet)
implementation(libs.ethelred.util)
testAnnotationProcessor(libs.mapstruct.processor)
testImplementation(project(":runtime"))
testImplementation(libs.jakarta.inject)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.ethelred.kiwiproc.processor;

import static org.ethelred.util.collect.BiMap.entry;
import static java.util.Map.entry;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand All @@ -18,11 +18,14 @@
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.ethelred.util.collect.BiMap;
import org.ethelred.kiwiproc.processor.types.BasicType;
import org.ethelred.kiwiproc.processor.types.KiwiType;
import org.ethelred.kiwiproc.processor.types.PrimitiveKiwiType;
import org.jspecify.annotations.Nullable;

public class CoreTypes {
public static final SimpleType STRING_TYPE = SimpleType.ofClass(String.class);
public static final BasicType STRING_TYPE =
new BasicType(String.class.getPackageName(), String.class.getSimpleName(), false);
public static final Set<Class<?>> BASIC_TYPES = Set.of(
String.class,
BigInteger.class,
Expand All @@ -39,7 +42,7 @@ public boolean hasWarning() {
}
}

public static final BiMap<Class<?>, Class<?>> primitiveToBoxed = BiMap.ofEntries(
public static final Map<Class<?>, Class<?>> primitiveToBoxed = Map.ofEntries(
entry(boolean.class, Boolean.class),
entry(byte.class, Byte.class),
entry(char.class, Character.class),
Expand All @@ -49,6 +52,10 @@ public boolean hasWarning() {
entry(float.class, Float.class),
entry(double.class, Double.class));

public static final Map<String, String> primitiveToBoxedStrings = primitiveToBoxed.entrySet().stream()
.map(e -> entry(e.getKey().getSimpleName(), e.getValue().getSimpleName()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

/*
The key type can be assigned to any of the value types without casting.
Primitive type mappings that are NOT in this map require a cast and a "lossy converson" warning.
Expand All @@ -68,7 +75,7 @@ private static boolean isAssignable(Class<?> source, Class<?> target) {
}

private final Conversion invalid = new Conversion(false, null, "invalid");
Map<Class<?>, SimpleType> coreTypes;
Map<Class<?>, KiwiType> coreTypes;
Map<TypeMapping, Conversion> coreMappings;

public CoreTypes() {
Expand All @@ -91,20 +98,20 @@ private Map<TypeMapping, Conversion> defineMappings() {
}

private void addPrimitiveParseMappings(Collection<Map.Entry<TypeMapping, Conversion>> entries) {
primitiveToBoxed.keysA().forEach(target -> {
primitiveToBoxed.keySet().forEach(target -> {
String warning = "possible NumberFormatException parsing String to %s".formatted(target.getName());
Class<?> boxed = primitiveToBoxed.getByA(target).orElseThrow();
Class<?> boxed = primitiveToBoxed.get(target);
// String -> primitive
TypeMapping t = new TypeMapping(STRING_TYPE, coreTypes.get(target));
Conversion c = new Conversion(
true,
warning,
"%s.parse%s(%%s)".formatted(boxed.getSimpleName(), Util.capitalizeFirst(target.getSimpleName())));
entries.add(Map.entry(t, c));
entries.add(entry(t, c));
// String -> boxed
t = new TypeMapping(STRING_TYPE, coreTypes.get(boxed));
c = new Conversion(true, warning, "%s.valueOf(%%s)".formatted(boxed.getSimpleName()));
entries.add(Map.entry(t, c));
entries.add(entry(t, c));
});
}

Expand All @@ -116,11 +123,6 @@ private void addBigNumberMappings(Collection<Map.Entry<TypeMapping, Conversion>>
Stream.of(byte.class, short.class, int.class, long.class, float.class, double.class)
.forEach(source -> {
entries.add(mappingEntry(source, big, null, "%s.valueOf(%%s)".formatted(big.getSimpleName())));
entries.add(mappingEntry(
primitiveToBoxed.getByA(source).orElseThrow(),
big,
null,
"%s.valueOf(%%s)".formatted(big.getSimpleName())));
});

// String -> Big
Expand All @@ -132,46 +134,27 @@ private void addBigNumberMappings(Collection<Map.Entry<TypeMapping, Conversion>>
.forEach(target -> {
String w = "possible lossy conversion from %s to %s".formatted(big.getName(), target.getName());
entries.add(mappingEntry(big, target, w, "%%s.%sValue()".formatted(target.getName())));
entries.add(mappingEntry(
big,
primitiveToBoxed.getByA(target).orElseThrow(),
w,
"%%s.%sValue()".formatted(target.getName())));
});
});
}

private void addPrimitiveMappings(Collection<Map.Entry<TypeMapping, Conversion>> entries) {
// boxing - is assignment
primitiveToBoxed.mapByA().forEach((source, target) -> entries.add(mappingEntry(source, target, null, "%s")));

// primitive safe assignments
assignableFrom.forEach((source, targets) -> {
targets.forEach(target -> {
// primitive
entries.add(mappingEntry(source, target, null, "%s"));
// also boxing
entries.add(mappingEntry(source, primitiveToBoxed.getByA(target).orElseThrow(), null, "%s"));
// also boxing both
entries.add(mappingEntry(
primitiveToBoxed.getByA(source).orElseThrow(),
primitiveToBoxed.getByA(target).orElseThrow(),
null,
"%s"));
});
});

// primitive lossy assignments
primitiveToBoxed.keysA().forEach(source -> {
primitiveToBoxed.keysA().forEach(target -> {
primitiveToBoxed.keySet().forEach(source -> {
primitiveToBoxed.keySet().forEach(target -> {
if (!source.equals(target) && !isAssignable(source, target)) {
String warning =
"possible lossy conversion from %s to %s".formatted(source.getName(), target.getName());
String conversionFormat = "(%s) %%s".formatted(target.getName());
entries.add(mappingEntry(source, target, warning, conversionFormat));
// also boxing
entries.add(mappingEntry(
source, primitiveToBoxed.getByA(target).orElseThrow(), warning, conversionFormat));
}
});
});
Expand All @@ -183,14 +166,16 @@ private Map.Entry<TypeMapping, Conversion> mappingEntry(
var toType = Objects.requireNonNull(coreTypes.get(target));
var mapping = new TypeMapping(fromType, toType);
var lookup = new Conversion(true, warning, conversionFormat);
return Map.entry(mapping, lookup);
return entry(mapping, lookup);
}

private Map<Class<?>, SimpleType> defineTypes() {
Map<Class<?>, SimpleType> builder = new LinkedHashMap<>(32);
primitiveToBoxed.keysA().forEach(c -> builder.put(c, SimpleType.ofClass(c)));
primitiveToBoxed.keysB().forEach(c -> builder.put(c, SimpleType.ofClass(c, true)));
BASIC_TYPES.forEach(c -> builder.put(c, SimpleType.ofClass(c)));
private Map<Class<?>, KiwiType> defineTypes() {
Map<Class<?>, KiwiType> builder = new LinkedHashMap<>(32);
primitiveToBoxed.forEach((key, value) -> {
builder.put(key, new PrimitiveKiwiType(key.getSimpleName(), false));
builder.put(value, new PrimitiveKiwiType(key.getSimpleName(), true));
});
BASIC_TYPES.forEach(c -> builder.put(c, new BasicType(c.getPackageName(), c.getSimpleName(), false)));
return Map.copyOf(builder);
}

Expand All @@ -202,13 +187,10 @@ public KiwiType type(Class<?> aClass) {
}

public Conversion lookup(TypeMapping mapper) {
if (mapper.source() instanceof SimpleType source && mapper.target() instanceof SimpleType target) {
return lookup(source, target);
}
return invalid;
return lookup(mapper.source(), mapper.target());
}

public Conversion lookup(SimpleType source, SimpleType target) {
public Conversion lookup(KiwiType source, KiwiType target) {
if (source.equals(target) || source.withIsNullable(true).equals(target)) {
return new Conversion(true, null, "%s");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import java.util.List;
import javax.lang.model.element.ExecutableElement;
import org.ethelred.kiwiproc.meta.ParsedQuery;
import org.ethelred.kiwiproc.processor.types.ContainerType;
import org.ethelred.kiwiproc.processor.types.KiwiType;
import org.jspecify.annotations.Nullable;

@KiwiRecordBuilder
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.ethelred.kiwiproc.processor;

import org.ethelred.kiwiproc.processor.types.KiwiType;

public record DAOResultColumn(String name, SqlTypeMapping sqlTypeMapping, KiwiType targetType) {
public TypeMapping asTypeMapping() {
return new TypeMapping(sqlTypeMapping.kiwiType(), targetType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import org.ethelred.kiwiproc.meta.DatabaseWrapper;
import org.ethelred.kiwiproc.meta.ParsedQuery;
import org.ethelred.kiwiproc.processor.generator.PoetDAOGenerator;
import org.ethelred.kiwiproc.processor.types.ContainerType;
import org.ethelred.kiwiproc.processor.types.RecordType;
import org.ethelred.kiwiproc.processorconfig.DataSourceConfig;
import org.ethelred.kiwiproc.processorconfig.DataSourceConfigJsonAdapter;
import org.ethelred.kiwiproc.processorconfig.ProcessorConfig;
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.List;
import javax.lang.model.type.*;
import javax.lang.model.util.SimpleTypeVisitor14;
import org.ethelred.kiwiproc.processor.types.*;

public class KiwiTypeVisitor extends SimpleTypeVisitor14<KiwiType, Void> {
private final TypeUtils utils;
Expand All @@ -14,7 +15,7 @@ public KiwiTypeVisitor(TypeUtils utils) {

@Override
public KiwiType visitPrimitive(PrimitiveType t, Void ignore) {
return new SimpleType("", t.toString(), false);
return new PrimitiveKiwiType(t.toString(), false);
}

@Override
Expand All @@ -24,11 +25,15 @@ public KiwiType visitArray(ArrayType t, Void ignore) {

@Override
public KiwiType visitDeclared(DeclaredType t, Void ignore) {
if (utils.isBoxed(t)) {
return new SimpleType(utils.packageName(t), utils.className(t), true);
try {
var primitiveType = utils.unboxedType(t);
return new PrimitiveKiwiType(primitiveType.toString(), true);

} catch (IllegalArgumentException e) {
// not a boxed type - continue
}
if (CoreTypes.BASIC_TYPES.stream().anyMatch(bt -> utils.isSameType(t, utils.type(bt)))) {
return new SimpleType(utils.packageName(t), utils.className(t), utils.isNullable(t));
return new BasicType(utils.packageName(t), utils.className(t), utils.isNullable(t));
}
for (var vct : ValidContainerType.values()) {
if (utils.isSameType(utils.erasure(t), utils.erasure(vct.javaType()))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.*;
import java.util.stream.Collectors;
import javax.lang.model.element.VariableElement;
import org.ethelred.kiwiproc.processor.types.KiwiType;
import org.jspecify.annotations.Nullable;

@KiwiRecordBuilder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import org.ethelred.kiwiproc.processor.types.KiwiType;

@KiwiRecordBuilder
public record Signature(KiwiType returnType, String methodName, List<String> paramNames) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import java.util.Map;
import java.util.stream.Collectors;
import org.ethelred.kiwiproc.meta.ColumnMetaData;
import org.ethelred.kiwiproc.processor.types.BasicType;
import org.ethelred.kiwiproc.processor.types.KiwiType;
import org.ethelred.kiwiproc.processor.types.PrimitiveKiwiType;
import org.ethelred.kiwiproc.processor.types.SqlArrayType;
import org.jspecify.annotations.Nullable;

@KiwiRecordBuilder
Expand Down Expand Up @@ -76,13 +80,9 @@ public KiwiType kiwiType() {
assert componentType != null;
return new SqlArrayType(componentType.kiwiType());
}
var resolvedType = baseType;
if (isNullable) {
var maybeBoxed = CoreTypes.primitiveToBoxed.getByA(baseType);
if (maybeBoxed.isPresent()) {
resolvedType = maybeBoxed.get();
}
if (CoreTypes.primitiveToBoxed.containsKey(baseType)) {
return new PrimitiveKiwiType(baseType().getSimpleName(), isNullable);
}
return SimpleType.ofClass(resolvedType, isNullable);
return new BasicType(baseType.getPackageName(), baseType.getSimpleName(), isNullable);
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package org.ethelred.kiwiproc.processor;

import org.ethelred.kiwiproc.processor.types.KiwiType;

public record TypeMapping(KiwiType source, KiwiType target) {}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import javax.lang.model.util.Elements;
import javax.lang.model.util.SimpleTypeVisitor14;
import javax.lang.model.util.Types;
import org.ethelred.kiwiproc.processor.types.KiwiType;
import org.ethelred.kiwiproc.processor.types.ValidContainerType;
import org.jspecify.annotations.Nullable;

public class TypeUtils extends TypeMirrors {
Expand Down
Loading

0 comments on commit 9b0f878

Please sign in to comment.