33import java .lang .reflect .Field ;
44import java .lang .reflect .ParameterizedType ;
55import java .lang .reflect .Type ;
6- import java .util .ArrayList ;
7- import java .util .List ;
8- import java .util .Optional ;
6+ import java .util .*;
97
108class ValueClassConverter <T > {
119
@@ -16,6 +14,8 @@ class ValueClassConverter<T> {
1614 }
1715
1816 private static java .lang .Object convertSingleValue (final Value value ) {
17+ if (value .isNull ())
18+ return null ;
1919 if (value .isBoolean ())
2020 return value .getBoolean ();
2121 if (value .isDouble ())
@@ -42,7 +42,9 @@ private static java.lang.Object convertSingleValue(final Value value) {
4242 }
4343
4444 private static <T > void setSingleValue (final Field field , final Class <?> type , final T target , final Value value ) throws IllegalAccessException {
45- if (value .isBoolean ()) {
45+ if (value .isNull ()) {
46+ field .set (target , null );
47+ } else if (value .isBoolean ()) {
4648 field .setBoolean (target , value .getBoolean ());
4749 } else if (value .isDouble ()) {
4850 final double d = value .getDouble ();
@@ -94,7 +96,7 @@ else if (type == Short.class)
9496
9597 private static java .lang .Object convertArrayValue (final Field field , final Value value ) throws ReflectiveOperationException {
9698 if (value .isObject ()) {
97- final Class <?> subType = getGenericType (field );
99+ final Class <?> subType = getGenericType (field , 0 );
98100 if (subType == null ) {
99101 throw new SurrealException ("Unsupported field type: " + field );
100102 }
@@ -115,19 +117,42 @@ private static <T> T convert(Class<T> clazz, Object source) throws ReflectiveOpe
115117 for (final Entry entry : source ) {
116118 try {
117119 final String key = entry .getKey ();
118- final Field field = clazz .getField (key );
119120 final Value value = entry .getValue ();
120- field . setAccessible ( true );
121+ final Field field = getInheritedDeclaredField ( clazz , key );
121122 final Class <?> type = field .getType ();
122- if (value .isArray ()) {
123+
124+ field .setAccessible (true );
125+
126+ if (Value .class .equals (type )) {
127+ field .set (target , value );
128+ } else if (value .isArray ()) {
123129 final List <java .lang .Object > arrayList = new ArrayList <>();
124130 for (final Value elementValue : value .getArray ()) {
125131 arrayList .add (convertArrayValue (field , elementValue ));
126132 }
127133 setFieldObject (field , type , target , arrayList );
128134 } else if (value .isObject ()) {
129- java .lang .Object o = convert (type , value .getObject ());
130- setFieldObject (field , type , target , o );
135+ if (Map .class .isAssignableFrom (type )) {
136+ final Map <String , java .lang .Object > map = new HashMap <>();
137+ final Class <?> subType = getGenericType (field , 1 );
138+ if (subType == null ) {
139+ throw new SurrealException ("Unsupported field type: " + field );
140+ }
141+ for (final Entry mapEntry : value .getObject ()) {
142+ final String entryKey = mapEntry .getKey ();
143+ final Value entryValue = mapEntry .getValue ();
144+ // todo - array support
145+ if (entryValue .isObject ()) {
146+ map .put (entryKey , convert (subType , entryValue .getObject ()));
147+ } else {
148+ map .put (entryKey , convertSingleValue (entryValue ));
149+ }
150+ }
151+ setFieldObject (field , type , target , map );
152+ } else {
153+ java .lang .Object o = convert (type , value .getObject ());
154+ setFieldObject (field , type , target , o );
155+ }
131156 } else {
132157 setFieldSingleValue (field , type , target , value );
133158 }
@@ -148,30 +173,52 @@ private static <T, V> void setFieldObject(Field field, Class<?> type, T target,
148173
149174 private static <T , V > void setFieldSingleValue (Field field , Class <?> type , T target , Value value ) throws ReflectiveOperationException {
150175 if (Optional .class .equals (type )) {
151- field .set (target , convertSingleValue (value ));
176+ final java .lang .Object converted = convertSingleValue (value );
177+ if (converted == null ) {
178+ field .set (target , Optional .empty ());
179+ } else {
180+ field .set (target , Optional .of (converted ));
181+ }
152182 } else {
153183 setSingleValue (field , type , target , value );
154184 }
155185 }
156186
157- static Class <?> getGenericType (final Field field ) {
187+ static Class <?> getGenericType (final Field field , final int index ) {
158188 // Check if the field is parameterized
159189 if (field .getGenericType () instanceof ParameterizedType ) {
160190 ParameterizedType parameterizedType = (ParameterizedType ) field .getGenericType ();
161191
162192 // Get the actual type arguments (generics)
163193 final Type [] actualTypeArguments = parameterizedType .getActualTypeArguments ();
164194
165- if (actualTypeArguments .length > 0 ) {
195+ if (actualTypeArguments .length > index ) {
166196 // Return the first type argument
167- return (Class <?>) actualTypeArguments [0 ];
197+ return (Class <?>) actualTypeArguments [index ];
168198 }
169199 }
170200 return null ;
171201 }
172202
203+ static Field getInheritedDeclaredField (Class <?> clazz , String fieldName ) throws NoSuchFieldException {
204+ while (clazz != null ) {
205+ try {
206+ return clazz .getDeclaredField (fieldName );
207+ } catch (NoSuchFieldException e ) {
208+ clazz = clazz .getSuperclass ();
209+ }
210+ }
211+ throw new NoSuchFieldException ("Field '" + fieldName + "' not found in class hierarchy." );
212+ }
213+
173214 final T convert (final Value value ) {
174215 try {
216+ if (value .isNone () || value .isNull ())
217+ return null ;
218+
219+ if (!value .isObject ())
220+ throw new SurrealException ("Unexpected value: " + value );
221+
175222 return convert (clazz , value .getObject ());
176223 } catch (ReflectiveOperationException e ) {
177224 throw new SurrealException ("Failed to create instance of " + clazz .getName (), e );
0 commit comments