json output directly from the list...may not remain there
This commit is contained in:
parent
db33d0fac8
commit
dd6b9c2281
8 changed files with 127 additions and 223 deletions
|
|
@ -1,33 +1,28 @@
|
||||||
package nl.sanderhautvast.contiguous;
|
package nl.sanderhautvast.contiguous;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class ListSerializer<E> extends StdSerializer<ContiguousList> {
|
public class ListSerializer<E> extends StdSerializer<ContiguousList<?>> {
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public ListSerializer() {
|
public ListSerializer() {
|
||||||
super(ContiguousList.class);
|
super((Class) ContiguousList.class); // ?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void serialize(
|
public void serialize(
|
||||||
ContiguousList clist, JsonGenerator generator, SerializerProvider provider)
|
ContiguousList<?> clist, JsonGenerator generator, SerializerProvider provider)
|
||||||
throws IOException, JsonProcessingException {
|
throws IOException {
|
||||||
generator.writeStartArray();
|
generator.writeStartArray();
|
||||||
|
|
||||||
if (clist.isSimpleElementType()){
|
Iterator<String> jsons = clist.jsonIterator();
|
||||||
Iterator<?> iterator = clist.valueIterator();
|
while (jsons.hasNext()) {
|
||||||
while (iterator.hasNext()){
|
generator.writeRawValue(jsons.next());
|
||||||
generator.writeString(iterator.next().toString());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.writeEndArray();
|
generator.writeEndArray();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package nl.sanderhautvast.contiguous;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
|
@ -45,9 +44,9 @@ class ListSerializerTest {
|
||||||
|
|
||||||
|
|
||||||
String json = mapper.writeValueAsString(strings);
|
String json = mapper.writeValueAsString(strings);
|
||||||
assertEquals("[{\"name\":\"Vogon constructor fleet\"}," +
|
assertEquals("[{\"name\": \"Vogon constructor fleet\"}," +
|
||||||
"{\"name\":\"Restaurant at the end of the Galaxy\"}," +
|
"{\"name\": \"Restaurant at the end of the Galaxy\"}," +
|
||||||
"{\"name\":\"Publishing houses of Ursa Minor\"}]",
|
"{\"name\": \"Publishing houses of Ursa Minor\"}]",
|
||||||
json);
|
json);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ public class JdbcResults {
|
||||||
}
|
}
|
||||||
next.set(fieldValue);
|
next.set(fieldValue);
|
||||||
}
|
}
|
||||||
setterIterator.nextRecord();
|
setterIterator.finishObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,7 +69,6 @@ public class JdbcResults {
|
||||||
* @throws SQLException when db throws error..
|
* @throws SQLException when db throws error..
|
||||||
*/
|
*/
|
||||||
public static <E> ContiguousList<E> toList(ResultSet result, Class<E> elementType) throws SQLException {
|
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());
|
return toList(result, elementType, Function.identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,18 +24,13 @@ public abstract class BuiltinTypeHandler<T> extends TypeHandler {
|
||||||
*/
|
*/
|
||||||
public abstract void store(T value, ContiguousList<?> list);
|
public abstract void store(T value, ContiguousList<?> list);
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isBuiltin() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void storePropertyValue(Object instance, ContiguousList<?> typedList) {
|
void storePropertyValue(Object instance, ContiguousList<?> typedList) {
|
||||||
T propertyValue = getValue(instance);
|
T propertyValue = getValue(instance);
|
||||||
store(propertyValue, typedList);
|
store(propertyValue, typedList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
void storeValue(Object value, ContiguousList<?> contiguousList) {
|
||||||
store((T)value, contiguousList);
|
store((T) value, contiguousList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private T getValue(Object propertyValue) {
|
private T getValue(Object propertyValue) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,9 @@ import java.util.*;
|
||||||
class CompoundTypeHandler extends TypeHandler {
|
class CompoundTypeHandler extends TypeHandler {
|
||||||
private final Map<String, TypeHandler> properties = new LinkedHashMap<>();
|
private final Map<String, TypeHandler> properties = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
CompoundTypeHandler(Class<?> type) {
|
||||||
|
super(type, null,null, null);
|
||||||
|
}
|
||||||
|
|
||||||
CompoundTypeHandler(Class<?> type, String propertyName) {
|
CompoundTypeHandler(Class<?> type, String propertyName) {
|
||||||
super(type, propertyName, null,null);
|
super(type, propertyName, null,null);
|
||||||
|
|
@ -24,10 +26,4 @@ class CompoundTypeHandler extends TypeHandler {
|
||||||
void addChild(Field property, CompoundTypeHandler childCompoundType) {
|
void addChild(Field property, CompoundTypeHandler childCompoundType) {
|
||||||
this.properties.put(property.getName(), childCompoundType);
|
this.properties.put(property.getName(), childCompoundType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isBuiltin() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
*/
|
*/
|
||||||
private ByteBuffer data = ByteBuffer.allocate(32);
|
private ByteBuffer data = ByteBuffer.allocate(32);
|
||||||
|
|
||||||
private int currentElementValueIndex;
|
private int bufferPosition;
|
||||||
|
|
||||||
private int[] elementIndices = new int[10]; // avoids autoboxing. Could also use standard ArrayList though
|
private int[] elementIndices = new int[10]; // avoids autoboxing. Could also use standard ArrayList though
|
||||||
// is there a standard lib IntList??
|
// is there a standard lib IntList??
|
||||||
|
|
@ -67,12 +67,9 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
|
|
||||||
private TypeHandler rootHandler;
|
private TypeHandler rootHandler;
|
||||||
|
|
||||||
private final Map<String, Integer> propertyNames;
|
|
||||||
|
|
||||||
public ContiguousList(Class<E> type) {
|
public ContiguousList(Class<E> type) {
|
||||||
inspectType(type);
|
inspectType(type);
|
||||||
elementIndices[0] = 0; // index of first element
|
elementIndices[0] = 0; // index of first element
|
||||||
propertyNames = findPropertyNames();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Class<?> getElementType() {
|
public Class<?> getElementType() {
|
||||||
|
|
@ -87,14 +84,14 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
* The advantage of the current implementation is that the binary data is not aware of the actual
|
* 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.
|
* object graph. It only knows the 'primitive' values.
|
||||||
*/
|
*/
|
||||||
private void inspectType(Class<?> type) {
|
private void inspectType(Class<?> elementClass) {
|
||||||
if (PropertyHandlerFactory.isBuiltInType(type)) {
|
if (PropertyHandlerFactory.isBuiltInType(elementClass)) {
|
||||||
this.rootHandler = PropertyHandlerFactory.forType(type);
|
this.rootHandler = PropertyHandlerFactory.forType(elementClass);
|
||||||
} else {
|
} else {
|
||||||
CompoundTypeHandler compoundType = new CompoundTypeHandler(type, null);//TODO revisit
|
CompoundTypeHandler compoundType = new CompoundTypeHandler(elementClass);
|
||||||
this.rootHandler = compoundType;
|
this.rootHandler = compoundType;
|
||||||
try {
|
try {
|
||||||
addPropertyHandlersForCompoundType(type, compoundType);
|
addPropertyHandlersForCompoundType(elementClass, compoundType);
|
||||||
} catch (IllegalAccessException e) {
|
} catch (IllegalAccessException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +111,8 @@ 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.isBuiltInType(fieldType)) {
|
if (PropertyHandlerFactory.isBuiltInType(fieldType)) {
|
||||||
BuiltinTypeHandler<?> primitiveType = PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
BuiltinTypeHandler<?> primitiveType =
|
||||||
|
PropertyHandlerFactory.forType(fieldType, field.getName(), getter, setter);
|
||||||
|
|
||||||
parentCompoundType.addHandler(field.getName(), primitiveType);
|
parentCompoundType.addHandler(field.getName(), primitiveType);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -144,7 +142,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
if (elementIndices.length < size + 1) {
|
if (elementIndices.length < size + 1) {
|
||||||
this.elementIndices = Arrays.copyOf(this.elementIndices, this.elementIndices.length * 2);
|
this.elementIndices = Arrays.copyOf(this.elementIndices, this.elementIndices.length * 2);
|
||||||
}
|
}
|
||||||
elementIndices[size] = currentElementValueIndex;
|
elementIndices[size] = bufferPosition;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,7 +199,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
E newInstance = (E) rootHandler.getType().getDeclaredConstructor().newInstance();
|
E newInstance = (E) rootHandler.getType().getDeclaredConstructor().newInstance();
|
||||||
|
|
||||||
// set the data
|
// set the data
|
||||||
copyDataIntoNewObjects(newInstance, (CompoundTypeHandler) rootHandler);
|
copyDataIntoNewObject(newInstance, (CompoundTypeHandler) rootHandler);
|
||||||
|
|
||||||
return newInstance;
|
return newInstance;
|
||||||
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
|
||||||
|
|
@ -213,7 +211,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void copyDataIntoNewObjects(Object element, CompoundTypeHandler compoundType) {
|
private void copyDataIntoNewObject(Object element, CompoundTypeHandler compoundType) {
|
||||||
compoundType.getProperties().forEach(property -> {
|
compoundType.getProperties().forEach(property -> {
|
||||||
if (property instanceof BuiltinTypeHandler) {
|
if (property instanceof BuiltinTypeHandler) {
|
||||||
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
|
BuiltinTypeHandler<?> type = ((BuiltinTypeHandler<?>) property);
|
||||||
|
|
@ -228,7 +226,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
p.getSetter().invokeWithArguments(element, newInstance);
|
p.getSetter().invokeWithArguments(element, newInstance);
|
||||||
|
|
||||||
// recurse down
|
// recurse down
|
||||||
copyDataIntoNewObjects(newInstance, p);
|
copyDataIntoNewObject(newInstance, p);
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
@ -251,103 +249,87 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
return new ValueIterator();
|
return new ValueIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Iterator<Property> propertyIterator() {
|
public Iterator<String> jsonIterator() {
|
||||||
return new PropertyIterator();
|
return new JsonIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Property {
|
class JsonIterator implements Iterator<String> {
|
||||||
String name;
|
|
||||||
String value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static class PropertyIterator implements Iterator<Property> {
|
private int index;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
return false;
|
return index < size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Property next() {
|
public String next() {
|
||||||
return null;
|
return getAsJson(index++);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return a list of types in the Object(graph). So the element type and all (nested) properties
|
* For now the simplest thing I can think of to get this to work
|
||||||
*/
|
|
||||||
List<Class<?>> getTypes() {
|
|
||||||
final List<Class<?>> types = new ArrayList<>();
|
|
||||||
getTypes(rootHandler, types);
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void getTypes(TypeHandler handler, List<Class<?>> types) {
|
|
||||||
if (handler instanceof BuiltinTypeHandler<?>) {
|
|
||||||
types.add(handler.getType());
|
|
||||||
} else {
|
|
||||||
types.add(handler.getType());
|
|
||||||
((CompoundTypeHandler) handler).getProperties()
|
|
||||||
.forEach(propertyHandler -> getTypes(propertyHandler, types));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<String> getPropertyNames() {
|
|
||||||
return new ArrayList<>(this.propertyNames.keySet());//TODO should be SET!
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* walk the tree of typehandlers to find the names
|
|
||||||
* adds an index to know what index a property has
|
|
||||||
* this in turn is needed to find where the data of the property is in the byte array
|
|
||||||
*
|
*
|
||||||
* could also store property data indices, but that would incur more memory overhead
|
* @param index
|
||||||
* the way it is now, we have to iterate all properties in an element. ie. a tradeoff
|
* @return
|
||||||
*/
|
*/
|
||||||
private Map<String, Integer> findPropertyNames() {
|
public String getAsJson(int index) {
|
||||||
// no name for the root property
|
if (index < 0 || index >= size) {
|
||||||
final Map<String, Integer> names = new HashMap<>();
|
throw new IndexOutOfBoundsException("index <0 or >" + size);
|
||||||
if (rootHandler instanceof CompoundTypeHandler) {
|
|
||||||
((CompoundTypeHandler) rootHandler).getProperties()
|
|
||||||
.forEach(propertyHandler -> findPropertyNames(propertyHandler, names, 0));
|
|
||||||
}
|
}
|
||||||
|
data.position(elementIndices[index]);
|
||||||
|
if (rootHandler instanceof BuiltinTypeHandler<?>) {
|
||||||
|
|
||||||
|
BuiltinTypeHandler<?> handler = (BuiltinTypeHandler<?>) rootHandler;
|
||||||
|
return getValue(handler);
|
||||||
|
}
|
||||||
|
// create a new instance of the list element type
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
s.append("{");
|
||||||
|
copyDataIntoStringBuilder(s, (CompoundTypeHandler) rootHandler);
|
||||||
|
s.append("}");
|
||||||
|
return s.toString();
|
||||||
|
|
||||||
return Collections.unmodifiableMap(names);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getValue(BuiltinTypeHandler<?> handler) {
|
||||||
|
Object read = ValueReader.read(data);
|
||||||
|
String out = handler.cast(read).toString();
|
||||||
|
if (handler instanceof StringHandler) {
|
||||||
|
out = quote(out);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String quote(String out) {
|
||||||
|
StringBuilder s = new StringBuilder();
|
||||||
|
out = s.append("\"").append(out).append("\"").toString();
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TODO
|
*
|
||||||
* // oopsie: the properties are not guaranteed to be unique
|
|
||||||
*/
|
*/
|
||||||
private void findPropertyNames(TypeHandler handler, Map<String, Integer> names, int index) {
|
private void copyDataIntoStringBuilder(StringBuilder s, CompoundTypeHandler compoundType) {
|
||||||
if (handler instanceof BuiltinTypeHandler<?>) {
|
compoundType.getProperties().forEach(property -> {
|
||||||
names.put(handler.getName(), index);
|
if (property instanceof BuiltinTypeHandler) {
|
||||||
} else {
|
BuiltinTypeHandler<?> typeHandler = (BuiltinTypeHandler<?>) property;
|
||||||
names.put(handler.getName(), index);
|
String name = typeHandler.getName();
|
||||||
for (TypeHandler propertyHandler : ((CompoundTypeHandler) handler).getProperties()) {
|
String value = getValue(typeHandler);
|
||||||
findPropertyNames(propertyHandler, names, index++);
|
s.append(quote(name)).append(": ").append(value);
|
||||||
|
} else {
|
||||||
|
CompoundTypeHandler p = (CompoundTypeHandler) property;
|
||||||
|
s.append(p.getName()).append(":{");
|
||||||
|
// recurse down
|
||||||
|
copyDataIntoStringBuilder(s, p);
|
||||||
|
s.append("}");
|
||||||
}
|
}
|
||||||
}
|
s.append(", ");
|
||||||
|
});
|
||||||
|
s.setLength(s.length() - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* gets a named property of element at index
|
|
||||||
*
|
|
||||||
* @param index elementIndex
|
|
||||||
* @param propertyName the name of the property
|
|
||||||
* @return the property value
|
|
||||||
*/
|
|
||||||
public Object getValue(int index, String propertyName) {
|
|
||||||
if (rootHandler.isBuiltin() || propertyName == null) {
|
|
||||||
data.position(elementIndices[index]);
|
|
||||||
return ValueReader.read(data);
|
|
||||||
} else {
|
|
||||||
return null; //TODO implement
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
List<BuiltinTypeHandler<?>> getBuiltinTypeHandlers() {
|
List<BuiltinTypeHandler<?>> getBuiltinTypeHandlers() {
|
||||||
final List<BuiltinTypeHandler<?>> types = new ArrayList<>();
|
final List<BuiltinTypeHandler<?>> types = new ArrayList<>();
|
||||||
getStoredTypes(rootHandler, types);
|
getStoredTypes(rootHandler, types);
|
||||||
|
|
@ -404,15 +386,13 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSimpleElementType() {
|
|
||||||
return PropertyHandlerFactory.isBuiltInType(rootHandler.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allows 'iterating insertion of data'. Returns an iterator of Setter
|
* Allows 'iterating insertion of data'. Returns an iterator of Setter
|
||||||
* Does not work for compound types yet
|
* Does not work for compound types yet // (check if still valid)
|
||||||
*
|
*
|
||||||
* @return A Reusable iterator
|
* @return an Iterator over bean property setters. Once an object is completely written,
|
||||||
|
* call finishObject, to increase the element count and to continue with the next element.
|
||||||
*/
|
*/
|
||||||
public SetterIterator setterIterator() {
|
public SetterIterator setterIterator() {
|
||||||
return new SetterIterator();
|
return new SetterIterator();
|
||||||
|
|
@ -450,11 +430,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasNext() {
|
public boolean hasNext() {
|
||||||
boolean hasNext = currentSetterIterator.hasNext();
|
return currentSetterIterator.hasNext();
|
||||||
if (!hasNext) {
|
|
||||||
extend(); // marks the end of an object
|
|
||||||
}
|
|
||||||
return hasNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -462,18 +438,15 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
return currentSetterIterator.next();
|
return currentSetterIterator.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void nextRecord() {
|
/**
|
||||||
|
* Indicates that writing of the current object is complete, so
|
||||||
|
* that it will increment the element count and start a new property iterator
|
||||||
|
* for the next object (or none it was the last).
|
||||||
|
*/
|
||||||
|
public void finishObject() {
|
||||||
|
extend();
|
||||||
currentSetterIterator = properties.iterator();
|
currentSetterIterator = properties.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return an {@link Iterator} over the property values of the specified element in the List.
|
|
||||||
*/
|
|
||||||
public Iterator<Object> valueIterator(int index) {
|
|
||||||
//TODO
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addAll(Collection<? extends E> collection) {
|
public boolean addAll(Collection<? extends E> collection) {
|
||||||
|
|
@ -484,7 +457,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
this.currentElementValueIndex = 0;
|
this.bufferPosition = 0;
|
||||||
this.size = 0;
|
this.size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -496,6 +469,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return size == 0;
|
return size == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] toArray() {
|
public Object[] toArray() {
|
||||||
Object[] objects = new Object[size];
|
Object[] objects = new Object[size];
|
||||||
|
|
@ -522,6 +496,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
* Although it's convenient to use, it's not the best way to read from the list because it
|
* Although it's convenient to use, it's not the best way to read from the list because it
|
||||||
* needs the Reflection API to instantiate new objects of the element type.
|
* needs the Reflection API to instantiate new objects of the element type.
|
||||||
* <p/>.
|
* <p/>.
|
||||||
|
*
|
||||||
* @return An Iterator over the elements in the List
|
* @return An Iterator over the elements in the List
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -550,15 +525,15 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
|
|
||||||
private void store(byte[] bytes) {
|
private void store(byte[] bytes) {
|
||||||
ensureFree(bytes.length);
|
ensureFree(bytes.length);
|
||||||
data.position(currentElementValueIndex); // ensures intermittent reads/writes are safe
|
data.position(bufferPosition); // ensures intermittent reads/writes are safe
|
||||||
data.put(bytes);
|
data.put(bytes);
|
||||||
currentElementValueIndex += bytes.length;
|
bufferPosition += bytes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void store0() {
|
private void store0() {
|
||||||
ensureFree(1);
|
ensureFree(1);
|
||||||
data.put((byte) 0);
|
data.put((byte) 0);
|
||||||
currentElementValueIndex += 1;
|
bufferPosition += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeString(String value) {
|
void storeString(String value) {
|
||||||
|
|
@ -636,7 +611,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] getData() {
|
byte[] getData() {
|
||||||
return Arrays.copyOfRange(data.array(), 0, currentElementValueIndex);
|
return Arrays.copyOfRange(data.array(), 0, bufferPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
int[] getElementIndices() {
|
int[] getElementIndices() {
|
||||||
|
|
@ -644,7 +619,7 @@ public class ContiguousList<E> extends NotImplementedList<E> implements List<E>
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureFree(int length) {
|
private void ensureFree(int length) {
|
||||||
while (currentElementValueIndex + length > data.capacity()) {
|
while (bufferPosition + length > data.capacity()) {
|
||||||
byte[] bytes = this.data.array();
|
byte[] bytes = this.data.array();
|
||||||
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
|
this.data = ByteBuffer.allocate(this.data.capacity() * 2);
|
||||||
this.data.put(bytes);
|
this.data.put(bytes);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@ 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* full name, prepended by all parent property names
|
||||||
|
*/
|
||||||
private final String name;
|
private final String name;
|
||||||
|
|
||||||
public TypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
public TypeHandler(Class<?> type, String name, MethodHandle getter, MethodHandle setter) {
|
||||||
|
|
@ -23,8 +27,6 @@ public abstract class TypeHandler {
|
||||||
this.setter = setter;
|
this.setter = setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isBuiltin();
|
|
||||||
|
|
||||||
void setGetter(MethodHandle getter) {
|
void setGetter(MethodHandle getter) {
|
||||||
this.getter = getter;
|
this.getter = getter;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
|
@ -12,7 +11,7 @@ public class ContiguousListTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddAndGetString() {
|
public void testAddAndGetString() {
|
||||||
List<String> list = new ContiguousList<>(String.class);
|
ContiguousList<String> list = new ContiguousList<>(String.class);
|
||||||
assertTrue(list.isEmpty());
|
assertTrue(list.isEmpty());
|
||||||
|
|
||||||
list.add("hitchhikersguide to the galaxy");
|
list.add("hitchhikersguide to the galaxy");
|
||||||
|
|
@ -21,6 +20,9 @@ public class ContiguousListTest {
|
||||||
|
|
||||||
String title = list.get(0);
|
String title = list.get(0);
|
||||||
assertEquals("hitchhikersguide to the galaxy", title);
|
assertEquals("hitchhikersguide to the galaxy", title);
|
||||||
|
|
||||||
|
String titleJson = list.getAsJson(0);
|
||||||
|
assertEquals("\"hitchhikersguide to the galaxy\"", titleJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -33,6 +35,9 @@ public class ContiguousListTest {
|
||||||
StringBean douglas = beanList.get(0);
|
StringBean douglas = beanList.get(0);
|
||||||
assertEquals("Douglas Adams", douglas.getName());
|
assertEquals("Douglas Adams", douglas.getName());
|
||||||
|
|
||||||
|
String douglasJson = beanList.getAsJson(0);
|
||||||
|
assertEquals("{\"name\": \"Douglas Adams\"}", douglasJson);
|
||||||
|
|
||||||
// now add new data to see if existing data remains intact
|
// now add new data to see if existing data remains intact
|
||||||
beanList.add(new StringBean("Ford Prefect"));
|
beanList.add(new StringBean("Ford Prefect"));
|
||||||
|
|
||||||
|
|
@ -198,85 +203,23 @@ public class ContiguousListTest {
|
||||||
assertEquals(new IntBean(100), integers.get(100)); // here an instance
|
assertEquals(new IntBean(100), integers.get(100)); // here an instance
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetTypesWhenCompound() {
|
public void testSetterIterator() {
|
||||||
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
||||||
Iterator<Class<?>> typeIterator = integers.getTypes().iterator();
|
ContiguousList<NestedBean>.SetterIterator iterator = integers.setterIterator();
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(NestedBean.class, typeIterator.next());
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(StringBean.class, typeIterator.next());
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(String.class, typeIterator.next());
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(IntBean.class, typeIterator.next());
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(Integer.class, typeIterator.next());
|
|
||||||
|
|
||||||
}
|
if (iterator.hasNext()) {
|
||||||
|
iterator.next().set("Magrathea");
|
||||||
@Test
|
|
||||||
public void testGetStoredTypesDeepCompound() {
|
|
||||||
final ContiguousList<DeepBean> beans = new ContiguousList<>(DeepBean.class);
|
|
||||||
Iterator<Class<?>> typeIterator = beans.getTypes().iterator();
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(DeepBean.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(NestedBean.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(StringBean.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(String.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(IntBean.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(Integer.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(Long.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(StringBean.class, typeIterator.next());
|
|
||||||
|
|
||||||
assertTrue(typeIterator.hasNext());
|
|
||||||
assertEquals(String.class, typeIterator.next());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTypeIteratorBuiltin() {
|
|
||||||
ContiguousList<Integer> integers = new ContiguousList<>(Integer.class);
|
|
||||||
Iterator<Class<?>> typeIterator = integers.getTypes().iterator();
|
|
||||||
if (typeIterator.hasNext()) {
|
|
||||||
assertEquals(Integer.class, typeIterator.next());
|
|
||||||
}
|
}
|
||||||
}
|
if (iterator.hasNext()) {
|
||||||
|
iterator.next().set(42);
|
||||||
|
}
|
||||||
|
iterator.finishObject();
|
||||||
|
|
||||||
@Test
|
NestedBean nestedBean = integers.get(0);
|
||||||
public void testGetPropertyNamesForBuiltinElementType(){
|
assertEquals("Magrathea", nestedBean.getStringBean().getName());
|
||||||
ContiguousList<Integer> integers = new ContiguousList<>(Integer.class);
|
assertEquals(42, nestedBean.getIntBean().getValue());
|
||||||
assertTrue(integers.getPropertyNames().isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetPropertyNames(){
|
|
||||||
ContiguousList<IntBean> integers = new ContiguousList<>(IntBean.class);
|
|
||||||
assertFalse(integers.getPropertyNames().isEmpty());
|
|
||||||
assertEquals("value", integers.getPropertyNames().get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGetMorePropertyNames(){
|
|
||||||
ContiguousList<NestedBean> integers = new ContiguousList<>(NestedBean.class);
|
|
||||||
assertFalse(integers.getPropertyNames().isEmpty());
|
|
||||||
assertEquals("stringBean", integers.getPropertyNames().get(0));
|
|
||||||
assertEquals("name", integers.getPropertyNames().get(1));
|
|
||||||
assertEquals("intBean", integers.getPropertyNames().get(2));
|
|
||||||
assertEquals("value", integers.getPropertyNames().get(3));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue