strangedb/src/main/java/it/cavallium/strangedb/java/objects/lists/ValuePointer.java

140 lines
4.5 KiB
Java

package it.cavallium.strangedb.java.objects.lists;
import it.cavallium.strangedb.java.annotations.DbField;
import it.cavallium.strangedb.java.annotations.DbPrimitiveField;
import it.cavallium.strangedb.java.annotations.DbProperty;
import it.cavallium.strangedb.java.objects.EnhancedObject;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
public class ValuePointer {
private static ValuePointer base = new ValuePointer(new int[0], new ValueType[0]);
private final int[] pathNumbers;
private final ValueType[] pathTypes;
private ValuePointer(int[] pathNumbers, ValueType[] pathTypes) {
this.pathNumbers = pathNumbers;
this.pathTypes = pathTypes;
}
public static <T extends EnhancedObject> ValuePointer ofField(Class<T> parentType, String field) {
return base.field(parentType, field);
}
public static <T extends EnhancedObject> ValuePointer ofProp(Class<T> parentType, String property) {
return base.prop(parentType, property);
}
public static <T extends EnhancedObject> ValuePointer ofPrimitiveField(Class<T> parentType, String primitiveFieldName) {
return base.primitiveField(parentType, primitiveFieldName);
}
public <T extends EnhancedObject> ValuePointer prop(Class<T> parentType, String propertyName) {
ValueType[] newPathTypes = append(this.pathTypes, ValueType.FIELD);
Method[] methods = MethodUtils.getMethodsWithAnnotation(parentType, DbProperty.class);
DbProperty dbProperty = null;
for (Method method : methods) {
DbProperty annotation = method.getAnnotation(DbProperty.class);
if (annotation.name().equals(propertyName)) {
dbProperty = annotation;
break;
}
}
if (dbProperty == null) {
throw new IllegalArgumentException("Property '" + propertyName + "' not found in class " + parentType.getSimpleName());
}
int[] newPathNumbers = append(this.pathNumbers, dbProperty.id());
return new ValuePointer(newPathNumbers, newPathTypes);
}
public <T extends EnhancedObject> ValuePointer field(Class<T> parentType, String fieldName) {
ValueType[] newPathTypes = append(this.pathTypes, ValueType.FIELD);
Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbField.class);
DbField dbField = null;
for (Field field : fields) {
DbField annotation = field.getAnnotation(DbField.class);
if (annotation.name().equals(fieldName)) {
dbField = annotation;
break;
}
}
if (dbField == null) {
throw new IllegalArgumentException("Field '" + fieldName + "' not found in class " + parentType.getSimpleName());
}
int[] newPathNumbers = append(this.pathNumbers, dbField.id());
return new ValuePointer(newPathNumbers, newPathTypes);
}
public <T extends EnhancedObject> ValuePointer primitiveField(Class<T> parentType, String primitiveFieldName) {
ValueType[] newPathTypes = append(this.pathTypes, ValueType.PRIMITIVE_FIELD);
Field[] fields = FieldUtils.getFieldsWithAnnotation(parentType, DbPrimitiveField.class);
DbPrimitiveField dbField = null;
for (Field field : fields) {
DbPrimitiveField annotation = field.getAnnotation(DbPrimitiveField.class);
if (annotation.name().equals(primitiveFieldName)) {
dbField = annotation;
break;
}
}
if (dbField == null) {
throw new IllegalArgumentException("Field '" + primitiveFieldName + "' not found in class " + parentType.getSimpleName());
}
int[] newPathNumbers = append(this.pathNumbers, dbField.id());
return new ValuePointer(newPathNumbers, newPathTypes);
}
public ValuePointer at(int index) {
if (index >= pathNumbers.length) {
throw new ArrayIndexOutOfBoundsException();
}
if (index == pathNumbers.length - 1) {
return this;
}
return new ValuePointer(Arrays.copyOf(this.pathNumbers, index + 1), Arrays.copyOf(this.pathTypes, index + 1));
}
public int size() {
return this.pathNumbers.length;
}
public boolean hasPrevious() {
return pathNumbers.length > 0;
}
public ValuePointer previous() {
return at(pathNumbers.length - 2);
}
private static int[] append(int[] array, int value) {
int[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = value;
return newArray;
}
private static <T> T[] append(T[] array, T value) {
T[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[array.length] = value;
return newArray;
}
public int getPathNumber() {
return pathNumbers[pathNumbers.length - 1];
}
public ValueType getPathType() {
return pathTypes[pathTypes.length - 1];
}
}