improvements

This commit is contained in:
Shautvast 2023-05-25 16:37:05 +02:00
parent 5619f8c2ae
commit e1530d076c
7 changed files with 101 additions and 38 deletions

View file

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

View file

@ -0,0 +1,20 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
import java.math.BigInteger;
class BigIntegerHandler extends PrimitiveType<BigInteger> {
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);
}
}

View file

@ -22,9 +22,9 @@ import java.util.function.UnaryOperator;
* <p> * <p>
* Employs the SQLite style of data storage, most notably integer numbers are stored with variable byte length * Employs the SQLite style of data storage, most notably integer numbers are stored with variable byte length
* <p> * <p>
* The classes stored in DehydrateList MUST have a no-args constructor. * The classes stored in {@link ContiguousList} MUST have a no-args constructor.
* <p> * <p>
* Like ArrayList mutating operations are not synchronized. * Like ArrayList, mutating operations are not synchronized.
* <p> * <p>
* Does not allow null elements. * Does not allow null elements.
* <p> * <p>
@ -169,7 +169,7 @@ public class ContiguousList<E> implements List<E> {
data.position(elementIndices[index]); data.position(elementIndices[index]);
try { try {
if (type instanceof PrimitiveType<?>) { 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 // create a new instance of the list element type
E newInstance = (E) type.type.getDeclaredConstructor().newInstance(); E newInstance = (E) type.type.getDeclaredConstructor().newInstance();
@ -187,7 +187,8 @@ public class ContiguousList<E> implements List<E> {
private void setProperties(Object element, CompoundType compoundType) { private void setProperties(Object element, CompoundType compoundType) {
compoundType.getProperties().forEach(property -> { compoundType.getProperties().forEach(property -> {
if (property instanceof PrimitiveType) { if (property instanceof PrimitiveType) {
((PrimitiveType<?>) property).setValue(element, ValueReader.read(data)); PrimitiveType<?> type =((PrimitiveType<?>) property);
type.setValue(element, ValueReader.read(data));
} else { } else {
try { try {
CompoundType p = (CompoundType) property; CompoundType p = (CompoundType) property;

View file

@ -2,7 +2,7 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle; 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. * 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. * 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 * ie. when a bean is added or retrieved from the list
*/ */
public abstract class PrimitiveType<T> extends Type { public abstract class PrimitiveType<T> 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<MethodHandle> childGetters = new ArrayList<>();
public PrimitiveType(Class<?> type, MethodHandle getter, MethodHandle setter) { public PrimitiveType(Class<?> type, MethodHandle getter, MethodHandle setter) {
super(type, getter, setter); super(type, getter, setter);
} }
@ -70,10 +54,23 @@ public abstract class PrimitiveType<T> extends Type {
*/ */
public void setValue(Object instance, Object value) { public void setValue(Object instance, Object value) {
try { try {
setter.invokeWithArguments(instance, value); setter.invokeWithArguments(instance, transform(value));
} catch (Throwable e) { } catch (Throwable e) {
throw new IllegalStateException(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;
}
} }

View file

@ -2,6 +2,8 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -15,23 +17,24 @@ final class PropertyHandlerFactory {
} }
static { static {
STANDARD_HANDLERS.put(String.class, StringHandler.class); register(String.class, StringHandler.class);
STANDARD_HANDLERS.put(byte.class, ByteHandler.class); register(byte.class, ByteHandler.class);
STANDARD_HANDLERS.put(Byte.class, ByteHandler.class); register(Byte.class, ByteHandler.class);
STANDARD_HANDLERS.put(int.class, IntegerHandler.class); register(int.class, IntegerHandler.class);
STANDARD_HANDLERS.put(Integer.class, IntegerHandler.class); register(Integer.class, IntegerHandler.class);
STANDARD_HANDLERS.put(short.class, ShortHandler.class); register(short.class, ShortHandler.class);
STANDARD_HANDLERS.put(Short.class, ShortHandler.class); register(Short.class, ShortHandler.class);
STANDARD_HANDLERS.put(long.class, LongHandler.class); register(long.class, LongHandler.class);
STANDARD_HANDLERS.put(Long.class, LongHandler.class); register(Long.class, LongHandler.class);
STANDARD_HANDLERS.put(float.class, FloatHandler.class); register(float.class, FloatHandler.class);
STANDARD_HANDLERS.put(Float.class, FloatHandler.class); register(Float.class, FloatHandler.class);
STANDARD_HANDLERS.put(double.class, DoubleHandler.class); register(double.class, DoubleHandler.class);
STANDARD_HANDLERS.put(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 //Date/Timestamp
//LocalDate/time //LocalDate/time
//BigDecimal
//BigInteger
} }
public static boolean isKnownType(Class<?> type) { public static boolean isKnownType(Class<?> type) {
@ -55,4 +58,11 @@ final class PropertyHandlerFactory {
public static <T> PrimitiveType<T> forType(Class<T> type) { public static <T> PrimitiveType<T> forType(Class<T> type) {
return forType(type, null, null); return forType(type, null, null);
} }
/**
* register a new TypeHandler that cannot be derived from bean properties
*/
public static void register(Class<?> type, Class<? extends PrimitiveType<?>> typehandler) {
STANDARD_HANDLERS.put(type, typehandler);
}
} }

View file

@ -2,8 +2,11 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandle;
/** /*
* ok, sorry * 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 { public abstract class Type {

View file

@ -2,6 +2,7 @@ package nl.sanderhautvast.contiguous;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.math.BigInteger;
import java.util.List; import java.util.List;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -129,5 +130,15 @@ public class ContiguousListTest {
beanList.add(new StringBean(null)); beanList.add(new StringBean(null));
} }
assertEquals(100, beanList.size()); assertEquals(100, beanList.size());
for (int i = 0; i < 100; i++) {
assertNull(beanList.get(i));
}
}
@Test
public void testBigInteger() {
ContiguousList<BigInteger> bigIntegers = new ContiguousList<>(BigInteger.class);
bigIntegers.add(new BigInteger("1000000000"));
assertEquals(1_000_000_000L, bigIntegers.get(0).longValue());
} }
} }