added setterIterator and jdbc module
This commit is contained in:
parent
4d1ae5acf4
commit
f778f0456c
24 changed files with 359 additions and 66 deletions
14
demo/pom.xml
14
demo/pom.xml
|
|
@ -18,19 +18,9 @@
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>nl.sanderhautvast</groupId>
|
||||||
<artifactId>contiguous</artifactId>
|
<artifactId>contiguous-jdbc</artifactId>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-web</artifactId>
|
|
||||||
<version>2.7.12</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.springframework.boot</groupId>
|
|
||||||
<artifactId>spring-boot-starter-data-jdbc</artifactId>
|
|
||||||
<version>2.7.12</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
|
|
@ -55,7 +45,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
<version>2.7.10</version>
|
<version>2.7.12</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<mainClass>nl.sanderhautvast.contiguous.demo.DemoApplication</mainClass>
|
<mainClass>nl.sanderhautvast.contiguous.demo.DemoApplication</mainClass>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package nl.sanderhautvast.contiguous.demo.repository;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import nl.sanderhautvast.contiguous.ContiguousList;
|
import nl.sanderhautvast.contiguous.ContiguousList;
|
||||||
|
import nl.sanderhautvast.contiguous.JdbcResults;
|
||||||
import nl.sanderhautvast.contiguous.demo.model.Customer;
|
import nl.sanderhautvast.contiguous.demo.model.Customer;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
|
@ -21,20 +22,7 @@ public class CustomerRepository {
|
||||||
|
|
||||||
public ContiguousList<Customer> getAllCustomers() {
|
public ContiguousList<Customer> getAllCustomers() {
|
||||||
return jdbcTemplate.query("select * from customers limit 5", rs -> {
|
return jdbcTemplate.query("select * from customers limit 5", rs -> {
|
||||||
ContiguousList<Customer> customers = new ContiguousList<>(Customer.class);
|
return JdbcResults.toList(rs, Customer.class);
|
||||||
while (rs.next()) {
|
|
||||||
Customer customer = Customer.builder()
|
|
||||||
.name(rs.getString("name"))
|
|
||||||
.email(rs.getString("email"))
|
|
||||||
.streetname(rs.getString("streetname"))
|
|
||||||
.housenumber(rs.getInt("housenumber"))
|
|
||||||
.city(rs.getString("city"))
|
|
||||||
.country(rs.getString("country"))
|
|
||||||
.build();
|
|
||||||
log.info("{}", customer);
|
|
||||||
customers.add(customer);
|
|
||||||
}
|
|
||||||
return customers;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>nl.sanderhautvast</groupId>
|
||||||
<artifactId>contiguous-jackson</artifactId>
|
<artifactId>contiguous-jackson</artifactId>
|
||||||
<version>1.1</version>
|
<version>1.1</version>
|
||||||
|
<description>Using Jackson to convert Contiguous data to JSON</description>
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
|
|
||||||
52
jdbc/pom.xml
Normal file
52
jdbc/pom.xml
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<groupId>nl.sanderhautvast</groupId>
|
||||||
|
<artifactId>contiguous-jdbc</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<description>JDBC functions for Contiguous data</description>
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>11</maven.compiler.source>
|
||||||
|
<maven.compiler.target>11</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>nl.sanderhautvast</groupId>
|
||||||
|
<artifactId>contiguous</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-engine</artifactId>
|
||||||
|
<version>5.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.junit.jupiter</groupId>
|
||||||
|
<artifactId>junit-jupiter-api</artifactId>
|
||||||
|
<version>5.8.2</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-junit-jupiter -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-junit-jupiter</artifactId>
|
||||||
|
<version>5.3.1</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.projectlombok</groupId>
|
||||||
|
<artifactId>lombok</artifactId>
|
||||||
|
<version>1.18.26</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
package nl.sanderhautvast.contiguous;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables the end user to add values from JDBC to a list of results without creating Objects.
|
||||||
|
* Every property must have a corresponding field in the ResultSet record (table/view/join etc)
|
||||||
|
* optionally applying a name mapping if they are not equal
|
||||||
|
* <p>
|
||||||
|
* // what about null values?
|
||||||
|
* // test test test
|
||||||
|
*/
|
||||||
|
public class JdbcResults {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the data to an existing CList
|
||||||
|
*
|
||||||
|
* @param result the JDBC ResultSet
|
||||||
|
* @param list The list to add to
|
||||||
|
* @throws SQLException when db throws error..
|
||||||
|
*/
|
||||||
|
public static void addAll(ResultSet result, ContiguousList<?> list) throws SQLException {
|
||||||
|
addAll(result, list, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the data to an existing CList.
|
||||||
|
*
|
||||||
|
* @param result the JDBC ResultSet
|
||||||
|
* @param list The list to add to
|
||||||
|
* @param fieldNameMapper maps the name from the element type property to the actual database column name
|
||||||
|
* @throws SQLException when db throws error..
|
||||||
|
*/
|
||||||
|
public static void addAll(ResultSet result, ContiguousList<?> list, Function<String, String> fieldNameMapper) throws SQLException {
|
||||||
|
ContiguousList<?>.SetterIterator setterIterator = list.setterIterator();
|
||||||
|
while (result.next()) {
|
||||||
|
while (setterIterator.hasNext()) {
|
||||||
|
ContiguousList<?>.Setter next = setterIterator.next();
|
||||||
|
String fieldName = next.getFieldName();
|
||||||
|
Object fieldValue;
|
||||||
|
if (fieldName != null) {
|
||||||
|
fieldValue = result.getObject(fieldNameMapper.apply(fieldName));
|
||||||
|
} else {
|
||||||
|
// assume single Primitive as Contiguous<String>, so just 1 column in the record
|
||||||
|
fieldValue = result.getObject(1);
|
||||||
|
}
|
||||||
|
next.set(fieldValue);
|
||||||
|
}
|
||||||
|
setterIterator.nextRecord();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as addAll, but creates a new CList.
|
||||||
|
*
|
||||||
|
* @param result The CList
|
||||||
|
* @param elementType the desired Object type
|
||||||
|
* @throws SQLException when db throws error..
|
||||||
|
*/
|
||||||
|
public static <E> ContiguousList<E> toList(ResultSet result, Class<E> elementType) throws SQLException {
|
||||||
|
ContiguousList<E> list = new ContiguousList<>(elementType);
|
||||||
|
return toList(result, elementType, Function.identity());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as addAll, but creates a new CList.
|
||||||
|
*
|
||||||
|
* @param result The CList
|
||||||
|
* @param elementType the desired Object type
|
||||||
|
* @param fieldNameMapper maps the name from the element type property to the actual database column name
|
||||||
|
* @throws SQLException when db throws error..
|
||||||
|
*/
|
||||||
|
public static <E> ContiguousList<E> toList(ResultSet result, Class<E> elementType, Function<String, String> fieldNameMapper) throws SQLException {
|
||||||
|
ContiguousList<E> list = new ContiguousList<>(elementType);
|
||||||
|
addAll(result, list, fieldNameMapper);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,71 @@
|
||||||
|
package nl.sanderhautvast.contiguous;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
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.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class JdbcResultsTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ResultSet mockResults;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListOfString() throws SQLException {
|
||||||
|
when(mockResults.next()).thenReturn(true, false);
|
||||||
|
when(mockResults.getObject(1)).thenReturn("Zaphod");
|
||||||
|
|
||||||
|
List<String> presidents = JdbcResults.toList(mockResults, String.class);
|
||||||
|
assertFalse(presidents.isEmpty());
|
||||||
|
assertEquals(1, presidents.size());
|
||||||
|
|
||||||
|
String president = presidents.get(0);
|
||||||
|
assertEquals("Zaphod", president);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testListOfBean() throws SQLException {
|
||||||
|
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");
|
||||||
|
when(mockResults.getObject("age")).thenReturn(42); // coincidence?
|
||||||
|
|
||||||
|
List<President> presidents = JdbcResults.toList(mockResults, President.class);
|
||||||
|
assertFalse(presidents.isEmpty());
|
||||||
|
assertEquals(1, presidents.size());
|
||||||
|
|
||||||
|
President president = presidents.get(0);
|
||||||
|
assertEquals("Zaphod", president.getName());
|
||||||
|
assertEquals(42, president.getAge());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMapping() throws SQLException {
|
||||||
|
when(mockResults.next()).thenReturn(true, false);
|
||||||
|
when(mockResults.getObject("name")).thenReturn("Trillian");
|
||||||
|
when(mockResults.getObject("realName")).thenReturn("Tricia MacMillan");
|
||||||
|
|
||||||
|
Map<String, String> nameMapping = Map.of("name", "name", "earthName", "realName");
|
||||||
|
List<Scientist> scientists = JdbcResults.toList(mockResults, Scientist.class, nameMapping::get);
|
||||||
|
|
||||||
|
assertFalse(scientists.isEmpty());
|
||||||
|
assertEquals(1, scientists.size());
|
||||||
|
|
||||||
|
Scientist scientist = scientists.get(0);
|
||||||
|
assertEquals("Trillian", scientist.getName());
|
||||||
|
assertEquals("Tricia MacMillan", scientist.getEarthName());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
package nl.sanderhautvast.contiguous;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class President {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private int age;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package nl.sanderhautvast.contiguous;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class Scientist {
|
||||||
|
private String name;
|
||||||
|
private String earthName;
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<groupId>nl.sanderhautvast</groupId>
|
<groupId>nl.sanderhautvast</groupId>
|
||||||
<artifactId>contiguous</artifactId>
|
<artifactId>contiguous</artifactId>
|
||||||
<description>Datastructures with contiguous storage</description>
|
<description>Datastructures with contiguous storage. Core library with no external dependencies</description>
|
||||||
<version>1.0-SNAPSHOT</version>
|
<version>1.0-SNAPSHOT</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
class BigDecimalHandler extends BuiltinTypeHandler<BigDecimal> {
|
class BigDecimalHandler extends BuiltinTypeHandler<BigDecimal> {
|
||||||
public BigDecimalHandler(MethodHandle getter, MethodHandle setter) {
|
public BigDecimalHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(BigDecimal.class, getter, setter);
|
super(BigDecimal.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
|
||||||
class BigIntegerHandler extends BuiltinTypeHandler<BigInteger> {
|
class BigIntegerHandler extends BuiltinTypeHandler<BigInteger> {
|
||||||
public BigIntegerHandler(MethodHandle getter, MethodHandle setter) {
|
public BigIntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(BigInteger.class, getter, setter);
|
super(BigInteger.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ 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 BuiltinTypeHandler<T> extends TypeHandler {
|
public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
public BuiltinTypeHandler(Class<?> type, MethodHandle getter, MethodHandle setter) {
|
public BuiltinTypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||||
super(type, getter, setter);
|
super(type, name, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -29,6 +29,10 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
store(propertyValue, typedList);
|
store(propertyValue, typedList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
||||||
|
store((T)value, contiguousList);
|
||||||
|
}
|
||||||
|
|
||||||
private T getValue(Object propertyValue) {
|
private T getValue(Object propertyValue) {
|
||||||
// I don't trust this
|
// I don't trust this
|
||||||
if (getter == null) {
|
if (getter == null) {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
*/
|
*/
|
||||||
class ByteHandler extends BuiltinTypeHandler<Byte> {
|
class ByteHandler extends BuiltinTypeHandler<Byte> {
|
||||||
|
|
||||||
public ByteHandler(MethodHandle getter, MethodHandle setter) {
|
public ByteHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Byte.class, getter, setter);
|
super(Byte.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ class CompoundTypeHandler extends TypeHandler {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CompoundTypeHandler(Class<?> type) {
|
CompoundTypeHandler(Class<?> type, String propertyName) {
|
||||||
super(type, null,null);
|
super(type, propertyName, null,null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,17 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
//notes:
|
//notes:
|
||||||
//1. should find out growth factor of arraylist
|
// should find out growth factor of arraylist
|
||||||
//2. elementIndices can be arrayList
|
// investigate data array reuse (pooling, SoftReferences etc)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Short for Contiguous Layout List, an Experimental List implementation
|
* Short for Contiguous Layout List, an Experimental List implementation
|
||||||
* Behaves like an ArrayList in that it's resizable and indexed.
|
* Behaves like an ArrayList in that it's resizable and indexed.
|
||||||
* The difference is that it uses an efficiently dehydrated version of the object in a cpu cache friendly, contiguous storage in a bytearray,
|
* The difference is that it uses an efficiently dehydrated version of the object in a cpu cache friendly, contiguous storage in a bytearray,
|
||||||
* without object instance overhead.
|
* without object instance overhead.
|
||||||
* <p>
|
* <p>
|
||||||
* Only uses reflection api on creation of the list.
|
* Only uses reflection api on creation of the list (and in the get() method, but the end user should employ value
|
||||||
|
* iteration rather than element iteration using said get method).
|
||||||
* Adding/Retrieving/Deleting depend on VarHandles and are aimed to be O(L) runtime complexity
|
* Adding/Retrieving/Deleting depend on VarHandles and are aimed to be O(L) runtime complexity
|
||||||
* where L is the nr of attributes to get/set from the objects (recursively).So O(1) for length of the list
|
* where L is the nr of attributes to get/set from the objects (recursively).So O(1) for length of the list
|
||||||
* <p>
|
* <p>
|
||||||
|
|
@ -35,6 +37,11 @@ import java.util.*;
|
||||||
* Implements java.util.List but some methods are not (yet) implemented mainly because they don't make much sense
|
* Implements java.util.List but some methods are not (yet) implemented mainly because they don't make much sense
|
||||||
* performance-wise, like the indexed add and set methods. They mess with the memory layout. The list is meant to
|
* performance-wise, like the indexed add and set methods. They mess with the memory layout. The list is meant to
|
||||||
* be appended at the tail.
|
* be appended at the tail.
|
||||||
|
* <p>
|
||||||
|
* What I think is a potential use case is a simple CRUD application.
|
||||||
|
* Here it would become possible to skip Object (when reading from the database),
|
||||||
|
* and directly map the results to JSON. Both writing and reading should ideally be faster
|
||||||
|
* than doing it the regular way.
|
||||||
*/
|
*/
|
||||||
public class ContiguousList<E> extends NotImplementedList<E> implements List<E> {
|
public class ContiguousList<E> extends NotImplementedList<E> implements List<E> {
|
||||||
|
|
||||||
|
|
@ -52,7 +59,8 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
|
|
||||||
private int currentElementValueIndex;
|
private int currentElementValueIndex;
|
||||||
|
|
||||||
private int[] elementIndices = new int[10];
|
private int[] elementIndices = new int[10]; // avoids autoboxing. Could also use standard ArrayList though
|
||||||
|
// is there a standard lib IntList??
|
||||||
|
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
|
|
@ -75,7 +83,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
if (PropertyHandlerFactory.isKnownType(type)) {
|
if (PropertyHandlerFactory.isKnownType(type)) {
|
||||||
this.rootHandler = PropertyHandlerFactory.forType(type);
|
this.rootHandler = PropertyHandlerFactory.forType(type);
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler compoundType = new CompoundTypeHandler(type);
|
CompoundTypeHandler compoundType = new CompoundTypeHandler(type, null);//TODO revisit
|
||||||
this.rootHandler = compoundType;
|
this.rootHandler = compoundType;
|
||||||
try {
|
try {
|
||||||
addPropertyHandlersForCompoundType(type, compoundType);
|
addPropertyHandlersForCompoundType(type, compoundType);
|
||||||
|
|
@ -95,11 +103,11 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
|
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
|
||||||
|
|
||||||
if (PropertyHandlerFactory.isKnownType(fieldType)) {
|
if (PropertyHandlerFactory.isKnownType(fieldType)) {
|
||||||
BuiltinTypeHandler<?> primitiveType = PropertyHandlerFactory.forType(fieldType, getter, setter);
|
BuiltinTypeHandler<?> primitiveType = PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
||||||
|
|
||||||
parentCompoundType.addHandler(field.getName(), primitiveType);
|
parentCompoundType.addHandler(field.getName(), primitiveType);
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler newParent = new CompoundTypeHandler(fieldType);
|
CompoundTypeHandler newParent = new CompoundTypeHandler(fieldType, field.getName());
|
||||||
newParent.setGetter(getter);
|
newParent.setGetter(getter);
|
||||||
newParent.setSetter(setter);
|
newParent.setSetter(setter);
|
||||||
parentCompoundType.addChild(field, newParent);
|
parentCompoundType.addChild(field, newParent);
|
||||||
|
|
@ -170,7 +178,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
try {
|
try {
|
||||||
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
||||||
Object read = ValueReader.read(data);
|
Object read = ValueReader.read(data);
|
||||||
return (E) ((BuiltinTypeHandler<?>) rootHandler).transform(read);
|
return (E) ((BuiltinTypeHandler<?>) rootHandler).cast(read);
|
||||||
}
|
}
|
||||||
// create a new instance of the list element type
|
// create a new instance of the list element type
|
||||||
E newInstance = (E) rootHandler.getType().getDeclaredConstructor().newInstance();
|
E newInstance = (E) rootHandler.getType().getDeclaredConstructor().newInstance();
|
||||||
|
|
@ -295,14 +303,74 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
handler = typeHandlersIterator.next();
|
handler = typeHandlersIterator.next();
|
||||||
|
|
||||||
return handler.transform(rawValue);
|
return handler.cast(rawValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Iterator} over the property values of the specified element in the List.
|
* Allows 'iterating insertion of data'. Returns an iterator of Setter
|
||||||
|
* Does not work for compound types yet
|
||||||
*
|
*
|
||||||
* @return
|
* @return A Reusable iterator
|
||||||
|
*/
|
||||||
|
public SetterIterator setterIterator() {
|
||||||
|
return new SetterIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Setter {
|
||||||
|
|
||||||
|
private final BuiltinTypeHandler<?> currentHandler;
|
||||||
|
|
||||||
|
public Setter(BuiltinTypeHandler<?> currentHandler) {
|
||||||
|
this.currentHandler = currentHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFieldName() {
|
||||||
|
return currentHandler.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(Object fieldValue) {
|
||||||
|
currentHandler.storeValue(fieldValue, ContiguousList.this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO proper naming
|
||||||
|
// BTW do we even need this as a class??
|
||||||
|
public class SetterIterator implements Iterator<Setter> {
|
||||||
|
private final List<Setter> properties = new ArrayList<>();
|
||||||
|
private Iterator<Setter> currentSetterIterator;
|
||||||
|
|
||||||
|
public SetterIterator() {
|
||||||
|
List<BuiltinTypeHandler<?>> builtinTypeHandlers = getBuiltinTypeHandlers();
|
||||||
|
for (BuiltinTypeHandler<?> builtinTypeHandler : builtinTypeHandlers) {
|
||||||
|
properties.add(new Setter(builtinTypeHandler));
|
||||||
|
}
|
||||||
|
// what to do with compound?
|
||||||
|
currentSetterIterator = this.properties.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
boolean hasNext = currentSetterIterator.hasNext();
|
||||||
|
if (!hasNext){
|
||||||
|
extend(); // marks the end of an object
|
||||||
|
}
|
||||||
|
return hasNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Setter next() {
|
||||||
|
return currentSetterIterator.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void nextRecord() {
|
||||||
|
currentSetterIterator = properties.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an {@link Iterator} over the property values of the specified element in the List.
|
||||||
*/
|
*/
|
||||||
public Iterator<Object> valueIterator(int index) {
|
public Iterator<Object> valueIterator(int index) {
|
||||||
//TODO
|
//TODO
|
||||||
|
|
@ -402,6 +470,12 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// to be called by framework to force element count
|
||||||
|
// used by SetterIterator
|
||||||
|
void extend() {
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
|
||||||
void storeLong(Long value) {
|
void storeLong(Long value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
store0();
|
store0();
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ import java.lang.invoke.MethodHandle;
|
||||||
* Stores a double value.
|
* Stores a double value.
|
||||||
*/
|
*/
|
||||||
class DoubleHandler extends BuiltinTypeHandler<Double> {
|
class DoubleHandler extends BuiltinTypeHandler<Double> {
|
||||||
public DoubleHandler(MethodHandle getter, MethodHandle setter) {
|
public DoubleHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Double.class, getter, setter);
|
super(Double.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package nl.sanderhautvast.contiguous;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
class FloatHandler extends BuiltinTypeHandler<Float> {
|
class FloatHandler extends BuiltinTypeHandler<Float> {
|
||||||
public FloatHandler(MethodHandle getter, MethodHandle setter) {
|
public FloatHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Float.class, getter, setter);
|
super(Float.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package nl.sanderhautvast.contiguous;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
class IntegerHandler extends BuiltinTypeHandler<Integer> {
|
class IntegerHandler extends BuiltinTypeHandler<Integer> {
|
||||||
public IntegerHandler(MethodHandle getter, MethodHandle setter) {
|
public IntegerHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Integer.class, getter, setter);
|
super(Integer.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package nl.sanderhautvast.contiguous;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
class LongHandler extends BuiltinTypeHandler<Long> {
|
class LongHandler extends BuiltinTypeHandler<Long> {
|
||||||
public LongHandler(MethodHandle getter, MethodHandle setter) {
|
public LongHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Long.class, getter, setter);
|
super(Long.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -41,14 +41,14 @@ final class PropertyHandlerFactory {
|
||||||
return TYPE_HANDLERS.containsKey(type);
|
return TYPE_HANDLERS.containsKey(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> BuiltinTypeHandler<T> forType(Class<T> type, MethodHandle getter, MethodHandle setter) {
|
public static <T> BuiltinTypeHandler<T> forType(Class<T> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||||
try {
|
try {
|
||||||
Class<? extends BuiltinTypeHandler<?>> appenderClass = TYPE_HANDLERS.get(type);
|
Class<? extends BuiltinTypeHandler<?>> appenderClass = TYPE_HANDLERS.get(type);
|
||||||
if (appenderClass == null) {
|
if (appenderClass == null) {
|
||||||
throw new IllegalStateException("No Handler for " + type.getName());
|
throw new IllegalStateException("No Handler for " + type.getName());
|
||||||
}
|
}
|
||||||
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(MethodHandle.class, MethodHandle.class)
|
return (BuiltinTypeHandler<T>) appenderClass.getDeclaredConstructor(String.class, MethodHandle.class, MethodHandle.class)
|
||||||
.newInstance(getter, setter);
|
.newInstance(name, getter, setter);
|
||||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||||
InvocationTargetException e) {
|
InvocationTargetException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
|
|
@ -56,7 +56,7 @@ final class PropertyHandlerFactory {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> BuiltinTypeHandler<T> forType(Class<T> type) {
|
public static <T> BuiltinTypeHandler<T> forType(Class<T> type) {
|
||||||
return forType(type, null, null);
|
return forType(type, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package nl.sanderhautvast.contiguous;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
class ShortHandler extends BuiltinTypeHandler<Short> {
|
class ShortHandler extends BuiltinTypeHandler<Short> {
|
||||||
public ShortHandler(MethodHandle getter, MethodHandle setter) {
|
public ShortHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(Short.class, getter, setter);
|
super(Short.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ package nl.sanderhautvast.contiguous;
|
||||||
import java.lang.invoke.MethodHandle;
|
import java.lang.invoke.MethodHandle;
|
||||||
|
|
||||||
class StringHandler extends BuiltinTypeHandler<String> {
|
class StringHandler extends BuiltinTypeHandler<String> {
|
||||||
public StringHandler(MethodHandle getter, MethodHandle setter) {
|
public StringHandler(String propertyName, MethodHandle getter, MethodHandle setter) {
|
||||||
super(String.class, getter, setter);
|
super(String.class, propertyName, getter, setter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import java.lang.invoke.MethodHandle;
|
||||||
/**
|
/**
|
||||||
* Abstract basertype over handlers for 'primitives' (ie. long, but also Long,
|
* Abstract basertype over handlers for 'primitives' (ie. long, but also Long,
|
||||||
* String..=> built-in types) and compound types (your own).
|
* String..=> built-in types) and compound types (your own).
|
||||||
*
|
|
||||||
* Common ancestor primarily to iterator over properties of any type.
|
* Common ancestor primarily to iterator over properties of any type.
|
||||||
* The respective functions are completely different though, and we need `instanceof` to check for the
|
* The respective functions are completely different though, and we need `instanceof` to check for the
|
||||||
* actual type. (Rust enums!)
|
* actual type. (Rust enums!)
|
||||||
|
|
@ -15,9 +14,11 @@ public abstract class TypeHandler {
|
||||||
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
|
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
|
||||||
protected MethodHandle setter;
|
protected MethodHandle setter;
|
||||||
private final Class<?> type;
|
private final Class<?> type;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
public TypeHandler(Class<?> type, MethodHandle getter, MethodHandle setter) {
|
public TypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
this.name = name;
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
}
|
}
|
||||||
|
|
@ -42,4 +43,7 @@ public abstract class TypeHandler {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
pom.xml
1
pom.xml
|
|
@ -10,6 +10,7 @@
|
||||||
<modules>
|
<modules>
|
||||||
<module>lib</module>
|
<module>lib</module>
|
||||||
<module>demo</module>
|
<module>demo</module>
|
||||||
|
<module>jdbc</module>
|
||||||
<module>jackson</module>
|
<module>jackson</module>
|
||||||
</modules>
|
</modules>
|
||||||
<name>contiguous</name>
|
<name>contiguous</name>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue