From e1530d076c10d309fd3a901965bb1b32091c5110 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Thu, 25 May 2023 16:37:05 +0200 Subject: [PATCH] improvements --- .../contiguous/BigDecimalHandler.java | 21 ++++++++++ .../contiguous/BigIntegerHandler.java | 20 ++++++++++ .../contiguous/ContiguousList.java | 9 +++-- .../contiguous/PrimitiveType.java | 33 +++++++-------- .../contiguous/PropertyHandlerFactory.java | 40 ++++++++++++------- .../nl/sanderhautvast/contiguous/Type.java | 5 ++- .../contiguous/ContiguousListTest.java | 11 +++++ 7 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java create mode 100644 lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java new file mode 100644 index 0000000..6a183cb --- /dev/null +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/BigDecimalHandler.java @@ -0,0 +1,21 @@ +package nl.sanderhautvast.contiguous; + +import java.lang.invoke.MethodHandle; +import java.math.BigDecimal; +import java.math.BigInteger; + +class BigDecimalHandler extends PrimitiveType { + public BigDecimalHandler(MethodHandle getter, MethodHandle setter) { + super(BigDecimal.class, getter, setter); + } + + @Override + public void store(BigDecimal value, ContiguousList list) { + list.storeString(value.toString()); + } + + @Override + public Object transform(Object value) { + return new BigDecimal((String) value); + } +} diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java b/lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java new file mode 100644 index 0000000..f0d0c59 --- /dev/null +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/BigIntegerHandler.java @@ -0,0 +1,20 @@ +package nl.sanderhautvast.contiguous; + +import java.lang.invoke.MethodHandle; +import java.math.BigInteger; + +class BigIntegerHandler extends PrimitiveType { + public BigIntegerHandler(MethodHandle getter, MethodHandle setter) { + super(BigInteger.class, getter, setter); + } + + @Override + public void store(BigInteger value, ContiguousList list) { + list.storeString(value.toString()); + } + + @Override + public Object transform(Object value) { + return new BigInteger((String) value); + } +} diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java b/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java index 53d18f7..82d2500 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/ContiguousList.java @@ -22,9 +22,9 @@ import java.util.function.UnaryOperator; *

* Employs the SQLite style of data storage, most notably integer numbers are stored with variable byte length *

- * The classes stored in DehydrateList MUST have a no-args constructor. + * The classes stored in {@link ContiguousList} MUST have a no-args constructor. *

- * Like ArrayList mutating operations are not synchronized. + * Like ArrayList, mutating operations are not synchronized. *

* Does not allow null elements. *

@@ -169,7 +169,7 @@ public class ContiguousList implements List { data.position(elementIndices[index]); try { if (type instanceof PrimitiveType) { - return (E) ValueReader.read(data); + return (E)((PrimitiveType)type).transform(ValueReader.read(data)); } // create a new instance of the list element type E newInstance = (E) type.type.getDeclaredConstructor().newInstance(); @@ -187,7 +187,8 @@ public class ContiguousList implements List { private void setProperties(Object element, CompoundType compoundType) { compoundType.getProperties().forEach(property -> { if (property instanceof PrimitiveType) { - ((PrimitiveType) property).setValue(element, ValueReader.read(data)); + PrimitiveType type =((PrimitiveType) property); + type.setValue(element, ValueReader.read(data)); } else { try { CompoundType p = (CompoundType) property; diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java b/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java index 888ec28..89a527f 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/PrimitiveType.java @@ -2,7 +2,7 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -/* +/** * Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage. * * Can be extended for types that you need to handle. @@ -12,22 +12,6 @@ import java.lang.invoke.MethodHandle; * ie. when a bean is added or retrieved from the list */ public abstract class PrimitiveType extends Type { - - /* - * Apology: - * This was the simplest thing I could think of when trying to accomodate for nested types. - * - * What you end up with after inspection in the DehydrateList is a flat list of getters and setters - * of properties that are in a tree-like structure (primitive properties within (nested) compound types) - * So to read or write a property in a 'root object' (element type in list) with compound property types - * you first have to traverse to the bean graph to the right container (bean) of the property you set/get - * (that is what the childGetters are for) - * - * Ideally you'd do this only once per containing class. In the current implementation it's once per - * property in the containing class. - */ -// private final List childGetters = new ArrayList<>(); - public PrimitiveType(Class type, MethodHandle getter, MethodHandle setter) { super(type, getter, setter); } @@ -70,10 +54,23 @@ public abstract class PrimitiveType extends Type { */ public void setValue(Object instance, Object value) { try { - setter.invokeWithArguments(instance, value); + setter.invokeWithArguments(instance, transform(value)); } catch (Throwable e) { throw new IllegalStateException(e); } } + /** + * Certain types can easily be stored as another known type, for instance + * a BigDecimal can be stored as a String. + * + * The {@link PrimitiveType} for BigDecimal would in that case be responsible for turning the String + * into a BigDecimal. It can do that by overriding this method + * + * @param value raw value to transform to the desired output type + * @return the transformed object + */ + public Object transform(Object value){ + return value; + } } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java b/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java index de946bc..2e928a5 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/PropertyHandlerFactory.java @@ -2,6 +2,8 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; @@ -15,23 +17,24 @@ final class PropertyHandlerFactory { } static { - STANDARD_HANDLERS.put(String.class, StringHandler.class); - STANDARD_HANDLERS.put(byte.class, ByteHandler.class); - STANDARD_HANDLERS.put(Byte.class, ByteHandler.class); - STANDARD_HANDLERS.put(int.class, IntegerHandler.class); - STANDARD_HANDLERS.put(Integer.class, IntegerHandler.class); - STANDARD_HANDLERS.put(short.class, ShortHandler.class); - STANDARD_HANDLERS.put(Short.class, ShortHandler.class); - STANDARD_HANDLERS.put(long.class, LongHandler.class); - STANDARD_HANDLERS.put(Long.class, LongHandler.class); - STANDARD_HANDLERS.put(float.class, FloatHandler.class); - STANDARD_HANDLERS.put(Float.class, FloatHandler.class); - STANDARD_HANDLERS.put(double.class, DoubleHandler.class); - STANDARD_HANDLERS.put(Double.class, DoubleHandler.class); + register(String.class, StringHandler.class); + register(byte.class, ByteHandler.class); + register(Byte.class, ByteHandler.class); + register(int.class, IntegerHandler.class); + register(Integer.class, IntegerHandler.class); + register(short.class, ShortHandler.class); + register(Short.class, ShortHandler.class); + register(long.class, LongHandler.class); + register(Long.class, LongHandler.class); + register(float.class, FloatHandler.class); + register(Float.class, FloatHandler.class); + register(double.class, DoubleHandler.class); + register(Double.class, DoubleHandler.class); + register(BigDecimal.class, StringHandler.class); + register(BigInteger.class, BigIntegerHandler.class); + register(BigDecimal.class, BigDecimalHandler.class); //Date/Timestamp //LocalDate/time - //BigDecimal - //BigInteger } public static boolean isKnownType(Class type) { @@ -55,4 +58,11 @@ final class PropertyHandlerFactory { public static PrimitiveType forType(Class type) { return forType(type, null, null); } + + /** + * register a new TypeHandler that cannot be derived from bean properties + */ + public static void register(Class type, Class> typehandler) { + STANDARD_HANDLERS.put(type, typehandler); + } } diff --git a/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java b/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java index 5a745e4..d4cb2b0 100644 --- a/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java +++ b/lib/src/main/java/nl/sanderhautvast/contiguous/Type.java @@ -2,8 +2,11 @@ package nl.sanderhautvast.contiguous; import java.lang.invoke.MethodHandle; -/** +/* * ok, sorry + * + * I needed to abstract over handlers for 'primitives' (ie. long, but also Long, String..=> built-in types) and compound types (your own) + * So this is the common ancestor. The respective functions are completely different. */ public abstract class Type { diff --git a/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java b/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java index 809dfb3..8c18dce 100644 --- a/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java +++ b/lib/src/test/java/nl/sanderhautvast/contiguous/ContiguousListTest.java @@ -2,6 +2,7 @@ package nl.sanderhautvast.contiguous; import org.junit.jupiter.api.Test; +import java.math.BigInteger; import java.util.List; import static org.junit.jupiter.api.Assertions.*; @@ -129,5 +130,15 @@ public class ContiguousListTest { beanList.add(new StringBean(null)); } assertEquals(100, beanList.size()); + for (int i = 0; i < 100; i++) { + assertNull(beanList.get(i)); + } + } + + @Test + public void testBigInteger() { + ContiguousList bigIntegers = new ContiguousList<>(BigInteger.class); + bigIntegers.add(new BigInteger("1000000000")); + assertEquals(1_000_000_000L, bigIntegers.get(0).longValue()); } }