made it a little smarter and fixed some bugs along the way. Also a demo rest api, which is WIP

This commit is contained in:
Shautvast 2023-05-25 15:56:32 +02:00
parent 5dae158b1d
commit 5619f8c2ae
44 changed files with 922 additions and 435 deletions

86
demo/pom.xml Normal file
View file

@ -0,0 +1,86 @@
<?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-demo</artifactId>
<version>1.1</version>
<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.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>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.5.4</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.7.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.10</version>
<configuration>
<mainClass>nl.sanderhautvast.contiguous.demo.DemoApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View file

@ -0,0 +1,74 @@
package nl.sanderhautvast.contiguous.demo;
import lombok.extern.slf4j.Slf4j;
import nl.sanderhautvast.contiguous.demo.repository.RandomStuffGenerator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
@Slf4j
@SpringBootApplication
public class DemoApplication {
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.driverClass}")
private String driverClass;
@Value("${spring.datasource.username}")
private String username;
@Value("${spring.datasource.password}")
private String password;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
log.info("Loading the database with test data");
JdbcTemplate jdbcTemplate = new JdbcTemplate(datasource());
jdbcTemplate.execute("drop table if exists customers");
jdbcTemplate.execute("create table customers (name varchar(100), email varchar(100), streetname varchar(100), housenumber integer, city varchar(100), country varchar(100))");
final RandomStuffGenerator generator = new RandomStuffGenerator();
for (int i = 0; i < 100_000; i++) {
jdbcTemplate.update("insert into customers (name, email, streetname, housenumber, city, country) values(?,?,?,?,?,?)",
ps -> {
String firstName = generator.generateFirstName();
String lastName = generator.generateLastName();
ps.setString(1, firstName + " " + lastName);
ps.setString(2, firstName + "." + lastName + "@icemail.com");
ps.setString(3, generator.generateStreetName());
ps.setInt(4, generator.generateSomeNumber());
ps.setString(5, generator.generateSomeCityInIceland());
ps.setString(6, generator.generateIceland());
});
}
log.info("Database loading finished successfully");
};
}
@Bean
public JdbcTemplate jdbcTemplate() {
return new JdbcTemplate(datasource());
}
@Bean
public DataSource datasource() {
DataSourceBuilder<?> dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.driverClassName(driverClass);
dataSourceBuilder.url(url);
dataSourceBuilder.username(username);
dataSourceBuilder.password(password);
return dataSourceBuilder.build();
}
}

View file

@ -0,0 +1,15 @@
package nl.sanderhautvast.contiguous.demo.model;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Customer {
String name;
String email;
String streetname;
int housenumber;
String city;
String country;
}

View file

@ -0,0 +1,40 @@
package nl.sanderhautvast.contiguous.demo.repository;
import lombok.extern.slf4j.Slf4j;
import nl.sanderhautvast.contiguous.ContiguousList;
import nl.sanderhautvast.contiguous.demo.model.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
@Repository
@Slf4j
public class CustomerRepository {
private final JdbcTemplate jdbcTemplate;
@Autowired
public CustomerRepository(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public ContiguousList<Customer> getAllCustomers() {
return jdbcTemplate.query("select * from customers limit 5", rs -> {
ContiguousList<Customer> customers = new ContiguousList<>(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;
});
}
}

View file

@ -0,0 +1,54 @@
package nl.sanderhautvast.contiguous.demo.repository;
import java.util.List;
import java.util.Random;
public class RandomStuffGenerator {
private final List<String> firstNameParts = List.of("sa", "ka", "zo", "ja", "za", "ka", "po", "ji", "ne", "si", "wi", "ha", "ut", "va", "no", "bo"
, "jo", "fe", "gu");
private final List<String> lastNameParts = List.of("fin", "wil", "cat", "loc", "der", "ter", "asp", "pen", "ill", "raf", "gut", "dax", "yin");
private final List<String> cities = List.of("Reykjavík", "Kópavogur", "Hafnarfjörður", "Akureyri", "Reykjanesbær", "Garðabær", "Mosfellsbær", "Selfoss", "Akranes", "Seltjarnarnes", "Vestmannaeyjar", "Grindavík", "Ísafjörður", "Álftanes", "Sauðárkrókur", "Hveragerði", "Egilsstaðir", "Húsavík", "Borgarnes", "Sandgerði", "Höfn", "Þorlákshöfn", "Garður", "Neskaupstaður", "Dalvík", "Reyðarfjörður", "Siglufjörður", "Vogar", "Stykkishólmur", "Eskifjörður", "Ólafsvík", "Hvolsvöllur", "Bolungarvík", "Hella", "Grundarfjörður", "Blönduós", "Ólafsfjörður", "Fáskrúðsfjörður", "Patreksfjörður", "Seyðisfjörður", "Grundarhverfi", "Hvammstangi", "Stokkseyri", "Eyrarbakki", "Vopnafjörður", "Skagaströnd", "Flúðir", "Vík", "Fellabær", "Hellissandur", "Djúpivogur", "Þórshöfn", "Svalbarðseyri", "Hólmavík", "Grenivík", "Hvanneyri", "Þingeyri", "Búðardalur", "Reykholt", "Hrafnagil", "Suðureyri", "Tálknafjörður", "Bíldudalur", "Mosfellsdalur", "Hnífsdalur", "Reykjahlíð", "Laugarvatn", "Raufarhöfn", "Stöðvarfjörður", "Bifröst", "Flateyri", "Kirkjubæjarklaustur", "Súðavík", "Hrísey", "Hofsós", "Breiðdalsvík", "Rif", "Reykhólar", "Varmahlíð", "Kópasker", "Laugarás", "Borg", "Hauganes", "Hafnir", "Laugar", "Melahverfi", "Tjarnabyggð", "Árskógssandur", "Lónsbakki", "Hólar", "Nesjahverfi", "Sólheimar", "Brúnahlíð", "Drangsnes", "Borgarfjörður eystri", "Árbæjarhverfi", "Brautarholt", "Rauðalækur", "Bakkafjörður", "Innnes", "Grímsey", "Þykkvabær", "Laugarbakki", "Reykholt", "Árnes", "Kristnes", "Kleppjárnsreykir");
private final Random random = new Random();
public String generateFirstName() {
return generateName(firstNameParts);
}
public String generateLastName() {
return generateName(lastNameParts);
}
public String generateStreetName() {
StringBuilder name = new StringBuilder();
int nLastNameParts = random.nextInt(5) + 1;
for (int i = 0; i < nLastNameParts; i++) {
name.append(firstNameParts.get(random.nextInt(firstNameParts.size())));
name.append(lastNameParts.get(random.nextInt(lastNameParts.size())));
}
name.append("götu");
return name.toString();
}
public int generateSomeNumber() {
return random.nextInt(1000);
}
public String generateSomeCityInIceland() {
return cities.get(random.nextInt(cities.size()));
}
public String generateIceland() {
return "Iceland"; // meant to be humorous
}
private String generateName(List<String> parts) {
StringBuilder name = new StringBuilder();
int size = random.nextInt(2) + 2;
for (int i = 0; i < size; i++) {
name.append(parts.get(random.nextInt(parts.size())));
}
return name.toString();
}
}

View file

@ -0,0 +1,35 @@
package nl.sanderhautvast.contiguous.demo.rest;
import lombok.extern.slf4j.Slf4j;
import nl.sanderhautvast.contiguous.ContiguousList;
import nl.sanderhautvast.contiguous.demo.model.Customer;
import nl.sanderhautvast.contiguous.demo.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@Slf4j
public class DemoRestApi {
private final CustomerRepository customerRepository;
@Autowired
public DemoRestApi(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@GetMapping(value = "/api/customers", produces = "application/json")
public List<Customer> getCustomers() {
try {
ContiguousList<Customer> customers = customerRepository.getAllCustomers();
log.info("customers {}", customers.size());
return customers;
} catch (Exception e) {
log.error("Error", e);
throw new RuntimeException(e);
}
}
}

View file

@ -0,0 +1,6 @@
logging.level.org.springframework=ERROR
spring.jpa.hibernate.ddl-auto=none
spring.datasource.driverClass=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=unsafe

4
demo/start_demo.sh Normal file
View file

@ -0,0 +1,4 @@
docker stop postgres
docker rm postgres
docker run -d -p5432:5432 -e POSTGRES_PASSWORD=unsafe --name postgres postgres:latest
mvn -f pom.xml -DskipTests clean spring-boot:run &

31
jackson/pom.xml Normal file
View file

@ -0,0 +1,31 @@
<?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-jackson</artifactId>
<version>1.1</version>
<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>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.1</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,30 @@
package nl.sanderhautvast.contiguous;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
public class ListSerializer<E> extends StdSerializer<ContiguousList<E>> {
public ListSerializer(Class<ContiguousList<E>> t) {
super(t);
}
@Override
public void serialize(
ContiguousList<E> value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
// value.
// jgen.writeStartObject();
// jgen.writeNumberField("id", value.id);
// jgen.writeStringField("itemName", value.itemName);
// jgen.writeNumberField("owner", value.owner.id);
// jgen.writeEndObject();
}
}

38
lib/pom.xml Normal file
View file

@ -0,0 +1,38 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.sanderhautvast</groupId>
<artifactId>contiguous</artifactId>
<description>Datastructures with contiguous storage</description>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>9</maven.compiler.source>
<maven.compiler.target>9</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<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>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View file

@ -5,9 +5,10 @@ import java.lang.invoke.MethodHandle;
/**
* Stores a byte value.
*/
class ByteHandler extends PropertyHandler<Byte> {
class ByteHandler extends PrimitiveType<Byte> {
public ByteHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Byte.class, getter, setter);
}
@Override

View file

@ -0,0 +1,51 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.util.*;
class CompoundType extends Type {
private final Map<String, Type> properties = new LinkedHashMap<>();
private MethodHandle getter;
private MethodHandle setter;
CompoundType(Class<?> type) {
super(type, null,null);
}
void setGetter(MethodHandle getter) {
this.getter = getter;
}
public MethodHandle getGetter() {
return getter;
}
public MethodHandle getSetter() {
return setter;
}
void setSetter(MethodHandle setter) {
this.setter = setter;
}
public Class<?> getType() {
return type;
}
Collection<Type> getProperties() {
return properties.values();
}
void addHandler(String propertyName, PrimitiveType<?> primitiveType) {
properties.put(propertyName, primitiveType);
}
void addChild(Field property, CompoundType childCompoundType) {
this.properties.put(property.getName(), childCompoundType);
}
}

View file

@ -9,7 +9,7 @@ import java.util.*;
import java.util.function.UnaryOperator;
/**
* Experimental List implementation
* Short for Contiguous Layout List, an Experimental List implementation
* 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,
* without object instance overhead.
@ -46,21 +46,17 @@ public class ContiguousList<E> implements List<E> {
*/
private ByteBuffer data = ByteBuffer.allocate(32);
private int currentValueIndex;
private int currentElementIndex;
private int[] valueIndices = new int[10];
private int[] elementIndices = new int[10];
private int size;
private final Class<?> type;
private final List<PropertyHandler> propertyHandlers = new LinkedList<>();
private Type type;
public ContiguousList(Class<E> type) {
this.type = type;
//have to make this recursive
inspectType(type, new ArrayList<>());
valueIndices[0] = 0;
inspectType(type);
elementIndices[0] = currentElementIndex; // index of first element
}
/*
@ -71,8 +67,21 @@ public class ContiguousList<E> implements List<E> {
* The advantage of the current implementation is that the binary data is not aware of the actual
* object graph. It only knows the 'primitive' values.
*/
private void inspectType(Class<?> type, List<MethodHandle> childGetters) {
private void inspectType(Class<?> type) {
if (PropertyHandlerFactory.isKnownType(type)) {
this.type = PropertyHandlerFactory.forType(type);
} else {
CompoundType compoundType = new CompoundType(type);
this.type = compoundType;
try {
addPropertyHandlersForCompoundType(type, compoundType);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
private void addPropertyHandlersForCompoundType(Class<?> type, CompoundType parentCompoundType) throws IllegalAccessException {
final MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(type, MethodHandles.lookup());
Arrays.stream(type.getDeclaredFields())
.forEach(field -> {
@ -82,27 +91,120 @@ public class ContiguousList<E> implements List<E> {
MethodHandle setter = lookup.findSetter(type, field.getName(), fieldType);
if (PropertyHandlerFactory.isKnownType(fieldType)) {
PropertyHandler propertyHandler = PropertyHandlerFactory.forType(fieldType, getter, setter);
PrimitiveType<?> primitiveType = PropertyHandlerFactory.forType(fieldType, getter, setter);
// not empty if there has been recursion
if (!childGetters.isEmpty()) {
childGetters.forEach(propertyHandler::addChildGetter);
}
propertyHandlers.add(propertyHandler);
parentCompoundType.addHandler(field.getName(), primitiveType);
} else {
// assume nested bean
childGetters.add(getter);
inspectType(fieldType, childGetters);
CompoundType newParent = new CompoundType(fieldType);
newParent.setGetter(getter);
newParent.setSetter(setter);
parentCompoundType.addChild(field, newParent);
addPropertyHandlersForCompoundType(fieldType, newParent);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (IllegalAccessException e) {
}
@Override
@SuppressWarnings("Contract")
public boolean add(E element) {
if (element == null) {
return false;
}
getProperties(element, type);
size += 1;
// keep track of where the objects are stored
if (elementIndices.length < size + 1) {
this.elementIndices = Arrays.copyOf(this.elementIndices, this.elementIndices.length * 2);
}
elementIndices[size] = currentElementIndex;
return true;
}
private void getProperties(Object element, Type type) {
// passed type is primitive
if (type instanceof PrimitiveType<?>) {
((PrimitiveType<?>) type).storePropertyValue(element, this);
} else {
// passed type is compund ie. has child properties
((CompoundType)type).getProperties().forEach(property -> {
if (property instanceof PrimitiveType<?>) {
// recurse once more -> property is stored
getProperties(element, property);
} else {
CompoundType child = ((CompoundType) property);
try {
Object result = child.getGetter().invoke(element);
getProperties(result, child);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
});
}
}
@Override
public boolean remove(Object o) {
throw new RuntimeException("Not yet implemented");
}
@Override
@SuppressWarnings("NullableProblems")
public boolean containsAll(Collection<?> collection) {
throw new RuntimeException("Not yet implemented");
}
@Override
@SuppressWarnings("unchecked")
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("index <0 or >" + size);
}
data.position(elementIndices[index]);
try {
if (type instanceof PrimitiveType<?>) {
return (E) ValueReader.read(data);
}
// create a new instance of the list element type
E newInstance = (E) type.type.getDeclaredConstructor().newInstance();
// set the data
setProperties(newInstance, (CompoundType) type);
return newInstance;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
private void setProperties(Object element, CompoundType compoundType) {
compoundType.getProperties().forEach(property -> {
if (property instanceof PrimitiveType) {
((PrimitiveType<?>) property).setValue(element, ValueReader.read(data));
} else {
try {
CompoundType p = (CompoundType) property;
// create a new instance of the property
Object newInstance = p.getType().getDeclaredConstructor().newInstance();
// set it on the parent
p.getSetter().invokeWithArguments(element, newInstance);
// recurse down
setProperties(newInstance, p);
} catch (Throwable e) {
throw new RuntimeException(e);
}
}
});
}
public boolean addAll(Collection<? extends E> collection) {
for (E element : collection) {
@ -111,18 +213,22 @@ public class ContiguousList<E> implements List<E> {
return true;
}
@Override
@SuppressWarnings("NullableProblems")
public boolean addAll(int i, Collection<? extends E> collection) {
throw new RuntimeException("Not yet implemented");
}
@Override
@SuppressWarnings("NullableProblems")
public boolean removeAll(Collection<?> collection) {
throw new RuntimeException("Not yet implemented");
throw new RuntimeException("Not implemented");
}
@Override
@SuppressWarnings("NullableProblems")
public boolean retainAll(Collection<?> collection) {
throw new RuntimeException("Not yet implemented");
throw new RuntimeException("Not implemented");
}
@Override
@ -136,56 +242,10 @@ public class ContiguousList<E> implements List<E> {
}
public void clear() {
this.currentValueIndex = 0;
this.currentElementIndex = 0;
this.size = 0;
}
@Override
public boolean add(E element) {
if (element == null) {
return false;
}
propertyHandlers.forEach(appender -> appender.storeValue(element, this));
size += 1;
// keep track of where the objects are stored
if (size > valueIndices.length) {
this.valueIndices = Arrays.copyOf(this.valueIndices, this.valueIndices.length * 2);
}
valueIndices[size] = currentValueIndex;
return true;
}
@Override
public boolean remove(Object o) {
throw new RuntimeException("Not yet implemented");
}
@Override
public boolean containsAll(Collection<?> collection) {
throw new RuntimeException("Not yet implemented");
}
@SuppressWarnings("unchecked")
@Override
public E get(int index) {
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException("index <0 or >" + size);
}
data.position(valueIndices[index]);
try {
E newInstance = (E) type.getDeclaredConstructor().newInstance();
propertyHandlers.forEach(appender -> {
appender.setValue(newInstance, ValueReader.read(data));
});
return newInstance;
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
@Override
public E set(int i, E e) {
throw new RuntimeException("Not implemented");
@ -198,17 +258,17 @@ public class ContiguousList<E> implements List<E> {
@Override
public E remove(int i) {
throw new RuntimeException("Not yet implemented");
throw new RuntimeException("Not implemented");
}
@Override
public int indexOf(Object o) {
throw new RuntimeException("Not yet implemented");
throw new RuntimeException("Not implemented");
}
@Override
public int lastIndexOf(Object o) {
throw new RuntimeException("Not yet implemented");
throw new RuntimeException("Not implemented");
}
@Override
@ -247,7 +307,7 @@ public class ContiguousList<E> implements List<E> {
@Override
public Iterator<E> iterator() {
return new Iter<E>();
return new Iter<>();
}
@Override
@ -260,6 +320,7 @@ public class ContiguousList<E> implements List<E> {
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] ts) {
if (size > ts.length) {
return (T[]) toArray();
@ -281,27 +342,28 @@ public class ContiguousList<E> implements List<E> {
}
@Override
@SuppressWarnings("unchecked")
public F next() {
return (F) get(curIndex++);
}
}
private void store(byte[] bytes) {
ensureCapacity(bytes.length);
data.position(currentValueIndex); // ensures intermittent reads/writes
ensureFree(bytes.length);
data.position(currentElementIndex); // ensures intermittent reads/writes
data.put(bytes);
currentValueIndex += bytes.length;
currentElementIndex += bytes.length;
}
private void store(byte singlebyte) {
ensureCapacity(1);
data.put(singlebyte);
currentValueIndex += 1;
private void store0() {
ensureFree(1);
data.put((byte) 0);
currentElementIndex += 1;
}
void storeString(String value) {
if (value == null) {
store(Varint.write(0));
store0();
} else {
byte[] utf = value.getBytes(StandardCharsets.UTF_8);
store(Varint.write(((long) (utf.length) << 1) + STRING_OFFSET));
@ -311,7 +373,7 @@ public class ContiguousList<E> implements List<E> {
void storeLong(Long value) {
if (value == null) {
store((byte) 0);
store0();
} else {
byte[] valueAsBytes = getValueAsBytes(value);
store(getIntegerType(value, valueAsBytes.length));
@ -321,7 +383,7 @@ public class ContiguousList<E> implements List<E> {
void storeInteger(Integer value) {
if (value == null) {
store((byte) 0);
store0();
} else {
byte[] valueAsBytes = getValueAsBytes(value);
store(getIntegerType(value, valueAsBytes.length));
@ -331,7 +393,17 @@ public class ContiguousList<E> implements List<E> {
void storeByte(Byte value) {
if (value == null) {
store((byte) 0);
store0();
} else {
byte[] valueAsBytes = getValueAsBytes(value);
store(getIntegerType(value, valueAsBytes.length));
store(valueAsBytes);
}
}
void storeShort(Short value) {
if (value == null) {
store0();
} else {
byte[] valueAsBytes = getValueAsBytes(value);
store(getIntegerType(value, valueAsBytes.length));
@ -341,7 +413,7 @@ public class ContiguousList<E> implements List<E> {
void storeDouble(Double value) {
if (value == null) {
store((byte) 0);
store0();
} else {
store(DOUBLE_TYPE);
store(ByteBuffer.wrap(new byte[8]).putDouble(0, value).array());
@ -350,7 +422,7 @@ public class ContiguousList<E> implements List<E> {
void storeFloat(Float value) {
if (value == null) {
store((byte) 0);
store0();
} else {
store(FLOAT_TYPE);
store(ByteBuffer.wrap(new byte[4]).putFloat(0, value).array());
@ -358,15 +430,15 @@ public class ContiguousList<E> implements List<E> {
}
byte[] getData() {
return Arrays.copyOfRange(data.array(), 0, currentValueIndex);
return Arrays.copyOfRange(data.array(), 0, currentElementIndex);
}
int[] getValueIndices() {
return Arrays.copyOfRange(valueIndices, 0, size + 1);
int[] getElementIndices() {
return Arrays.copyOfRange(elementIndices, 0, size + 1);
}
private void ensureCapacity(int length) {
while (currentValueIndex + length > data.capacity()) {
private void ensureFree(int length) {
while (currentElementIndex + length > data.capacity()) {
byte[] bytes = this.data.array();
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
this.data.put(bytes);

View file

@ -5,9 +5,9 @@ import java.lang.invoke.MethodHandle;
/**
* Stores a double value.
*/
class DoubleHandler extends PropertyHandler<Double> {
class DoubleHandler extends PrimitiveType<Double> {
public DoubleHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Double.class, getter, setter);
}
@Override

View file

@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
class FloatHandler extends PropertyHandler<Float> {
class FloatHandler extends PrimitiveType<Float> {
public FloatHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Float.class, getter, setter);
}
@Override

View file

@ -2,19 +2,14 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
class IntegerHandler extends PropertyHandler<Integer> {
class IntegerHandler extends PrimitiveType<Integer> {
public IntegerHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Integer.class, getter, setter);
}
/**
* TODO improve
* it's first extended to long (s64) and then stored with variable length.
* With a little more code for s64, s16 and s8 specifically we can avoid the lenghtening and shortening
*/
@Override
public void store(Integer value, ContiguousList<?> list) {
list.storeInteger((Integer)value);
list.storeInteger(value);
}
/*

View file

@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
class LongHandler extends PropertyHandler<Long> {
class LongHandler extends PrimitiveType<Long> {
public LongHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Long.class, getter, setter);
}
@Override

View file

@ -1,8 +1,6 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.List;
/*
* Base class for handlers. Its responsibility is to read and write a property from the incoming object to the internal storage.
@ -13,10 +11,7 @@ import java.util.List;
* of the bean that it needs to call 'runtime' (after instantiation of the list),
* ie. when a bean is added or retrieved from the list
*/
public abstract class PropertyHandler<T> {
private final MethodHandle getter;
private final MethodHandle setter;
public abstract class PrimitiveType<T> extends Type {
/*
* Apology:
@ -31,11 +26,10 @@ public abstract class PropertyHandler<T> {
* 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<>();
// private final List<MethodHandle> childGetters = new ArrayList<>();
public PropertyHandler(MethodHandle getter, MethodHandle setter) {
this.getter = getter;
this.setter = setter;
public PrimitiveType(Class<?> type, MethodHandle getter, MethodHandle setter) {
super(type, getter, setter);
}
/**
@ -46,18 +40,19 @@ public abstract class PropertyHandler<T> {
*/
public abstract void store(T value, ContiguousList<?> list);
void storeValue(T instance, ContiguousList<?> typedList) {
store(getValue(instance), typedList);
void storePropertyValue(Object instance, ContiguousList<?> typedList) {
T propertyValue = getValue(instance);
store(propertyValue, typedList);
}
private T getValue(Object instance) {
Object objectToCall = instance;
private T getValue(Object propertyValue) {
// I don't trust this
if (getter == null) {
return (T) propertyValue;
}
try {
for (MethodHandle childGetter:childGetters){
objectToCall = childGetter.invoke(instance);
}
return (T)getter.invoke(objectToCall);
return (T) getter.invoke(propertyValue);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
@ -66,7 +61,7 @@ public abstract class PropertyHandler<T> {
/**
* This is used when get() is called on the list.
* As this will create a new instance of the type, it's property values need to be set.
*
* <p>
* Can be overridden to do transformations on the value after it has been retrieved, but make sure
* to call super.setValue() or the value won't be set.
*
@ -74,20 +69,11 @@ public abstract class PropertyHandler<T> {
* @param value the value that has been read from ContiguousList storage
*/
public void setValue(Object instance, Object value) {
Object objectToCall = instance;
try {
for (MethodHandle childGetter:childGetters){
objectToCall = childGetter.invoke(instance);
}
setter.invokeWithArguments(objectToCall, value);
setter.invokeWithArguments(instance, value);
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
void addChildGetter(MethodHandle childGetter){
childGetters.add(childGetter);
}
}

View file

@ -0,0 +1,58 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/*
* Maps the propertyvalue type to a PropertyHandler
*/
final class PropertyHandlerFactory {
private static final Map<Class<?>, Class<? extends PrimitiveType<?>>> STANDARD_HANDLERS = new HashMap<>();
private 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);
//Date/Timestamp
//LocalDate/time
//BigDecimal
//BigInteger
}
public static boolean isKnownType(Class<?> type) {
return STANDARD_HANDLERS.containsKey(type);
}
public static <T> PrimitiveType<T> forType(Class<T> type, MethodHandle getter, MethodHandle setter) {
try {
Class<? extends PrimitiveType<?>> appenderClass = STANDARD_HANDLERS.get(type);
if (appenderClass == null) {
throw new IllegalStateException("No Handler for " + type.getName());
}
return (PrimitiveType<T>) appenderClass.getDeclaredConstructor(MethodHandle.class, MethodHandle.class)
.newInstance(getter, setter);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
public static <T> PrimitiveType<T> forType(Class<T> type) {
return forType(type, null, null);
}
}

View file

@ -2,14 +2,14 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
class ShortHandler extends PropertyHandler<Short> {
class ShortHandler extends PrimitiveType<Short> {
public ShortHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(Short.class, getter, setter);
}
@Override
public void store(Short value, ContiguousList<?> list) {
list.storeInteger(value == null ? null : value.intValue());
list.storeShort(value);
}
@Override

View file

@ -2,9 +2,9 @@ package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
class StringHandler extends PropertyHandler<String> {
class StringHandler extends PrimitiveType<String> {
public StringHandler(MethodHandle getter, MethodHandle setter) {
super(getter, setter);
super(String.class, getter, setter);
}
@Override

View file

@ -0,0 +1,19 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
/**
* ok, sorry
*/
public abstract class Type {
protected MethodHandle getter; // both can be null, if it's for a known ('primitive') type
protected MethodHandle setter;
protected Class<?> type;
public Type(Class<?> type, MethodHandle getter, MethodHandle setter) {
this.type = type;
this.getter = getter;
this.setter = setter;
}
}

View file

@ -1,7 +1,6 @@
package nl.sanderhautvast.contiguous;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/*
@ -20,7 +19,7 @@ class ValueReader {
*/
public static Object read(ByteBuffer buffer) {
long type = Varint.read(buffer);
return read(buffer, type, StandardCharsets.UTF_8);
return read(buffer, type);
}
/**
@ -28,11 +27,10 @@ class ValueReader {
*
* @param buffer Bytebuffer containing the storage.
* @param columnType type representation borrowed from SQLite
* @param charset database charset
*
* @return the value implementation
*/
private static Object read(ByteBuffer buffer, long columnType, Charset charset) {
private static Object read(ByteBuffer buffer, long columnType) {
if (columnType == 0) {
return null;
} else if (columnType < 6L) {
@ -54,7 +52,7 @@ class ValueReader {
} else if (columnType >= 13) {
byte[] bytes = new byte[getvalueLengthForType(columnType)];
buffer.get(bytes);
return new String(bytes, charset);
return new String(bytes, StandardCharsets.UTF_8);
} else throw new IllegalStateException("unknown column type" + columnType);
}
@ -79,47 +77,6 @@ class ValueReader {
}
}
static int getLengthOfByteEncoding(long value) {
long u;
if (value < 0) {
u = ~value;
} else {
u = value;
}
if (u <= 127) {
return 1;
} else if (u <= 32767) {
return 2;
} else if (u <= 8388607) {
return 3;
} else if (u <= 2147483647) {
return 4;
} else if (u <= 140737488355327L) {
return 6;
} else {
return 8;
}
}
public static byte[] getValueAsBytes(long value) {
if (value == 0) {
return new byte[0];
} else if (value == 1) {
return new byte[0];
} else {
return longToBytes(value, getLengthOfByteEncoding(value));
}
}
public static byte[] longToBytes(long n, int nbytes) {
byte[] b = new byte[nbytes];
for (int i = 0; i < nbytes; i++) {
b[i] = (byte) ((n >> (nbytes - i - 1) * 8) & 0xFF);
}
return b;
}
public static long bytesToLong(final byte[] b) {
long n = 0;
for (int i = 0; i < b.length; i++) {

View file

@ -40,15 +40,6 @@ final class Varint {
}
}
/*
* read a long value from a variable nr of bytes in varint format
* NB the end is encoded in the bytes, and the passed byte array may be bigger, but the
* remainder is not read. It's up to the caller to do it right.
*/
public static long read(byte[] bytes) {
return read(ByteBuffer.wrap(bytes));
}
/*
* read a long value from a variable nr of bytes in varint format
*
@ -58,8 +49,6 @@ final class Varint {
*
* Does not have the issue that the read(byte[] bytes) method has. The nr of bytes read is determined
* by the varint64 format.
*
* TODO write specialized version for u32
*/
public static long read(ByteBuffer buffer) {
int SLOT_2_0 = 0x001fc07f;

View file

@ -0,0 +1,12 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class ByteBean {
byte value;
}

View file

@ -2,11 +2,27 @@ package nl.sanderhautvast.contiguous;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
public class ContiguousListTest {
@Test
public void testString() {
public void testAddAndGetString() {
List<String> list = new ContiguousList<>(String.class);
assertTrue(list.isEmpty());
list.add("hitchhikersguide to the galaxy");
assertFalse(list.isEmpty());
assertEquals(1, list.size());
String title = list.get(0);
assertEquals("hitchhikersguide to the galaxy", title);
}
@Test
public void testStringBean() {
ContiguousList<StringBean> beanList = new ContiguousList<>(StringBean.class);
beanList.add(new StringBean("Douglas Adams"));
@ -25,7 +41,7 @@ public class ContiguousListTest {
}
@Test
public void testInt() {
public void testIntBean() {
ContiguousList<IntBean> beanList = new ContiguousList<>(IntBean.class);
beanList.add(new IntBean(42));
@ -51,7 +67,7 @@ public class ContiguousListTest {
assertArrayEquals(new byte[]{1, 42},
beanList.getData());
assertArrayEquals(new int[]{0, 2}, beanList.getValueIndices());
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
}
@Test
@ -61,17 +77,16 @@ public class ContiguousListTest {
assertArrayEquals(new byte[]{1, -42},
beanList.getData());
assertArrayEquals(new int[]{0, 2}, beanList.getValueIndices());
assertArrayEquals(new int[]{0, 2}, beanList.getElementIndices());
}
@Test
public void testNestedBean() {
ContiguousList<NestedBean> beanList = new ContiguousList<>(NestedBean.class);
beanList.add(new NestedBean(new StringBean("42")));
beanList.add(new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42)));
assertArrayEquals(new byte[]{17, 52, 50},
beanList.getData());
assertArrayEquals(new int[]{0, 3}, beanList.getValueIndices());
NestedBean expected = new NestedBean(new StringBean("vogon constructor fleet"), new IntBean(42));
assertEquals(expected, beanList.get(0));
}
@Test
@ -106,4 +121,13 @@ public class ContiguousListTest {
assertNull(beanList.get(0).getName());
}
@Test
public void test100Elements() {
ContiguousList<StringBean> beanList = new ContiguousList<>(StringBean.class);
for (int i = 0; i < 100; i++) {
beanList.add(new StringBean(null));
}
assertEquals(100, beanList.size());
}
}

View file

@ -0,0 +1,14 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class DoubleBean {
private Double value;
}

View file

@ -0,0 +1,12 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class FloatBean {
private Float value;
}

View file

@ -0,0 +1,12 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class IntBean {
private int value;
}

View file

@ -0,0 +1,12 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class LongBean {
private long value;
}

View file

@ -0,0 +1,13 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class NestedBean {
private StringBean stringBean;
private IntBean intBean;
}

View file

@ -0,0 +1,13 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
class ShortBean {
private short value;
}

View file

@ -0,0 +1,13 @@
package nl.sanderhautvast.contiguous;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StringBean {
private String name;
}

43
pom.xml
View file

@ -1,25 +1,32 @@
<?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">
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nl.sanderhautvast</groupId>
<artifactId>contiguous</artifactId>
<description>Datastructures with contiguous storage</description>
<version>1.0-SNAPSHOT</version>
<artifactId>contiguous-pom</artifactId>
<packaging>pom</packaging>
<version>1.1</version>
<modules>
<module>lib</module>
<module>demo</module>
<module>jackson</module>
</modules>
<name>contiguous</name>
<description>contiguous storage for java</description>
<properties>
<maven.compiler.source>9</maven.compiler.source>
<maven.compiler.target>9</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>9</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>9</release>
</configuration>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,54 +0,0 @@
package nl.sanderhautvast.contiguous;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/*
* Maps the propertyvalue type to a PropertyHandler
*/
final class PropertyHandlerFactory {
private static final Map<Class<?>, Class<? extends PropertyHandler>> APPENDERS = new HashMap<>();
private PropertyHandlerFactory() {
}
static {
APPENDERS.put(String.class, StringHandler.class);
APPENDERS.put(byte.class, ByteHandler.class);
APPENDERS.put(Byte.class, ByteHandler.class);
APPENDERS.put(int.class, IntegerHandler.class);
APPENDERS.put(Integer.class, IntegerHandler.class);
APPENDERS.put(short.class, ShortHandler.class);
APPENDERS.put(Short.class, ShortHandler.class);
APPENDERS.put(long.class, LongHandler.class);
APPENDERS.put(Long.class, LongHandler.class);
APPENDERS.put(float.class, FloatHandler.class);
APPENDERS.put(Float.class, FloatHandler.class);
APPENDERS.put(double.class, DoubleHandler.class);
APPENDERS.put(Double.class, DoubleHandler.class);
//Date/Timestamp
//LocalDate/time
//BigDecimal
//BigInteger
}
public static boolean isKnownType(Class<?> type) {
return APPENDERS.containsKey(type);
}
public static <T> PropertyHandler forType(Class<T> type, MethodHandle getter, MethodHandle setter) {
try {
Class<? extends PropertyHandler> appenderClass = APPENDERS.get(type);
if (appenderClass == null) {
throw new IllegalStateException("No ListAppender for " + type.getName());
}
return appenderClass.getDeclaredConstructor(MethodHandle.class, MethodHandle.class)
.newInstance(getter, setter);
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new IllegalStateException(e);
}
}
}

View file

@ -1,13 +0,0 @@
package nl.sanderhautvast.contiguous;
class ByteBean {
private byte value;
ByteBean(byte value) {
this.value = value;
}
public byte getValue() {
return value;
}
}

View file

@ -1,16 +0,0 @@
package nl.sanderhautvast.contiguous;
class DoubleBean {
private Double value;
public DoubleBean() {
}
public DoubleBean(Double value) {
this.value = value;
}
public Double getValue() {
return value;
}
}

View file

@ -1,16 +0,0 @@
package nl.sanderhautvast.contiguous;
class FloatBean {
private Float value;
public FloatBean() {
}
public FloatBean(Float value) {
this.value = value;
}
public Float getValue() {
return value;
}
}

View file

@ -1,17 +0,0 @@
package nl.sanderhautvast.contiguous;
class IntBean {
private int value;
public IntBean(){
}
IntBean(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}

View file

@ -1,17 +0,0 @@
package nl.sanderhautvast.contiguous;
class LongBean {
private long value;
public LongBean(){
}
LongBean(long value) {
this.value = value;
}
public long getValue() {
return value;
}
}

View file

@ -1,20 +0,0 @@
package nl.sanderhautvast.contiguous;
public class NestedBean {
private StringBean stringBean;
public NestedBean() {
}
public NestedBean(StringBean stringBean) {
this.stringBean = stringBean;
}
public StringBean getStringBean() {
return stringBean;
}
public void setStringBean(StringBean stringBean) {
this.stringBean = stringBean;
}
}

View file

@ -1,13 +0,0 @@
package nl.sanderhautvast.contiguous;
class ShortBean {
private short value;
ShortBean(short value) {
this.value = value;
}
public short getValue() {
return value;
}
}

View file

@ -1,20 +0,0 @@
package nl.sanderhautvast.contiguous;
public class StringBean {
private String name;
public StringBean(){
}
public StringBean(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}