replaced MethodHandles with custom reflection-less reflectivity

This commit is contained in:
Shautvast 2023-08-23 09:14:09 +02:00
parent d7d4ca06fc
commit 938f6e9521
26 changed files with 103 additions and 54 deletions

View file

@ -29,7 +29,7 @@ public class CustomerRepository {
}
public List<Customer> getAllCustomersTraditional() {
return jdbcTemplate.query("select * from customers", (rs, rowNum) -> new Customer(
return jdbcTemplate.query("select * from customers limit 10000", (rs, rowNum) -> new Customer(
rs.getString("name"),rs.getString("email"),
rs.getString("streetname"), rs.getInt("housenumber"),
rs.getString("city"), rs.getString("country")

View file

@ -22,7 +22,8 @@ public class ListSerializer extends StdSerializer<ContiguousList<?>> {
Iterator<String> jsons = clist.jsonIterator();
while (jsons.hasNext()) {
generator.writeRawValue(jsons.next());
String next = jsons.next();
generator.writeRawValue(next);
}
generator.writeEndArray();

View file

@ -10,16 +10,16 @@ import static org.junit.jupiter.api.Assertions.*;
class ListSerializerTest {
private ObjectMapper mapper;
@BeforeEach
public void setup(){
public void setup() {
mapper = new ObjectMapper();
final SimpleModule module = new SimpleModule("mySerializers");
module.addSerializer(new ListSerializer());
mapper.registerModule(module);
}
@Test
public void testStringList() throws JsonProcessingException {
ContiguousList<String> strings = new ContiguousList<>(String.class);
@ -42,7 +42,6 @@ class ListSerializerTest {
strings.add(new AdamsObject("Publishing houses of Ursa Minor"));
String json = mapper.writeValueAsString(strings);
assertEquals("[{\"name\": \"Vogon constructor fleet\"}," +
"{\"name\": \"Restaurant at the end of the Galaxy\"}," +

View file

@ -1,26 +1,22 @@
package com.github.shautvast.contiguous;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.Mockito;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class JdbcResultsTest {
@Mock
private ResultSet mockResults;
@Test
public void testListOfString() throws SQLException {
ResultSet mockResults = Mockito.mock(ResultSet.class);
when(mockResults.next()).thenReturn(true, false);
when(mockResults.getObject(1)).thenReturn("Zaphod");
@ -35,6 +31,7 @@ class JdbcResultsTest {
@Test
public void testListOfBean() throws SQLException {
ResultSet mockResults = Mockito.mock(ResultSet.class);
when(mockResults.next()).thenReturn(true, false);
// the shape of the result equals that of the result (name:String, age:int)
when(mockResults.getObject("name")).thenReturn("Zaphod");
@ -51,6 +48,7 @@ class JdbcResultsTest {
@Test
public void testNameMapping() throws SQLException {
ResultSet mockResults = Mockito.mock(ResultSet.class);
when(mockResults.next()).thenReturn(true, false);
when(mockResults.getObject("name")).thenReturn("Trillian");
when(mockResults.getObject("realName")).thenReturn("Tricia MacMillan");

View file

@ -12,7 +12,7 @@
<artifactId>contiguous</artifactId>
<description>Datastructures with contiguous storage. Core library with no external dependencies</description>
<description>Datastructures with contiguous storage. Core library</description>
<packaging>jar</packaging>
<properties>
@ -21,6 +21,11 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>com.github.shautvast</groupId>
<artifactId>reflective</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
@ -40,4 +45,12 @@
<scope>test</scope>
</dependency>
</dependencies>
<distributionManagement>
<repository>
<id>github</id>
<name>GitHub OWNER Apache Maven Packages</name>
<url>https://maven.pkg.github.com/shautvast/Contiguous</url>
</repository>
</distributionManagement>
</project>

View file

@ -1,10 +1,12 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
import java.math.BigDecimal;
class BigDecimalHandler extends BuiltinTypeHandler<BigDecimal> {
public BigDecimalHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public BigDecimalHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(BigDecimal.class, propertyName, getter, setter);
}

View file

@ -1,10 +1,12 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
import java.math.BigInteger;
class BigIntegerHandler extends BuiltinTypeHandler<BigInteger> {
public BigIntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public BigIntegerHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(BigInteger.class, propertyName, getter, setter);
}

View file

@ -1,10 +1,8 @@
package com.github.shautvast.contiguous;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* Boundless cache something

View file

@ -1,6 +1,6 @@
package com.github.shautvast.contiguous;
import java.lang.invoke.MethodHandle;
import com.github.shautvast.reflective.MetaMethod;
/**
* Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage.
@ -12,7 +12,7 @@ import java.lang.invoke.MethodHandle;
* ie. when a bean is added or retrieved from the list
*/
abstract class BuiltinTypeHandler<T> extends TypeHandler {
public BuiltinTypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
public BuiltinTypeHandler(Class<?> type, String name, MetaMethod getter, MetaMethod setter) {
super(type, name, getter, setter);
}
@ -38,9 +38,9 @@ abstract class BuiltinTypeHandler<T> extends TypeHandler {
if (getter == null) {
return (T) propertyValue;
}
System.out.println(propertyValue.getClass());
try {
return (T) getter.invoke(propertyValue);
return (T) getter.invoke(propertyValue).unwrap();
} catch (Throwable e) {
throw new IllegalStateException(e);
}
@ -57,8 +57,11 @@ abstract class BuiltinTypeHandler<T> extends TypeHandler {
* @param value the value that has been read from ContiguousList storage
*/
public void setValue(Object instance, Object value) {
System.out.println(instance.getClass());
System.out.println(cast(value));
System.out.println(setter.getMetaClass().getJavaClass().getName());
try {
setter.invokeWithArguments(instance, cast(value));
setter.invoke(instance, cast(value)).unwrap();
} catch (Throwable e) {
throw new IllegalStateException(e);
}

View file

@ -1,5 +1,7 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
/**
@ -7,7 +9,7 @@ import java.lang.invoke.MethodHandle;
*/
class ByteHandler extends BuiltinTypeHandler<Byte> {
public ByteHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public ByteHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Byte.class, propertyName, getter, setter);
}

View file

@ -1,5 +1,10 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.InvokerFactory;
import com.github.shautvast.reflective.MetaClass;
import com.github.shautvast.reflective.MetaMethod;
import com.github.shautvast.reflective.Reflective;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.InvocationTargetException;
@ -73,7 +78,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
elementIndices.add(0); // index of first element
}
public void close(){
public void close() {
BufferCache.release(this.data);
}
@ -100,13 +105,15 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
* using reflection find all properties in the element, recursing down when the property is compound
*/
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundTypeHandler parentCompoundType) {
final MethodHandles.Lookup lookup = getLookup(type);
MetaClass metaType = Reflective.getMetaClass(type);
Arrays.stream(type.getDeclaredFields())
.forEach(field -> {
try {
Class<?> fieldType = field.getType();
MethodHandle getter = lookup.findGetter(type, field.getName(), fieldType);
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
String capitalized = capitalize(field.getName());
MetaMethod getter = metaType.getMethod("get" + capitalized).get();
MetaMethod setter = metaType.getMethod("set" + capitalized).get();
Optional<TypeHandler> typeHandler = PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
if (typeHandler.isPresent()) {
@ -161,7 +168,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
} else {
CompoundTypeHandler child = ((CompoundTypeHandler) property);
try {
Object result = child.getGetter().invoke(element);
Object result = child.getGetter().invoke(element).unwrap();
storePropertyData(result, child);
} catch (Throwable e) {
throw new RuntimeException(e);
@ -213,7 +220,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
compoundType.getProperties().forEach(property -> {
if (property instanceof BuiltinTypeHandler) {
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
type.setValue(element, ValueReader.read(data));
Object readValue = ValueReader.read(data);
System.out.println(readValue);
type.setValue(element, readValue);
} else {
try {
CompoundTypeHandler p = (CompoundTypeHandler) property;
@ -221,7 +230,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
Object newInstance = p.getType().getDeclaredConstructor().newInstance();
// set it on the parent
p.getSetter().invokeWithArguments(element, newInstance);
p.getSetter().invoke(element, newInstance);
// recurse down
copyDataIntoNewObject(newInstance, p);
@ -615,8 +624,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
private void ensureFree(int length) {
while (bufferPosition + length > data.capacity()) {
ByteBuffer bytes = this.data;
bytes.position(0);
BufferCache.release(this.data);
this.data = BufferCache.get((int)(bytes.capacity() * 1.5));
this.data = BufferCache.get((int) (bytes.capacity() * 1.5));
this.data.put(bytes);
}
}
@ -745,4 +755,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
} else return Varint.write(6);
}
}
private String capitalize(String text) {
return text.substring(0, 1).toUpperCase() + text.substring(1);
}
}

View file

@ -1,12 +1,14 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
/**
* Stores a double value.
*/
class DoubleHandler extends BuiltinTypeHandler<Double> {
public DoubleHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public DoubleHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Double.class, propertyName, getter, setter);
}

View file

@ -1,9 +1,11 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
class FloatHandler extends BuiltinTypeHandler<Float> {
public FloatHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public FloatHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Float.class, propertyName, getter, setter);
}

View file

@ -1,9 +1,11 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
class IntegerHandler extends BuiltinTypeHandler<Integer> {
public IntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public IntegerHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Integer.class, propertyName, getter, setter);
}

View file

@ -1,9 +1,11 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
class LongHandler extends BuiltinTypeHandler<Long> {
public LongHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public LongHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Long.class, propertyName, getter, setter);
}

View file

@ -4,7 +4,7 @@ import java.util.*;
import java.util.function.UnaryOperator;
/**
* Base class that is a list of all the methods live that will likely not be implemented (pun intended)
* Base class with all the methods that will not be implemented
* Only purpose: reduce linecount in the subclass.
*
* @param <E>

View file

@ -1,5 +1,7 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
@ -38,10 +40,10 @@ final class PropertyHandlerFactory {
}
@SuppressWarnings("unchecked")
public static <T> Optional<TypeHandler> forType(Class<T> type, String name, MethodHandle getter, MethodHandle setter) {
public static <T> Optional<TypeHandler> forType(Class<T> type, String name, MetaMethod getter, MetaMethod setter) {
return Optional.ofNullable(BUILTIN.get(type)).map(appenderClass -> {
try {
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class)
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MetaMethod.class, MetaMethod.class)
.newInstance(name, getter, setter);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {

View file

@ -1,9 +1,11 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
class ShortHandler extends BuiltinTypeHandler<Short> {
public ShortHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public ShortHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(Short.class, propertyName, getter, setter);
}

View file

@ -1,9 +1,11 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
class StringHandler extends BuiltinTypeHandler<String> {
public StringHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
public StringHandler(String propertyName, MetaMethod getter, MetaMethod setter) {
super(String.class, propertyName, getter, setter);
}

View file

@ -1,5 +1,7 @@
package com.github.shautvast.contiguous;
import com.github.shautvast.reflective.MetaMethod;
import java.lang.invoke.MethodHandle;
/**
@ -11,8 +13,8 @@ import java.lang.invoke.MethodHandle;
*/
public abstract class TypeHandler {
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
protected MethodHandle setter;
protected MetaMethod getter; // both can be null, if it's for a known ('primitive') type
protected MetaMethod setter;
private final Class<?> type;
/**
@ -20,26 +22,26 @@ public abstract class TypeHandler {
*/
private final String name;
public TypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
public TypeHandler(Class<?> type, String name, MetaMethod getter, MetaMethod setter) {
this.type = type;
this.name = name;
this.getter = getter;
this.setter = setter;
}
void setGetter(MethodHandle getter) {
void setGetter(MetaMethod getter) {
this.getter = getter;
}
public MethodHandle getGetter() {
public MetaMethod getGetter() {
return getter;
}
public MethodHandle getSetter() {
public MetaMethod getSetter() {
return setter;
}
void setSetter(MethodHandle setter) {
void setSetter(MetaMethod setter) {
this.setter = setter;
}

View file

@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class ByteBean {
public class ByteBean {
byte value;
}

View file

@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class DoubleBean {
public class DoubleBean {
private Double value;

View file

@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class FloatBean {
public class FloatBean {
private Float value;
}

View file

@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class IntBean {
public class IntBean {
private int value;
}

View file

@ -7,6 +7,6 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class LongBean {
public class LongBean {
private long value;
}

View file

@ -7,7 +7,7 @@ import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class ShortBean {
public class ShortBean {
private short value;
}