Primitive types

This commit is contained in:
Andrea Cavalli 2019-03-06 17:25:56 +01:00
parent d8bfea0a3f
commit 1e735cd992
16 changed files with 405 additions and 380 deletions

View File

@ -6,7 +6,7 @@
<groupId>org.warp</groupId>
<artifactId>jcwdb</artifactId>
<version>1.5.1</version>
<version>1.5.2</version>
<name>jcwdb</name>
<url>https://git.ignuranza.net/andreacavalli/JCWDB</url>

View File

@ -5,6 +5,7 @@ import org.apache.commons.lang3.reflect.MethodUtils;
import org.warp.cowdb.database.EnhancedObjectFullInfo;
import org.warp.jcwdb.ann.DBClass;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBPrimitiveType;
import org.warp.jcwdb.ann.DBPropertyGetter;
import org.warp.jcwdb.ann.DBPropertySetter;
@ -19,6 +20,9 @@ public abstract class EnhancedObject {
private Field[] fields;
private DBDataType[] fieldTypes;
private long[] fieldReferences;
private Field[] primitiveFields;
private DBPrimitiveType[] primitiveFieldTypes;
private long primitiveFieldsDataReference;
private Method[] propertyGetters;
private Method[] propertySetters;
private DBDataType[] propertyTypes;
@ -44,6 +48,12 @@ public abstract class EnhancedObject {
this.fieldReferences = fieldReferences;
}
public void setPrimitiveFields(Field[] fields, DBPrimitiveType[] fieldTypes, long primitiveFieldsDataReference) {
this.primitiveFields = fields;
this.primitiveFieldTypes = fieldTypes;
this.primitiveFieldsDataReference = primitiveFieldsDataReference;
}
public Method[] getPropertyGetters() {
return MethodUtils.getMethodsWithAnnotation(this.getClass(), DBPropertyGetter.class);
}
@ -64,7 +74,7 @@ public abstract class EnhancedObject {
}
public EnhancedObjectFullInfo getAllInfo() {
return new EnhancedObjectFullInfo(version, fieldReferences, fieldTypes, fields, propertyReferences, propertyTypes, loadedPropertyValues);
return new EnhancedObjectFullInfo(version, fieldReferences, fieldTypes, fields, primitiveFieldsDataReference, primitiveFieldTypes, primitiveFields, propertyReferences, propertyTypes, loadedPropertyValues);
}

View File

@ -1,16 +1,54 @@
package org.warp.cowdb;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.io.IOException;
import java.util.function.Supplier;
public interface EnhancedObjectUpgrader {
<T> T getPrimitiveField(int id, DBPrimitiveType integer) throws IOException;
default int getPrimitiveBoolean(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.BOOLEAN);
}
default int getPrimitiveByte(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.BYTE);
}
default int getPrimitiveShort(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.SHORT);
}
default int getPrimitiveChar(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.CHAR);
}
default int getPrimitiveInt(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.INTEGER);
}
default long getPrimitiveLong(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.LONG);
}
default float getPrimitiveFloat(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.FLOAT);
}
default double getPrimitiveDouble(int id) throws IOException {
return getPrimitiveField(id, DBPrimitiveType.DOUBLE);
}
Object getField(int id, DBDataType type, Supplier<Class<?>> enhancedClassType) throws IOException;
default Object getField(int id, DBDataType type) throws IOException {
return getField(id, type, null);
}
Object getMethod(int id, DBDataType type, Supplier<Class<?>> enhancedClassType) throws IOException;
default Object getMethod(int id, DBDataType type) throws IOException {
return getField(id, type, null);
}

View File

@ -1,6 +1,7 @@
package org.warp.cowdb;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import org.warp.jcwdb.ann.DBDataType;
import java.io.IOException;
@ -13,36 +14,12 @@ public interface IObjectsIO {
LongArrayList loadReferencesList(long reference) throws IOException;
boolean loadBoolean(long reference) throws IOException;
byte loadByte(long reference) throws IOException;
short loadShort(long reference) throws IOException;
char loadChar(long reference) throws IOException;
int loadInt(long reference) throws IOException;
long loadLong(long reference) throws IOException;
<T extends EnhancedObject> void setEnhancedObject(long reference, T value) throws IOException;
<T> void setObject(long reference, T value) throws IOException;
void setReferencesList(long reference, LongArrayList value) throws IOException;
void setBoolean(long reference, boolean value) throws IOException;
void setByte(long reference, byte value) throws IOException;
void setShort(long reference, short value) throws IOException;
void setChar(long reference, char value) throws IOException;
void setInt(long reference, int value) throws IOException;
void setLong(long reference, long value) throws IOException;
long newNullObject() throws IOException;
default <T extends EnhancedObject> long newEnhancedObject(T value) throws IOException {
@ -69,45 +46,11 @@ public interface IObjectsIO {
return reference;
}
default long newBoolean(boolean value) throws IOException {
long reference = newNullObject();
setBoolean(reference, value);
return reference;
}
default long newByte(byte value) throws IOException {
long reference = newNullObject();
setByte(reference, value);
return reference;
}
default long newShort(short value) throws IOException {
long reference = newNullObject();
setShort(reference, value);
return reference;
}
default long newChar(char value) throws IOException {
long reference = newNullObject();
setChar(reference, value);
return reference;
}
default long newInt(int value) throws IOException {
long reference = newNullObject();
setInt(reference, value);
return reference;
}
default long newLong(long value) throws IOException {
long reference = newNullObject();
setLong(reference, value);
return reference;
}
void loadProperty(EnhancedObject enhancedObject, int propertyId, Method propertyGetter, DBDataType propertyType, long propertyUID) throws IOException;
void registerClass(Class<?> type, int id);
IDataInitializer getDataInitializer();
LongList loadPrimitiveData(long id) throws IOException;
}

View File

@ -1,11 +1,9 @@
package org.warp.cowdb.database;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.warp.cowdb.EnhancedObject;
import org.warp.cowdb.IDataInitializer;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBField;
import org.warp.jcwdb.ann.DBPropertyGetter;
import org.warp.jcwdb.ann.DBPropertySetter;
import org.warp.jcwdb.ann.*;
import java.io.IOException;
import java.lang.reflect.Field;
@ -24,6 +22,7 @@ public class DatabaseDataInitializer implements IDataInitializer {
@Override
public void initializeDBObject(EnhancedObject obj) throws IOException {
initializeDBObjectFields(obj);
initializeDBObjectPrimitiveFields(obj);
initializeDBObjectProperties(obj);
}
@ -53,6 +52,61 @@ public class DatabaseDataInitializer implements IDataInitializer {
obj.setFields(fields, orderedFieldTypes, fieldUIDs);
}
private void initializeDBObjectPrimitiveFields(EnhancedObject obj) throws IOException {
// Declare the variables needed to get the biggest field Id
Field[] unorderedFields = objectsIO.getPrimitiveFields(obj);
// Find the biggest field Id
int biggestFieldId = objectsIO.getBiggestPrimitiveFieldId(unorderedFields);
// Allocate new UID
long fieldDataUID = objectsIO.newNullObject();
// Declare the other variables
Field[] fields = new Field[biggestFieldId + 1];
DBPrimitiveType[] orderedFieldTypes = new DBPrimitiveType[biggestFieldId + 1];
// Load all fields metadata and load them
try {
for (Field field : unorderedFields) {
DBPrimitiveField fieldAnnotation = field.getAnnotation(DBPrimitiveField.class);
int fieldId = fieldAnnotation.id();
DBPrimitiveType fieldType = fieldAnnotation.type();
switch (fieldType) {
case BOOLEAN:
FieldUtils.writeField(field, obj, false, true);
break;
case BYTE:
FieldUtils.writeField(field, obj, (byte) 0, true);
break;
case CHAR:
FieldUtils.writeField(field, obj, (char) 0, true);
break;
case SHORT:
FieldUtils.writeField(field, obj, (short) 0, true);
break;
case INTEGER:
FieldUtils.writeField(field, obj, 0, true);
break;
case LONG:
FieldUtils.writeField(field, obj, (long) 0, true);
break;
case FLOAT:
FieldUtils.writeField(field, obj, (float) 0, true);
break;
case DOUBLE:
FieldUtils.writeField(field, obj, (double) 0, true);
break;
}
fields[fieldId] = field;
orderedFieldTypes[fieldId] = fieldType;
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IOException(e);
}
// Set fields metadata
obj.setPrimitiveFields(fields, orderedFieldTypes, fieldDataUID);
}
private void initializeDBObjectProperties(EnhancedObject obj) throws IOException {
// Declare the variables needed to get the biggest property Id
Method[] unorderedPropertyGetters = obj.getPropertyGetters();

View File

@ -1,7 +1,9 @@
package org.warp.cowdb.database;
import it.unimi.dsi.fastutil.longs.LongList;
import org.warp.cowdb.EnhancedObjectUpgrader;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.io.IOException;
import java.util.function.Supplier;
@ -10,11 +12,13 @@ public class DatabaseEnhancedObjectUpgrader implements EnhancedObjectUpgrader {
private final DatabaseObjectsIO objectsIO;
private final long[] fieldRefs;
private final long[] methodRefs;
private final long primitiveDataRef;
public DatabaseEnhancedObjectUpgrader(DatabaseObjectsIO objectsIO, long[] fieldRefs, long[] methodRefs) {
public DatabaseEnhancedObjectUpgrader(DatabaseObjectsIO objectsIO, long[] fieldRefs, long[] methodRefs, long primitiveDataRef) {
this.objectsIO = objectsIO;
this.fieldRefs = fieldRefs;
this.methodRefs = methodRefs;
this.primitiveDataRef = primitiveDataRef;
}
@Override
@ -28,4 +32,30 @@ public class DatabaseEnhancedObjectUpgrader implements EnhancedObjectUpgrader {
public Object getMethod(int id, DBDataType type, Supplier<Class<?>> enhancedClassType) throws IOException {
return objectsIO.loadData(type, methodRefs[id], enhancedClassType);
}
@SuppressWarnings("unchecked")
@Override
public <T> T getPrimitiveField(int id, DBPrimitiveType type) throws IOException {
LongList data = objectsIO.loadPrimitiveData(primitiveDataRef);
switch (type) {
case BOOLEAN:
return (T) ((Object) (data.getLong(id) % 2 == 1));
case BYTE:
return (T) ((Object) ((byte) data.getLong(id)));
case SHORT:
return (T) ((Object) ((short) data.getLong(id)));
case CHAR:
return (T) ((Object) ((char) data.getLong(id)));
case INTEGER:
return (T) ((Object) ((int) data.getLong(id)));
case LONG:
return (T) ((Object) ((long) data.getLong(id)));
case FLOAT:
return (T) ((Object) ((float) Float.intBitsToFloat((int) data.getLong(id))));
case DOUBLE:
return (T) ((Object) ((double) Double.longBitsToDouble(data.getLong(id))));
default:
throw new IOException("Type " + type + " not implemented");
}
}
}

View File

@ -8,9 +8,13 @@ import it.unimi.dsi.fastutil.bytes.ByteArrayList;
import it.unimi.dsi.fastutil.chars.CharArrayList;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.warp.cowdb.*;
import org.warp.cowdb.EnhancedObject;
import org.warp.cowdb.IDataInitializer;
import org.warp.cowdb.IDatabaseTools;
import org.warp.cowdb.IObjectsIO;
import org.warp.jcwdb.ann.*;
import java.io.ByteArrayOutputStream;
@ -109,11 +113,12 @@ public class DatabaseObjectsIO implements IObjectsIO {
for (int i = 0; i < methodsCount; i++) {
methodRefs[i] = buffer.getLong();
}
return preloadEnhancedObject(objectType, serializedVersion, fieldRefs, methodRefs);
long nativeFieldsDataReference = buffer.getLong();
return preloadEnhancedObject(objectType, serializedVersion, nativeFieldsDataReference, fieldRefs,
methodRefs);
}
}
@SuppressWarnings("unchecked")
Object loadData(DBDataType propertyType, long dataReference, Supplier<Class<?>> returnType) throws IOException {
switch (propertyType) {
@ -123,18 +128,6 @@ public class DatabaseObjectsIO implements IObjectsIO {
return loadObject(dataReference);
case REFERENCES_LIST:
return loadReferencesList(dataReference);
case BOOLEAN:
return loadBoolean(dataReference);
case BYTE:
return loadByte(dataReference);
case SHORT:
return loadShort(dataReference);
case CHAR:
return loadChar(dataReference);
case INTEGER:
return loadInt(dataReference);
case LONG:
return loadLong(dataReference);
default:
throw new NullPointerException("Unknown data type");
}
@ -142,24 +135,6 @@ public class DatabaseObjectsIO implements IObjectsIO {
<T> void setData(long reference, DBDataType propertyType, T loadedPropertyValue) throws IOException {
switch (propertyType) {
case BOOLEAN:
setBoolean(reference, loadedPropertyValue != null && (boolean) loadedPropertyValue);
break;
case BYTE:
setByte(reference, loadedPropertyValue == null ? 0 : (byte) loadedPropertyValue);
break;
case SHORT:
setShort(reference, loadedPropertyValue == null ? 0 : (short) loadedPropertyValue);
break;
case CHAR:
setChar(reference, loadedPropertyValue == null ? 0 : (char) loadedPropertyValue);
break;
case INTEGER:
setInt(reference, loadedPropertyValue == null ? 0 : (int) loadedPropertyValue);
break;
case LONG:
setLong(reference, loadedPropertyValue == null ? 0 : (long) loadedPropertyValue);
break;
case OBJECT:
setObject(reference, loadedPropertyValue);
break;
@ -172,32 +147,87 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
}
<T extends EnhancedObject> void setPrimitives(T enhancedObject, long reference, DBPrimitiveType[] types, Field[] fields)
throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES * fields.length);
try {
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
DBPrimitiveType type = types[i];
if (field == null) {
buffer.putLong(0);
} else {
switch (type) {
case BOOLEAN:
buffer.putLong(field.getBoolean(enhancedObject) ? 1 : 0);
break;
case BYTE:
buffer.putLong(field.getByte(enhancedObject));
break;
case SHORT:
buffer.putLong(field.getShort(enhancedObject));
break;
case CHAR:
buffer.putLong(field.getChar(enhancedObject));
break;
case INTEGER:
buffer.putLong(field.getInt(enhancedObject));
break;
case LONG:
buffer.putLong(field.getLong(enhancedObject));
break;
case FLOAT:
buffer.putLong(Float.floatToRawIntBits(field.getFloat(enhancedObject)));
break;
case DOUBLE:
buffer.putLong(Double.doubleToRawLongBits(field.getDouble(enhancedObject)));
break;
}
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IOException(e);
}
buffer.flip();
referencesIO.writeToReference(reference, buffer.limit(), buffer);
}
@Override
public <T extends EnhancedObject> void setEnhancedObject(long reference, T value) throws IOException {
synchronized (accessLock) {
if (value != null) {
EnhancedObjectFullInfo objectFullInfo = value.getAllInfo();
if (objectFullInfo == null || objectFullInfo.getFieldReferences() == null || objectFullInfo.getPropertyReferences() == null) {
throw new NullPointerException("An EnhancedObject has been initialized using the empty constructor!");
if (objectFullInfo == null || objectFullInfo.getFieldReferences() == null
|| objectFullInfo.getPropertyReferences() == null) {
throw new NullPointerException(
"An EnhancedObject has been initialized using the empty constructor!");
}
int totalSize = Byte.BYTES + Integer.BYTES * 2 + objectFullInfo.getFieldReferences().length * Long.BYTES + objectFullInfo.getPropertyReferences().length * Long.BYTES;
final long[] fieldReferences = objectFullInfo.getFieldReferences();
final DBDataType[] fieldTypes = objectFullInfo.getFieldTypes();
final Field[] fields = objectFullInfo.getFields();
final long nativeFieldDataReference = objectFullInfo.getPrimitiveFieldDataReference();
final DBPrimitiveType[] nativeFieldTypes = objectFullInfo.getPrimitiveFieldTypes();
final Field[] nativeFields = objectFullInfo.getPrimitiveFields();
final long[] propertyReferences = objectFullInfo.getPropertyReferences();
final DBDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
final Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
final int totalSize = Byte.BYTES + Integer.BYTES * 2 + fieldReferences.length * Long.BYTES
+ propertyReferences.length * Long.BYTES + Long.BYTES;
ByteBuffer buffer = ByteBuffer.allocate(totalSize);
buffer.put((byte) objectFullInfo.getVersion());
buffer.putInt(objectFullInfo.getFieldReferences().length);
buffer.putInt(objectFullInfo.getPropertyReferences().length);
for (int i = 0; i < objectFullInfo.getFieldReferences().length; i++) {
buffer.putLong(objectFullInfo.getFieldReferences()[i]);
buffer.putInt(fieldReferences.length);
buffer.putInt(propertyReferences.length);
for (int i = 0; i < fieldReferences.length; i++) {
buffer.putLong(fieldReferences[i]);
}
for (int i = 0; i < objectFullInfo.getPropertyReferences().length; i++) {
buffer.putLong(objectFullInfo.getPropertyReferences()[i]);
for (int i = 0; i < propertyReferences.length; i++) {
buffer.putLong(propertyReferences[i]);
}
long[] fieldReferences = objectFullInfo.getFieldReferences();
DBDataType[] fieldTypes = objectFullInfo.getFieldTypes();
Field[] fields = objectFullInfo.getFields();
long[] propertyReferences = objectFullInfo.getPropertyReferences();
DBDataType[] propertyTypes = objectFullInfo.getPropertyTypes();
Object[] propertyValues = objectFullInfo.getLoadedPropertyValues();
for (int i = 0; i < objectFullInfo.getFieldReferences().length; i++) {
buffer.putLong(nativeFieldDataReference);
buffer.flip();
for (int i = 0; i < fieldReferences.length; i++) {
if (fields[i] != null) {
try {
setData(fieldReferences[i], fieldTypes[i], fields[i].get(value));
@ -206,12 +236,12 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
}
}
for (int i = 0; i < objectFullInfo.getPropertyReferences().length; i++) {
for (int i = 0; i < propertyReferences.length; i++) {
if (propertyValues[i] != null) {
setData(propertyReferences[i], propertyTypes[i], propertyValues[i]);
}
}
buffer.flip();
setPrimitives(value, nativeFieldDataReference, nativeFieldTypes, nativeFields);
referencesIO.writeToReference(reference, totalSize, buffer);
} else {
referencesIO.writeToReference(reference, 0, null);
@ -250,68 +280,18 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
@Override
public boolean loadBoolean(long reference) throws IOException {
public LongList loadPrimitiveData(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return false;
return null;
}
return buffer.get() == 1;
}
}
@Override
public byte loadByte(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return 0;
int size = buffer.limit() / Long.BYTES;
LongArrayList result = new LongArrayList(size);
for (int i = 0; i < size; i++) {
result.add(buffer.getLong());
}
return buffer.get();
}
}
@Override
public short loadShort(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return 0;
}
return buffer.getShort();
}
}
@Override
public char loadChar(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return 0;
}
return buffer.getChar();
}
}
@Override
public int loadInt(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return 0;
}
return buffer.getInt();
}
}
@Override
public long loadLong(long reference) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = referencesIO.readFromReference(reference);
if (buffer.limit() == 0) {
return 0;
}
return buffer.getLong();
return result;
}
}
@ -350,66 +330,6 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
}
@Override
public void setBoolean(long reference, boolean value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Byte.BYTES);
buffer.put(value ? (byte) 1 : (byte) 0);
buffer.flip();
referencesIO.writeToReference(reference, Byte.BYTES, buffer);
}
}
@Override
public void setByte(long reference, byte value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Byte.BYTES);
buffer.put(value);
buffer.flip();
referencesIO.writeToReference(reference, Byte.BYTES, buffer);
}
}
@Override
public void setShort(long reference, short value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Short.BYTES);
buffer.putShort(value);
buffer.flip();
referencesIO.writeToReference(reference, Short.BYTES, buffer);
}
}
@Override
public void setChar(long reference, char value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Character.BYTES);
buffer.putChar(value);
buffer.flip();
referencesIO.writeToReference(reference, Character.BYTES, buffer);
}
}
@Override
public void setInt(long reference, int value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES);
buffer.putInt(value);
buffer.flip();
referencesIO.writeToReference(reference, Integer.BYTES, buffer);
}
}
@Override
public void setLong(long reference, long value) throws IOException {
synchronized (accessLock) {
ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
buffer.putLong(value);
buffer.flip();
referencesIO.writeToReference(reference, Long.BYTES, buffer);
}
}
@Override
public long newNullObject() throws IOException {
synchronized (accessLock) {
@ -418,7 +338,8 @@ public class DatabaseObjectsIO implements IObjectsIO {
}
@Override
public void loadProperty(EnhancedObject obj, int propertyId, Method property, DBDataType propertyType, long propertyUID) throws IOException {
public void loadProperty(EnhancedObject obj, int propertyId, Method property, DBDataType propertyType,
long propertyUID) throws IOException {
synchronized (accessLock) {
obj.setProperty(propertyId, loadData(propertyType, propertyUID, property::getReturnType));
}
@ -475,7 +396,8 @@ public class DatabaseObjectsIO implements IObjectsIO {
setterMethods.put(property.getName(), propertyAnnotation);
}
// Set properties metadata
obj.setProperties(propertyGetters, propertySetters, propertyTypes, propertyReferences, setterMethods, getterMethods);
obj.setProperties(propertyGetters, propertySetters, propertyTypes, propertyReferences, setterMethods,
getterMethods);
}
int getBiggestPropertyGetterId(Method[] unorderedPropertyGetters) {
@ -502,7 +424,72 @@ public class DatabaseObjectsIO implements IObjectsIO {
return biggestPropertyId;
}
private <T extends EnhancedObject> void preloadEnhancedObjectFields(T obj, long[] fieldReferences) throws IOException {
private <T extends EnhancedObject> void preloadEnhancedObjectPrimitiveFields(T obj, long nativeFieldsDataReference)
throws IOException {
// Declare the variables needed to get the biggest field Id
Field[] unorderedFields = getPrimitiveFields(obj);
// Find the biggest field Id
int biggestFieldId = getBiggestPrimitiveFieldId(unorderedFields);
// Declare the other variables
Field[] fields = new Field[biggestFieldId + 1];
DBPrimitiveType[] orderedFieldTypes = new DBPrimitiveType[biggestFieldId + 1];
// Load all fields metadata
for (Field field : unorderedFields) {
DBPrimitiveField fieldAnnotation = field.getAnnotation(DBPrimitiveField.class);
int fieldId = fieldAnnotation.id();
DBPrimitiveType fieldType = fieldAnnotation.type();
fields[fieldId] = field;
orderedFieldTypes[fieldId] = fieldType;
}
// Load fields data
ByteBuffer buffer = referencesIO.readFromReference(nativeFieldsDataReference);
// Load fields
try {
for (int id = 0; id < fields.length; id++) {
Field field = fields[id];
DBPrimitiveType type = orderedFieldTypes[id];
switch (type) {
case BOOLEAN:
FieldUtils.writeField(field, obj, (boolean) (buffer.getLong() % 2 == 1), true);
break;
case BYTE:
FieldUtils.writeField(field, obj, (byte) buffer.getLong(), true);
break;
case SHORT:
FieldUtils.writeField(field, obj, (short) buffer.getLong(), true);
break;
case CHAR:
FieldUtils.writeField(field, obj, (char) buffer.getLong(), true);
break;
case INTEGER:
FieldUtils.writeField(field, obj, (int) buffer.getLong(), true);
break;
case LONG:
FieldUtils.writeField(field, obj, (long) buffer.getLong(), true);
break;
case FLOAT:
FieldUtils.writeField(field, obj, Float.intBitsToFloat((int) buffer.getLong()), true);
break;
case DOUBLE:
FieldUtils.writeField(field, obj, Double.longBitsToDouble(buffer.getLong()), true);
break;
}
}
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IOException(e);
}
// Set fields metadata
obj.setPrimitiveFields(fields, orderedFieldTypes, nativeFieldsDataReference);
}
private <T extends EnhancedObject> void preloadEnhancedObjectFields(T obj, long[] fieldReferences)
throws IOException {
// Declare the variables needed to get the biggest field Id
Field[] unorderedFields = getFields(obj);
// Find the biggest field Id
@ -525,12 +512,14 @@ public class DatabaseObjectsIO implements IObjectsIO {
obj.setFields(fields, orderedFieldTypes, fieldReferences);
}
<T extends EnhancedObject> void loadField(T obj, Field field, DBDataType fieldType, long fieldReference) throws IOException {
<T extends EnhancedObject> void loadField(T obj, Field field, DBDataType fieldType, long fieldReference)
throws IOException {
Object data = loadData(fieldType, fieldReference, field::getType);
try {
if (fieldType == DBDataType.OBJECT && data != null) {
if (!field.getType().isInstance(data)) {
throw new IOException("There is an attempt to load an object of type " + data.getClass() + " into a field of type " + field.getType());
throw new IOException("There is an attempt to load an object of type " + data.getClass()
+ " into a field of type " + field.getType());
}
}
FieldUtils.writeField(field, obj, data, true);
@ -543,6 +532,10 @@ public class DatabaseObjectsIO implements IObjectsIO {
return FieldUtils.getFieldsWithAnnotation(obj.getClass(), DBField.class);
}
<T extends EnhancedObject> Field[] getPrimitiveFields(T obj) {
return FieldUtils.getFieldsWithAnnotation(obj.getClass(), DBPrimitiveField.class);
}
int getBiggestFieldId(Field[] unorderedFields) {
int biggestFieldId = -1;
for (Field field : unorderedFields) {
@ -555,19 +548,33 @@ public class DatabaseObjectsIO implements IObjectsIO {
return biggestFieldId;
}
int getBiggestPrimitiveFieldId(Field[] unorderedFields) {
int biggestFieldId = -1;
for (Field field : unorderedFields) {
DBPrimitiveField fieldAnnotation = field.getAnnotation(DBPrimitiveField.class);
int propertyId = fieldAnnotation.id();
if (propertyId > biggestFieldId) {
biggestFieldId = propertyId;
}
}
return biggestFieldId;
}
private <T extends EnhancedObject> T toInstance(Class<T> type) throws IOException {
try {
T obj = type.getConstructor().newInstance();
obj.setDatabaseTools(databaseTools);
return obj;
} catch (NoSuchMethodException e) {
throw new IOException("You must declare a public empty constructor in class " + type + ": public " + type.getSimpleName() + "()", e);
throw new IOException("You must declare a public empty constructor in class " + type + ": public "
+ type.getSimpleName() + "()", e);
} catch (IllegalAccessException | InvocationTargetException | InstantiationException e) {
throw new IOException(e);
}
}
private <T extends EnhancedObject> T preloadEnhancedObject(Class<T> objectType, int serializedVersion, long[] fieldRefs, long[] methodRefs) throws IOException {
private <T extends EnhancedObject> T preloadEnhancedObject(Class<T> objectType, int serializedVersion,
long nativeFieldsRef, long[] fieldRefs, long[] methodRefs) throws IOException {
// Instantiate the class to an object
T obj = toInstance(objectType);
@ -578,12 +585,14 @@ public class DatabaseObjectsIO implements IObjectsIO {
classVersion = dbClass.version();
}
if (classVersion > serializedVersion) {
DatabaseEnhancedObjectUpgrader enhancedObjectUpgrader = new DatabaseEnhancedObjectUpgrader(this, fieldRefs, methodRefs);
DatabaseEnhancedObjectUpgrader enhancedObjectUpgrader = new DatabaseEnhancedObjectUpgrader(this, fieldRefs, methodRefs, nativeFieldsRef);
dataInitializer.initializeDBObject(obj);
obj.onUpgrade(serializedVersion, enhancedObjectUpgrader);
} else if (classVersion < serializedVersion) {
throw new IllegalStateException("The serialized class is more recent than the current version of that class!");
throw new IllegalStateException(
"The serialized class is more recent than the current version of that class!");
} else {
preloadEnhancedObjectPrimitiveFields(obj, nativeFieldsRef);
preloadEnhancedObjectFields(obj, fieldRefs);
preloadEnhancedObjectProperties(obj, methodRefs);
}
@ -602,4 +611,5 @@ public class DatabaseObjectsIO implements IObjectsIO {
public IDataInitializer getDataInitializer() {
return dataInitializer;
}
}

View File

@ -1,6 +1,7 @@
package org.warp.cowdb.database;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.lang.reflect.Field;
@ -9,11 +10,14 @@ public class EnhancedObjectFullInfo {
private final long[] fieldReferences;
private final DBDataType[] fieldTypes;
private final Field[] fields;
private final long primitiveFieldDataReference;
private final DBPrimitiveType[] primitiveFieldTypes;
private final Field[] primitiveFields;
private final long[] propertyReferences;
private final DBDataType[] propertyTypes;
private final Object[] loadedPropertyValues;
public EnhancedObjectFullInfo(int version, long[] fieldReferences, DBDataType[] fieldTypes, Field[] fields, long[] propertyReferences, DBDataType[] propertyTypes, Object[] loadedPropertyValues) {
public EnhancedObjectFullInfo(int version, long[] fieldReferences, DBDataType[] fieldTypes, Field[] fields, long primitiveFieldDataReference, DBPrimitiveType[] primitiveFieldTypes, Field[] primitiveFields, long[] propertyReferences, DBDataType[] propertyTypes, Object[] loadedPropertyValues) {
this.version = version;
if (version > 255) {
throw new IllegalArgumentException();
@ -21,6 +25,9 @@ public class EnhancedObjectFullInfo {
this.fieldReferences = fieldReferences;
this.fieldTypes = fieldTypes;
this.fields = fields;
this.primitiveFieldDataReference = primitiveFieldDataReference;
this.primitiveFieldTypes = primitiveFieldTypes;
this.primitiveFields = primitiveFields;
this.propertyReferences = propertyReferences;
this.propertyTypes = propertyTypes;
this.loadedPropertyValues = loadedPropertyValues;
@ -42,6 +49,18 @@ public class EnhancedObjectFullInfo {
return fields;
}
public long getPrimitiveFieldDataReference() {
return primitiveFieldDataReference;
}
public DBPrimitiveType[] getPrimitiveFieldTypes() {
return primitiveFieldTypes;
}
public Field[] getPrimitiveFields() {
return primitiveFields;
}
long[] getPropertyReferences() {
return propertyReferences;
}

View File

@ -3,11 +3,5 @@ package org.warp.jcwdb.ann;
public enum DBDataType {
ENHANCED_OBJECT,
OBJECT,
BOOLEAN,
BYTE,
SHORT,
CHAR,
INTEGER,
LONG,
REFERENCES_LIST
}

View File

@ -0,0 +1,13 @@
package org.warp.jcwdb.ann;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface DBPrimitiveField {
int id();
DBPrimitiveType type();
}

View File

@ -0,0 +1,12 @@
package org.warp.jcwdb.ann;
public enum DBPrimitiveType {
BOOLEAN,
BYTE,
SHORT,
CHAR,
INTEGER,
LONG,
FLOAT,
DOUBLE
}

View File

@ -1,11 +1,11 @@
package org.warp.jcwdb.tests;
import org.warp.cowdb.EnhancedObject;
import org.warp.cowdb.IDatabase;
import org.warp.cowdb.IDatabaseTools;
import org.warp.jcwdb.ann.DBClass;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBField;
import org.warp.jcwdb.ann.DBPrimitiveField;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.io.IOException;
@ -14,10 +14,10 @@ public class OldClass extends EnhancedObject {
@DBField(id = 0, type = DBDataType.OBJECT)
public String field1;
@DBField(id = 1, type = DBDataType.INTEGER)
@DBPrimitiveField(id = 0, type = DBPrimitiveType.INTEGER)
public int field2;
@DBField(id = 3, type = DBDataType.INTEGER)
@DBPrimitiveField(id = 2, type = DBPrimitiveType.INTEGER)
public int field4;
public OldClass() {

View File

@ -10,11 +10,9 @@ import org.warp.jcwdb.VariableWrapper;
import org.warp.jcwdb.ann.*;
import java.io.IOException;
import java.lang.reflect.Array;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Vector;
public class Performance {
private static boolean FAST_TESTS;
@ -324,10 +322,10 @@ public class Performance {
@DBField(id = 0, type = DBDataType.OBJECT)
public ArrayList<String> object;
@DBField(id = 1, type = DBDataType.INTEGER)
@DBPrimitiveField(id = 0, type = DBPrimitiveType.INTEGER)
public int integerNumber;
@DBField(id = 2, type = DBDataType.LONG)
@DBPrimitiveField(id = 1, type = DBPrimitiveType.LONG)
public long longNumber;
}
}

View File

@ -2,23 +2,24 @@ package org.warp.jcwdb.tests;
import org.warp.cowdb.EnhancedObject;
import org.warp.cowdb.EnhancedObjectUpgrader;
import org.warp.cowdb.IDatabase;
import org.warp.cowdb.IDatabaseTools;
import org.warp.jcwdb.ann.DBClass;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBField;
import org.warp.jcwdb.ann.DBPrimitiveField;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.io.IOException;
@DBClass(version = 1)
public class V2Class extends EnhancedObject {
@DBField(id = 0, type = DBDataType.LONG)
@DBPrimitiveField(id = 0, type = DBPrimitiveType.LONG)
public long field1;
@DBField(id = 1, type = DBDataType.INTEGER)
@DBPrimitiveField(id = 1, type = DBPrimitiveType.INTEGER)
public int field2;
@DBField(id = 3, type = DBDataType.OBJECT)
@DBField(id = 0, type = DBDataType.OBJECT)
public String field4;
public V2Class() {
@ -33,8 +34,8 @@ public class V2Class extends EnhancedObject {
public void onUpgrade(int oldObjectVersion, EnhancedObjectUpgrader enhancedObjectUpgrader) throws IOException {
switch (oldObjectVersion) {
case 0: {
field1 = (long) (Integer) enhancedObjectUpgrader.getField(3, DBDataType.INTEGER);
field2 = (int) enhancedObjectUpgrader.getField(1, DBDataType.INTEGER);
field1 = (long) enhancedObjectUpgrader.getPrimitiveInt(2);
field2 = enhancedObjectUpgrader.getPrimitiveInt(0);
field4 = (String) enhancedObjectUpgrader.getField(0, DBDataType.OBJECT);
break;
}

View File

@ -2,14 +2,14 @@ package org.warp.jcwdb.utils;
import org.warp.cowdb.Database;
import org.warp.cowdb.EnhancedObject;
import org.warp.jcwdb.ann.DBDataType;
import org.warp.jcwdb.ann.DBField;
import org.warp.jcwdb.ann.DBPrimitiveField;
import org.warp.jcwdb.ann.DBPrimitiveType;
import java.io.IOException;
public class NSimplestClass extends EnhancedObject {
@DBField(id = 0, type = DBDataType.BOOLEAN)
@DBPrimitiveField(id = 0, type = DBPrimitiveType.BOOLEAN)
public boolean field1;
public NSimplestClass() {

View File

@ -3,7 +3,6 @@ package org.warp.jcwdb.utils;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import org.warp.cowdb.Database;
import org.warp.cowdb.EnhancedObject;
import org.warp.cowdb.IDatabase;
import org.warp.cowdb.IDatabaseTools;
import org.warp.jcwdb.ann.*;
@ -99,12 +98,6 @@ public class NTestUtils {
}
public void setRootClassProperties(RootClass root) throws IOException {
root.set1(true);
root.set2((byte)2);
root.set3((short)3);
root.set4((char)4);
root.set5(5);
root.set6(6);
root.set7("Test");
LongArrayList lArrayList = new LongArrayList();
lArrayList.add(0);
@ -138,12 +131,6 @@ public class NTestUtils {
}
public void testRootClassProperties(RootClass root) {
shouldGetPropertyBoolean(root);
shouldGetPropertyByte(root);
shouldGetPropertyShort(root);
shouldGetPropertyCharacter(root);
shouldGetPropertyInteger(root);
shouldGetPropertyLong(root);
shouldGetPropertyObject(root);
shouldGetPropertyUID(root);
shouldGetPropertyDBObject(root);
@ -154,50 +141,26 @@ public class NTestUtils {
assertTrue(root.field1);
}
private void shouldGetPropertyBoolean(RootClass root) {
assertTrue(root.get1());
}
private void shouldGetFieldByte(RootClass root) {
assertEquals(2, root.field2);
}
private void shouldGetPropertyByte(RootClass root) {
assertEquals(2, root.get2());
}
private void shouldGetFieldShort(RootClass root) {
assertEquals(3, root.field3);
}
private void shouldGetPropertyShort(RootClass root) {
assertEquals(3, root.get3());
}
private void shouldGetFieldCharacter(RootClass root) {
assertEquals(4, root.field4);
}
private void shouldGetPropertyCharacter(RootClass root) {
assertEquals(4, root.get4());
}
private void shouldGetFieldInteger(RootClass root) {
assertEquals(5, root.field5);
}
private void shouldGetPropertyInteger(RootClass root) {
assertEquals(5, root.get5());
}
private void shouldGetFieldLong(RootClass root) {
assertEquals(6, root.field6);
}
private void shouldGetPropertyLong(RootClass root) {
assertEquals(6, root.get6());
}
private void shouldGetFieldObject(RootClass root) {
shouldGetObject(root.field7);
}
@ -247,31 +210,31 @@ public class NTestUtils {
public static class RootClass extends EnhancedObject {
@DBField(id = 0, type = DBDataType.BOOLEAN)
@DBPrimitiveField(id = 0, type = DBPrimitiveType.BOOLEAN)
public boolean field1;
@DBField(id = 1, type = DBDataType.BYTE)
@DBPrimitiveField(id = 1, type = DBPrimitiveType.BYTE)
public byte field2;
@DBField(id = 2, type = DBDataType.SHORT)
@DBPrimitiveField(id = 2, type = DBPrimitiveType.SHORT)
public short field3;
@DBField(id = 3, type = DBDataType.CHAR)
@DBPrimitiveField(id = 3, type = DBPrimitiveType.CHAR)
public char field4;
@DBField(id = 4, type = DBDataType.INTEGER)
@DBPrimitiveField(id = 4, type = DBPrimitiveType.INTEGER)
public int field5;
@DBField(id = 5, type = DBDataType.LONG)
@DBPrimitiveField(id = 5, type = DBPrimitiveType.LONG)
public long field6;
@DBField(id = 6, type = DBDataType.OBJECT)
@DBField(id = 0, type = DBDataType.OBJECT)
public String field7;
@DBField(id = 7, type = DBDataType.REFERENCES_LIST)
@DBField(id = 1, type = DBDataType.REFERENCES_LIST)
public LongArrayList field8;
@DBField(id = 8, type = DBDataType.ENHANCED_OBJECT)
@DBField(id = 2, type = DBDataType.ENHANCED_OBJECT)
public NSimplestClass field9;
public RootClass() {
@ -282,92 +245,32 @@ public class NTestUtils {
super(databaseTools);
}
@DBPropertyGetter(id = 0, type = DBDataType.BOOLEAN)
public boolean get1() {
return getProperty();
}
@DBPropertyGetter(id = 1, type = DBDataType.BYTE)
public byte get2() {
return getProperty();
}
@DBPropertyGetter(id = 2, type = DBDataType.SHORT)
public short get3() {
return getProperty();
}
@DBPropertyGetter(id = 3, type = DBDataType.CHAR)
public char get4() {
return getProperty();
}
@DBPropertyGetter(id = 4, type = DBDataType.INTEGER)
public int get5() {
return getProperty();
}
@DBPropertyGetter(id = 5, type = DBDataType.LONG)
public long get6() {
return getProperty();
}
@DBPropertyGetter(id = 6, type = DBDataType.OBJECT)
@DBPropertyGetter(id = 0, type = DBDataType.OBJECT)
public String get7() {
return getProperty();
}
@DBPropertyGetter(id = 7, type = DBDataType.REFERENCES_LIST)
@DBPropertyGetter(id = 1, type = DBDataType.REFERENCES_LIST)
public LongArrayList get8() {
return getProperty();
}
@DBPropertyGetter(id = 8, type = DBDataType.ENHANCED_OBJECT)
@DBPropertyGetter(id = 2, type = DBDataType.ENHANCED_OBJECT)
public NSimplestClass get9() {
return getProperty();
}
@DBPropertySetter(id = 0, type = DBDataType.BOOLEAN)
public void set1(boolean val) {
setProperty(val);
}
@DBPropertySetter(id = 1, type = DBDataType.BYTE)
public void set2(byte val) {
setProperty(val);
}
@DBPropertySetter(id = 2, type = DBDataType.SHORT)
public void set3(short val) {
setProperty(val);
}
@DBPropertySetter(id = 3, type = DBDataType.CHAR)
public void set4(char val) {
setProperty(val);
}
@DBPropertySetter(id = 4, type = DBDataType.INTEGER)
public void set5(int val) {
setProperty(val);
}
@DBPropertySetter(id = 5, type = DBDataType.LONG)
public void set6(long val) {
setProperty(val);
}
@DBPropertySetter(id = 6, type = DBDataType.OBJECT)
@DBPropertySetter(id = 0, type = DBDataType.OBJECT)
public void set7(String val) {
setProperty(val);
}
@DBPropertySetter(id = 7, type = DBDataType.REFERENCES_LIST)
@DBPropertySetter(id = 1, type = DBDataType.REFERENCES_LIST)
public void set8(LongArrayList val) {
setProperty(val);
}
@DBPropertySetter(id = 8, type = DBDataType.ENHANCED_OBJECT)
@DBPropertySetter(id = 2, type = DBDataType.ENHANCED_OBJECT)
public void set9(NSimplestClass val) {
setProperty(val);
}