Skip to content

Commit

Permalink
Implements reflection
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuel-keller committed Jun 23, 2024
1 parent 07a4fe9 commit 9b46f9f
Show file tree
Hide file tree
Showing 10 changed files with 284 additions and 77 deletions.
10 changes: 9 additions & 1 deletion src/main/java/com/surrealdb/Array.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,16 @@ public Iterator<Value> iterator() {
return new ValueIterator(iterator(getPtr()));
}

public SynchronizedValueIterator synchronizedIterator() {
public <T> Iterator<T> iterator(Class<T> clazz) {
return new ClassValueIterator(clazz, iterator());
}

public Iterator<Value> synchronizedIterator() {
return new SynchronizedValueIterator(synchronizedIterator(getPtr()));
}

public <T> Iterator<T> synchronizedIterator(Class<T> clazz) {
return new ClassValueIterator(clazz, synchronizedIterator());
}
}

123 changes: 123 additions & 0 deletions src/main/java/com/surrealdb/ClassValueIterator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package com.surrealdb;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

class ClassValueIterator<T> implements Iterator<T> {

private final Class<T> clazz;
private final Iterator<Value> iterator;

ClassValueIterator(Class<T> clazz, Iterator<Value> iterator) {
this.clazz = clazz;
this.iterator = iterator;
}


private static java.lang.Object convertArrayValue(Field field, Value value) throws ReflectiveOperationException {
if (value.isBoolean()) {
value.getBoolean();
} else if (value.isDouble()) {
return value.getDouble();
} else if (value.isLong()) {
return value.getLong();
} else if (value.isString()) {
return value.getString();
} else if (value.isThing()) {
return value.getThing();
} else if (value.isGeometry()) {
return value.getGeometry();
} else if (value.isBigdecimal()) {
return value.getBigDecimal();
} else if (value.isBytes()) {
return value.getBytes();
} else if (value.isUuid()) {
return value.getUuid();
} else if (value.isObject()) {
final Class<?> subType = getGenericType(field);
if (subType != null) {
return convertObject(subType, value.getObject());
}
} else if (value.isArray()) {
final List<java.lang.Object> arrayList = new ArrayList<>();
for (final Value elementValue : value.getArray()) {
arrayList.add(convertArrayValue(field, elementValue));
}
return arrayList;
}
return null;
}

private static <T> T convertObject(Class<T> clazz, Object source) throws ReflectiveOperationException {
final T target = clazz.getConstructor().newInstance();
for (final Entry entry : source) {
final Field field = clazz.getDeclaredField(entry.getKey());
final Value value = entry.getValue();
field.setAccessible(true);
if (value.isBoolean()) {
field.setBoolean(target, value.getBoolean());
} else if (value.isDouble()) {
field.setDouble(target, value.getDouble());
} else if (value.isLong()) {
field.setLong(target, value.getLong());
} else if (value.isString()) {
field.set(target, value.getString());
} else if (value.isThing()) {
field.set(target, value.getThing());
} else if (value.isGeometry()) {
field.set(target, value.getGeometry());
} else if (value.isBigdecimal()) {
field.set(target, value.getBigDecimal());
} else if (value.isBytes()) {
field.set(target, value.getBytes());
} else if (value.isUuid()) {
field.set(target, value.getUuid());
} else if (value.isArray()) {
final List<java.lang.Object> arrayList = new ArrayList<>();
for (final Value elementValue : value.getArray()) {
arrayList.add(convertArrayValue(field, elementValue));
}
field.set(target, arrayList);
} else if (value.isObject()) {
java.lang.Object o = convertObject(field.getType(), value.getObject());
field.set(target, o);
}
}
return target;
}

private static Class<?> getGenericType(Field field) {
// Check if the field is parameterized
if (field.getGenericType() instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) field.getGenericType();

// Get the actual type arguments (generics)
final Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();

if (actualTypeArguments.length > 0) {
// Return the first type argument
return (Class<?>) actualTypeArguments[0];
}
}
return null;
}

@Override
final public boolean hasNext() {
return iterator.hasNext();
}

@Override
final public T next() {
final Object source = iterator.next().getObject();
try {
return convertObject(clazz, source);
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Failed to create instance of " + clazz.getName(), e);
}
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/surrealdb/SynchronizedEntryIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import java.util.Iterator;

public class SynchronizedEntryIterator extends Native implements Iterator<Entry> {
class SynchronizedEntryIterator extends Native implements Iterator<Entry> {

SynchronizedEntryIterator(long ptr) {
super(ptr);
Expand All @@ -15,12 +15,12 @@ public class SynchronizedEntryIterator extends Native implements Iterator<Entry>
final protected native boolean deleteInstance(long ptr);

@Override
public boolean hasNext() {
final public boolean hasNext() {
return hasNext(getPtr());
}

@Override
public Entry next() {
final public Entry next() {
return new Entry(next(getPtr()));
}
}
8 changes: 4 additions & 4 deletions src/main/java/com/surrealdb/SynchronizedValueIterator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import java.util.Iterator;

public class SynchronizedValueIterator extends Native implements Iterator<Value> {
class SynchronizedValueIterator extends Native implements Iterator<Value> {

SynchronizedValueIterator(long ptr) {
super(ptr);
}
Expand All @@ -15,12 +15,12 @@ public class SynchronizedValueIterator extends Native implements Iterator<Value>
final protected native boolean deleteInstance(long ptr);

@Override
public boolean hasNext() {
final public boolean hasNext() {
return hasNext(getPtr());
}

@Override
public Value next() {
final public Value next() {
return new Value(next(getPtr()));
}
}
2 changes: 1 addition & 1 deletion src/main/rust/entryiterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ pub extern "system" fn Java_com_surrealdb_EntryIterator_next<'local>(
if let Some((k, v)) = iter.next() {
create_instance((k, Arc::new(v)))
} else {
SurrealError::NullPointerException("Value").exception(&mut env, || 0)
SurrealError::NoSuchElementException.exception(&mut env, || 0)
}
}
3 changes: 3 additions & 0 deletions src/main/rust/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,21 @@ use jni::JNIEnv;
pub(super) enum SurrealError {
Exception(Error),
NullPointerException(&'static str),
NoSuchElementException,
SurrealDB(surrealdb::Error),
}

const EXCEPTION: &str = "java/lang/exception";
const NULL_POINTER_EXCEPTION: &str = "java/lang/NullPointerException";
const NO_SUCH_ELEMENT_EXCEPTION: &str = "java/util/NoSuchElementException";
const SURREALDB_EXCEPTION: &str = "com/surrealdb/SurrealDBException";

impl ToException for SurrealError {
fn to_exception(&self) -> Exception {
match self {
Self::Exception(e) => Exception { class: EXCEPTION.to_string(), msg: format!("{e}") },
Self::NullPointerException(s) => Exception { class: NULL_POINTER_EXCEPTION.to_string(), msg: format!("{s} instance not found") },
Self::NoSuchElementException => Exception { class: NO_SUCH_ELEMENT_EXCEPTION.to_string(), msg: "No more elements".to_string() },
Self::SurrealDB(e) => Exception { class: SURREALDB_EXCEPTION.to_string(), msg: format!("{e}") }
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/rust/syncentryiterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ pub extern "system" fn Java_com_surrealdb_SynchronizedEntryIterator_next<'local>
if let Some((key, value)) = iter.next() {
create_instance((key, Arc::new(value)))
} else {
SurrealError::NullPointerException("Value").exception(&mut env, || 0)
SurrealError::NoSuchElementException.exception(&mut env, || 0)
}
}
2 changes: 1 addition & 1 deletion src/main/rust/syncvalueiterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ pub extern "system" fn Java_com_surrealdb_SynchronizedValueIterator_next<'local>
if let Some(v) = iter.next() {
create_instance(Arc::new(v))
} else {
SurrealError::NullPointerException("Value").exception(&mut env, || 0)
SurrealError::NoSuchElementException.exception(&mut env, || 0)
}
}
14 changes: 7 additions & 7 deletions src/main/rust/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getArray<'local>(
if value.is_array() {
create_instance(value)
} else {
SurrealError::NullPointerException("Not an array").exception(&mut env, || 0)
SurrealError::NullPointerException("Array").exception(&mut env, || 0)
}
}

Expand All @@ -86,7 +86,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getObject<'local>(
if value.is_object() {
create_instance(value)
} else {
SurrealError::NullPointerException("Not an object").exception(&mut env, || 0)
SurrealError::NullPointerException("Object").exception(&mut env, || 0)
}
}

Expand All @@ -111,7 +111,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getBoolean<'local>(
if let Value::Bool(b) = value.as_ref() {
*b as jboolean
} else {
SurrealError::NullPointerException("Not a boolean").exception(&mut env, || 0)
SurrealError::NullPointerException("Boolean").exception(&mut env, || 0)
}
}

Expand Down Expand Up @@ -213,7 +213,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getGeometry<'local>(
if let Value::Geometry(_) = value.as_ref() {
create_instance(value)
} else {
SurrealError::NullPointerException("Not a Geometry").exception(&mut env, || 0)
SurrealError::NullPointerException("Geometry").exception(&mut env, || 0)
}
}

Expand Down Expand Up @@ -257,7 +257,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getString<'local>(
if let Value::Strand(s) = value.as_ref() {
new_string!(&mut env, &s.0, ||null_mut())
} else {
SurrealError::NullPointerException("Not a string").exception(&mut env, || null_mut())
SurrealError::NullPointerException("String").exception(&mut env, || null_mut())
}
}

Expand All @@ -281,7 +281,7 @@ pub extern "system" fn Java_com_surrealdb_Value_getThing<'local>(
if let Value::Thing(_) = value.as_ref() {
create_instance(value)
} else {
SurrealError::NullPointerException("Not a thing").exception(&mut env, || 0)
SurrealError::NullPointerException("Thing").exception(&mut env, || 0)
}
}

Expand All @@ -305,6 +305,6 @@ pub extern "system" fn Java_com_surrealdb_Value_getUuid<'local>(
if let Value::Uuid(uuid) = value.as_ref() {
new_string!(&mut env, uuid.0.to_string(), ||null_mut())
} else {
SurrealError::NullPointerException("Not an UUID").exception(&mut env, || null_mut())
SurrealError::NullPointerException("UUID").exception(&mut env, || null_mut())
}
}
Loading

0 comments on commit 9b46f9f

Please sign in to comment.