replace : iotivity -> iotivity-sec
[platform/upstream/iotivity.git] / service / resource-encapsulation / android / service / src / main / jni / JniRcsValue.cpp
1 /******************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20
21 #include "JniRcsValue.h"
22
23 #include "JniRcsObject.h"
24 #include "JniRcsResourceAttributes.h"
25 #include "JavaClasses.h"
26 #include "JavaExceptions.h"
27 #include "JavaLocalRef.h"
28 #include "Log.h"
29
30 using namespace OIC::Service;
31
32 #define LOG_TAG "JNI-RCSValue"
33
34 #define CLS_NAME_VALUE_TYPE CLS_NAME_VALUE "$Type"
35 #define CLS_NAME_VALUE_TYPEID CLS_NAME_VALUE "$TypeId"
36 #define CLS_NAME_VALUE_NULL_TYPE CLS_NAME_VALUE "$NullType"
37
38 namespace
39 {
40     jclass g_cls_RCSValue;
41     jclass g_cls_Type;
42     jclass g_cls_TypeId;
43
44     jmethodID g_ctor_RCSValue;
45
46     jmethodID g_smethod_Type_getDepth;
47     jmethodID g_smethod_Type_getBaseTypeId;
48
49     jmethodID g_method_RCSValue_getType;
50
51     jfieldID g_field_RCSValue_mObject;
52     jfieldID g_field_RCSValue_sNullValue;
53
54     jobject g_obj_TypeId_Null;
55     jobject g_obj_TypeId_Boolean;
56     jobject g_obj_TypeId_Integer;
57     jobject g_obj_TypeId_Double;
58     jobject g_obj_TypeId_String;
59     jobject g_obj_TypeId_ByteString;
60     jobject g_obj_TypeId_Attributes;
61     jobject g_obj_TypeId_Array;
62
63     template< int >
64     struct Int2Type{ };
65
66     template< int DEPTH, typename BASE_TYPE >
67     struct SeqType
68     {
69         typedef std::vector< typename SeqType< DEPTH - 1, BASE_TYPE >::type > type;
70     };
71
72     template< typename BASE_TYPE >
73     struct SeqType< 0, BASE_TYPE >
74     {
75         typedef BASE_TYPE type;
76     };
77
78     template< typename T >
79     struct BaseType
80     {
81       typedef T type;
82     };
83
84     template< typename T >
85     struct BaseType< std::vector< T > >
86     {
87       typedef typename BaseType< T >::type type;
88     };
89
90
91     template< int D >
92     struct ArrayPrefix
93     {
94         static constexpr char str[] = "";
95     };
96     template< int D >
97     constexpr char ArrayPrefix< D >::str[];
98
99     template<>
100     struct ArrayPrefix< 1 >
101     {
102         static constexpr char str[] = "[";
103     };
104     constexpr char ArrayPrefix< 1 >::str[];
105
106     template<>
107     struct ArrayPrefix< 2 >
108     {
109         static constexpr char str[] = "[[";
110     };
111     constexpr char ArrayPrefix< 2 >::str[];
112
113     struct PrimitiveType {
114         static constexpr bool isPrimitive = true;
115     };
116
117     struct ObjectType {
118         static constexpr bool isPrimitive = false;
119     };
120
121     template< typename T >
122     struct JniTypeTrait;
123
124     template<>
125     struct JniTypeTrait< int >: public PrimitiveType
126     {
127         static_assert(sizeof(int) == sizeof(jint), "int and jint have different size!");
128
129         static constexpr decltype(&JNIEnvWrapper::NewIntArray) newArrayFunc =
130                 &JNIEnvWrapper::NewIntArray;
131         static constexpr decltype(&JNIEnvWrapper::SetIntArrayRegion) setArrayRegionFunc =
132                       &JNIEnvWrapper::SetIntArrayRegion;
133
134         static constexpr decltype(&invoke_Integer_intValue<JNIEnvWrapper>) converter =
135                       &invoke_Integer_intValue<JNIEnvWrapper>;
136
137         static constexpr decltype(&newIntegerObject<JNIEnvWrapper>) newObjectFunc =
138                 &newIntegerObject<JNIEnvWrapper>;
139
140         static constexpr char className[] = "I";
141     };
142     constexpr char JniTypeTrait< int >::className[];
143
144     template<>
145     struct JniTypeTrait< bool >: public PrimitiveType
146     {
147         static_assert(sizeof(bool) == sizeof(jboolean), "bool and jboolean have different size!");
148
149         static constexpr decltype(&JNIEnvWrapper::NewBooleanArray) newArrayFunc =
150                 &JNIEnvWrapper::NewBooleanArray;
151         static constexpr decltype(&JNIEnvWrapper::SetBooleanArrayRegion) setArrayRegionFunc =
152                       &JNIEnvWrapper::SetBooleanArrayRegion;
153
154         static constexpr decltype(&invoke_Boolean_booleanValue<JNIEnvWrapper>) converter =
155                       &invoke_Boolean_booleanValue<JNIEnvWrapper>;
156
157         static constexpr decltype(&newBooleanObject<JNIEnvWrapper>) newObjectFunc =
158                 &newBooleanObject<JNIEnvWrapper>;
159
160         static constexpr char className[] = "Z";
161     };
162     constexpr char JniTypeTrait< bool >::className[];
163
164     template<>
165     struct JniTypeTrait< double > : public PrimitiveType
166     {
167         static_assert(sizeof(double) == sizeof(jdouble), "double and jdouble have different size!");
168
169         static constexpr decltype(&JNIEnvWrapper::NewDoubleArray) newArrayFunc =
170                 &JNIEnvWrapper::NewDoubleArray;
171         static constexpr decltype(&JNIEnvWrapper::SetDoubleArrayRegion) setArrayRegionFunc =
172                       &JNIEnvWrapper::SetDoubleArrayRegion;
173
174         static constexpr decltype(&invoke_Double_doubleValue<JNIEnvWrapper>) converter =
175                       &invoke_Double_doubleValue<JNIEnvWrapper>;
176
177         static constexpr decltype(&newDoubleObject<JNIEnvWrapper>) newObjectFunc =
178                 &newDoubleObject<JNIEnvWrapper>;
179
180         static constexpr char className[] = "D";
181     };
182     constexpr char JniTypeTrait< double >::className[];
183
184     template<>
185     struct JniTypeTrait< std::string >: public ObjectType
186     {
187         static constexpr decltype(&newStringObject<JNIEnvWrapper>) newObjectFunc =
188                 &newStringObject<JNIEnvWrapper>;
189
190         static constexpr char className[] = "L" CLS_NAME_STRING ";";
191     };
192     constexpr char JniTypeTrait< std::string >::className[];
193     template< typename ENV >
194     inline RCSByteString invoke_ByteString_byteStringValue(JNIEnvWrapper *env, jobject byteStringObj)
195     {
196         EXPECT_RET(byteStringObj, "byteStringObj is null!", { });
197
198         jclass g_cls_RCSByteString = env->FindClassAsGlobalRef(CLS_NAME_RESOURCEBYTESTRING);
199
200         static jfieldID field_data = env->GetFieldID(g_cls_RCSByteString, "mData", "[B");
201         static jfieldID field_length = env->GetFieldID(g_cls_RCSByteString, "mSize", "J");
202
203         jbyteArray jDataInfo = (jbyteArray)env->GetObjectField(byteStringObj, field_data);
204         jlong jDataLength = env->GetLongField(byteStringObj, field_length);
205
206         jbyte *byteStringData = env->GetByteArrayElements(jDataInfo, NULL);
207
208         RCSByteString byteString((uint8_t *)byteStringData, (size_t)jDataLength);
209
210         env->ReleaseByteArrayElements(jDataInfo, (jbyte*) byteStringData, JNI_ABORT);
211         env->DeleteGlobalRef(g_cls_RCSByteString);
212
213         return byteString;
214     }
215
216     template< typename ENV >
217     inline jobject newRCSByteStringObject(ENV* env, const RCSByteString& value)
218     {
219         jsize jSize = (jsize)value.size();
220
221         jbyteArray jData = env->NewByteArray(jSize);
222
223         std::vector<uint8_t> byteString = value.getByteString();
224
225         env->SetByteArrayRegion(jData, 0, jSize, (const jbyte*)&byteString[0]);
226
227         jclass g_cls_RCSByteString = env->FindClassAsGlobalRef(CLS_NAME_RESOURCEBYTESTRING);
228         jmethodID g_ctor_RCSByteString = env->GetConstructorID(g_cls_RCSByteString, "([BJ)V");
229
230         EXPECT_RET(g_ctor_RCSByteString, "g_ctor_RCSByteString is null!", { });
231
232         jobject jObj = (jobject)env->NewObject(g_cls_RCSByteString, g_ctor_RCSByteString, jData,
233                                                (jlong)jSize);
234
235         EXPECT_RET(jObj, "jObj is null!", { });
236
237         return jObj;
238     }
239
240     template<>
241     struct JniTypeTrait< RCSByteString >: public ObjectType
242     {
243         static decltype(&invoke_ByteString_byteStringValue<JNIEnvWrapper>) converter;
244
245         static decltype(&newRCSByteStringObject<JNIEnvWrapper>) newObjectFunc;
246
247         static constexpr char className[] = CLS_NAME_RESOURCEBYTESTRING;
248     };
249     constexpr char JniTypeTrait< RCSByteString >::className[];
250     decltype(&invoke_ByteString_byteStringValue<JNIEnvWrapper>) JniTypeTrait< RCSByteString >::converter =
251         &invoke_ByteString_byteStringValue<JNIEnvWrapper>;
252
253     decltype(&newRCSByteStringObject<JNIEnvWrapper>) JniTypeTrait< RCSByteString >::newObjectFunc =
254         &newRCSByteStringObject<JNIEnvWrapper>;
255
256     template<>
257     struct JniTypeTrait< RCSResourceAttributes >: public ObjectType
258     {
259         inline static jobject newObjectFunc(JNIEnvWrapper* env, const RCSResourceAttributes& value)
260         {
261             return newAttributesObject(env, value);
262         }
263
264         inline static RCSResourceAttributes converter(JNIEnvWrapper* env, jobject obj)
265         {
266             return toNativeAttributes(env, obj);
267         }
268
269         static constexpr char className[] = "L" CLS_NAME_RESOURCEATTRIBUTES ";";
270     };
271     constexpr char JniTypeTrait< RCSResourceAttributes >::className[];
272
273     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, std::string& result, Int2Type< 0 >)
274     {
275         result = toStdString(env, static_cast< jstring >(obj));
276     }
277
278     template< typename T >
279     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, T& result, Int2Type< 0 >)
280     {
281         result = JniTypeTrait< T >::converter(env, obj);
282     }
283
284     template< int DEPTH, typename RET >
285     inline void toNativeValue(JNIEnvWrapper* env, jobject obj, RET& result, Int2Type< DEPTH >)
286     {
287         const auto arrayObj = static_cast< jobjectArray >(obj);
288         result.resize(env->GetArrayLength(arrayObj));
289
290         for (typename RET::size_type i = 0; i < result.size(); ++i)
291         {
292             JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
293
294             toNativeValue(env, elementObj, result[i], Int2Type< DEPTH - 1 >{ });
295         }
296     }
297
298     template< typename T >
299     inline typename std::enable_if< JniTypeTrait< T >::isPrimitive >::type
300     toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
301     {
302         const auto arrayObj = static_cast< jobjectArray >(obj);
303         const jsize arraySize = env->GetArrayLength(arrayObj);
304
305         T* raw = static_cast< T* >(env->GetPrimitiveArrayCritical(arrayObj, nullptr));
306
307         try
308         {
309             result = std::vector< T >(raw, raw + arraySize);
310         } catch (...)
311         {
312         }
313
314         env->ReleasePrimitiveArrayCritical(arrayObj, raw, JNI_ABORT);
315     }
316
317     template< typename T >
318     inline typename std::enable_if< !JniTypeTrait< T >::isPrimitive >::type
319     toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
320     {
321         const auto arrayObj = static_cast< jobjectArray >(obj);
322         const jsize arraySize = env->GetArrayLength(arrayObj);
323
324         result.resize(arraySize);
325
326         for (typename std::vector< T >::size_type i = 0; i < result.size(); ++i)
327         {
328             JavaLocalObject elementObj{ env,  env->GetObjectArrayElement(arrayObj, i) };
329             toNativeValue(env, elementObj, result[i], Int2Type< 0 >{ });
330         }
331     }
332
333
334     template< typename T, int DEPTH, typename RET = typename SeqType< DEPTH, T >::type >
335     inline RET toNativeValue(JNIEnvWrapper* env, jobject obj)
336     {
337         static_assert(DEPTH >= 0, "DEPTH must be positive!");
338
339         typename SeqType< DEPTH, T >::type result;
340
341         toNativeValue(env, obj, result, Int2Type< DEPTH >{ });
342
343         return result;
344     }
345
346     template< typename T >
347     inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth)
348     {
349         switch (depth)
350         {
351             case 0: return toNativeValue< T, 0 >(env, val);
352             case 1: return toNativeValue< T, 1 >(env, val);
353             case 2: return toNativeValue< T, 2 >(env, val);
354             case 3: return toNativeValue< T, 3 >(env, val);
355         }
356
357         return {};
358     }
359
360     inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth,
361             RCSResourceAttributes::TypeId typeId)
362     {
363         LOGD("toNativeValue depth is %d", depth);
364         EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
365
366         switch (typeId)
367          {
368              case RCSResourceAttributes::TypeId::NULL_T: return { };
369
370              case RCSResourceAttributes::TypeId::BOOL:
371                  return toNativeValue< bool >(env, val, depth);
372
373              case RCSResourceAttributes::TypeId::INT:
374                  return toNativeValue< int >(env, val, depth);
375
376              case RCSResourceAttributes::TypeId::DOUBLE:
377                  return toNativeValue< double >(env, val, depth);
378
379              case RCSResourceAttributes::TypeId::STRING:
380                  return toNativeValue< std::string >(env, val, depth);
381
382             case RCSResourceAttributes::TypeId::BYTESTRING:
383                 return toNativeValue< RCSByteString >(env, val, depth);
384
385              case RCSResourceAttributes::TypeId::ATTRIBUTES:
386                  return toNativeValue< RCSResourceAttributes >(env, val, depth);
387          }
388
389         throwRCSException(env, "Failed to convert RCSValue : unknown type id");
390         return {};
391     }
392
393     template< typename T, int DEPTH, typename BASE_TYPE = typename BaseType< T >::type >
394     inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< DEPTH >)
395     {
396         const std::string elementClsName{ std::string{ ArrayPrefix< DEPTH - 1 >::str }
397             + JniTypeTrait< BASE_TYPE >::className };
398
399         LOGD("create array %dd, %s", DEPTH, elementClsName.c_str());
400
401         auto cls = env->FindClass(elementClsName.c_str());
402
403         const jsize len = value.size();
404
405         auto array = env->NewObjectArray(len, cls, nullptr);
406
407         for(jsize i = 0; i < len; ++i)
408         {
409             auto element = createJavaObject(env, value[i], Int2Type< DEPTH - 1>{ });
410             env->SetObjectArrayElement(array, i, element);
411         }
412
413         return array;
414     }
415
416     template< typename T, typename TRAIT = JniTypeTrait< T > >
417     inline typename std::enable_if< TRAIT::isPrimitive, jobject >::type
418     createJavaObject(JNIEnvWrapper* env, const std::vector< T >& value, Int2Type< 1 >)
419     {
420         LOGD("create array with newArray");
421         const jsize len = value.size();
422
423         auto array = (env->*TRAIT::newArrayFunc)(len);
424
425         if (!value.empty()) (env->*TRAIT::setArrayRegionFunc)(array, 0, len, &value[0]);
426
427         return array;
428     }
429
430     inline jobject createJavaObject(JNIEnvWrapper* env, const std::vector< bool >& value, Int2Type< 1 >)
431     {
432         const auto len = value.size();
433         LOGD("create bool array with newArray %d", len);
434
435         auto arrayObj = env->NewBooleanArray(len);
436
437         bool* raw = static_cast< bool* >(env->GetPrimitiveArrayCritical(arrayObj, 0));
438
439         std::copy(value.begin(), value.end(), raw);
440
441         env->ReleasePrimitiveArrayCritical(arrayObj, raw, 0);
442
443         return arrayObj;
444     }
445
446     template< typename T, typename TRAIT = JniTypeTrait< T > >
447     inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< 0 >)
448     {
449         LOGD("createJavaObject 0-depth");
450         return TRAIT::newObjectFunc(env, value);
451     }
452
453     template< int DEPTH >
454     inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
455     {
456         const auto type = value.getType();
457         const auto baseType = RCSResourceAttributes::Type::getBaseTypeId(type);
458
459         LOGD("createJavaObject with DEPTH. type is %d", static_cast< int >(baseType));
460
461         switch (baseType)
462         {
463             case RCSResourceAttributes::TypeId::NULL_T:
464                 return env->GetStaticObjectField(g_cls_RCSValue, g_field_RCSValue_sNullValue);
465
466             case RCSResourceAttributes::TypeId::BOOL:
467                 return createJavaObject(env, value.get< typename SeqType< DEPTH, bool >::type >(),
468                         Int2Type< DEPTH >{ });
469
470             case RCSResourceAttributes::TypeId::INT:
471                 return createJavaObject(env, value.get< typename SeqType< DEPTH, int >::type >(),
472                         Int2Type< DEPTH >{ });
473
474             case RCSResourceAttributes::TypeId::DOUBLE:
475                 return createJavaObject(env, value.get< typename SeqType< DEPTH, double >::type >(),
476                         Int2Type< DEPTH >{ });
477
478             case RCSResourceAttributes::TypeId::STRING:
479                 return createJavaObject(env,
480                         value.get< typename SeqType< DEPTH, std::string >::type >(),
481                         Int2Type< DEPTH >{ });
482
483             case RCSResourceAttributes::TypeId::BYTESTRING:
484                 return createJavaObject(env,
485                                         value.get< typename SeqType< DEPTH, RCSByteString >::type >(),
486                                         Int2Type< DEPTH > { });
487
488             case RCSResourceAttributes::TypeId::ATTRIBUTES:
489                 return createJavaObject(env,
490                         value.get< typename SeqType< DEPTH, RCSResourceAttributes >::type >(),
491                         Int2Type< DEPTH >{ });
492         }
493
494         LOGE("Unknown type!");
495
496         return nullptr;
497     }
498
499     inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
500     {
501         const auto type = value.getType();
502         const auto depth = RCSResourceAttributes::Type::getDepth(type);
503
504         EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
505
506         switch (depth)
507         {
508             case 0: return createJavaObject< 0 >(env, value);
509             case 1: return createJavaObject< 1 >(env, value);
510             case 2: return createJavaObject< 2 >(env, value);
511             case 3: return createJavaObject< 3 >(env, value);
512         }
513
514         return nullptr;
515     }
516
517     inline RCSResourceAttributes::TypeId toNativeTypeId(JNIEnvWrapper* env, jobject typeIdObj)
518     {
519         typedef RCSResourceAttributes::TypeId TypeId;
520
521         if (env->IsSameObject(g_obj_TypeId_Null, typeIdObj)) return TypeId::NULL_T;
522         if (env->IsSameObject(g_obj_TypeId_Boolean, typeIdObj)) return TypeId::BOOL;
523         if (env->IsSameObject(g_obj_TypeId_Integer, typeIdObj)) return TypeId::INT;
524         if (env->IsSameObject(g_obj_TypeId_Double, typeIdObj)) return TypeId::DOUBLE;
525         if (env->IsSameObject(g_obj_TypeId_String, typeIdObj)) return TypeId::STRING;
526         if (env->IsSameObject(g_obj_TypeId_ByteString, typeIdObj)) return TypeId::BYTESTRING;
527         if (env->IsSameObject(g_obj_TypeId_Attributes, typeIdObj)) return TypeId::ATTRIBUTES;
528         if (env->IsSameObject(g_obj_TypeId_Array, typeIdObj)) return TypeId::VECTOR;
529
530         throwRCSException(env, "Failed to convert RCSValue : unknown type id");
531         return TypeId::NULL_T;
532     }
533
534     jobject getTypeIdObj(JNIEnvWrapper* env, const char* name)
535     {
536         return env->NewGlobalRef(
537                 env->GetStaticObjectField(g_cls_TypeId, name, AS_SIG(CLS_NAME_VALUE_TYPEID)));
538     }
539 }
540
541 void initRCSValue(JNIEnvWrapper* env)
542 {
543     g_cls_RCSValue = env->FindClassAsGlobalRef(CLS_NAME_VALUE);
544     g_ctor_RCSValue = env->GetConstructorID(g_cls_RCSValue, "(" AS_SIG(CLS_NAME_OBJECT) ")V");
545
546     g_method_RCSValue_getType = env->GetMethodID(g_cls_RCSValue, "getType",
547             "()" AS_SIG(CLS_NAME_VALUE_TYPE));
548
549     g_field_RCSValue_mObject = env->GetFieldID(g_cls_RCSValue, "mObject", AS_SIG(CLS_NAME_OBJECT));
550
551     g_field_RCSValue_sNullValue = env->GetStaticFieldID(g_cls_RCSValue, "sNullValue",
552             AS_SIG(CLS_NAME_VALUE_NULL_TYPE));
553
554     g_cls_Type = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPE);
555
556     g_smethod_Type_getBaseTypeId = env->GetStaticMethodID(g_cls_Type, "getBaseTypeId",
557             "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")" AS_SIG(CLS_NAME_VALUE_TYPEID));
558
559     g_smethod_Type_getDepth = env->GetStaticMethodID(g_cls_Type, "getDepth",
560                 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")I");
561
562     g_cls_TypeId = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPEID);
563
564     g_obj_TypeId_Null = getTypeIdObj(env, "NULL");
565     g_obj_TypeId_Boolean = getTypeIdObj(env, "BOOLEAN");
566     g_obj_TypeId_Integer = getTypeIdObj(env, "INTEGER");
567     g_obj_TypeId_Double = getTypeIdObj(env, "DOUBLE");
568     g_obj_TypeId_String = getTypeIdObj(env, "STRING");
569     g_obj_TypeId_ByteString = getTypeIdObj(env, "BYTESTRING");
570     g_obj_TypeId_Attributes = getTypeIdObj(env, "ATTRIBUTES");
571     g_obj_TypeId_Array = getTypeIdObj(env, "ARRAY");
572 }
573
574 void clearRCSValue(JNIEnvWrapper* env)
575 {
576     env->DeleteGlobalRef(g_cls_RCSValue);
577     env->DeleteGlobalRef(g_cls_Type);
578     env->DeleteGlobalRef(g_cls_TypeId);
579
580     env->DeleteGlobalRef(g_obj_TypeId_Null);
581     env->DeleteGlobalRef(g_obj_TypeId_Boolean);
582     env->DeleteGlobalRef(g_obj_TypeId_Integer);
583     env->DeleteGlobalRef(g_obj_TypeId_Double);
584     env->DeleteGlobalRef(g_obj_TypeId_String);
585     env->DeleteGlobalRef(g_obj_TypeId_ByteString);
586     env->DeleteGlobalRef(g_obj_TypeId_Attributes);
587     env->DeleteGlobalRef(g_obj_TypeId_Array);
588 }
589
590 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnv* env, jobject valueObj)
591 {
592     JNIEnvWrapper envWrapper(env);
593
594     try
595     {
596         return toNativeAttrsValue(&envWrapper, valueObj);
597     }
598     catch (const JavaException&)
599     {
600         return { };
601     }
602 }
603
604 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnvWrapper* env, jobject valueObj)
605 {
606     auto typeObj = env->CallObjectMethod(valueObj, g_method_RCSValue_getType);
607     auto typeIdObj = env->CallStaticObjectMethod(g_cls_Type, g_smethod_Type_getBaseTypeId, typeObj);
608     auto depth = env->CallStaticIntMethod(g_cls_Type, g_smethod_Type_getDepth, typeObj);
609     auto memObj = env->GetObjectField(valueObj, g_field_RCSValue_mObject);
610
611     auto ret = toNativeValue(env, memObj, depth, toNativeTypeId(env, typeIdObj));
612
613     if (env->get()->ExceptionCheck()) throw JavaException();
614
615     return ret;
616 }
617
618 jobject newRCSValueObject(JNIEnv* env, const RCSResourceAttributes::Value& value)
619 {
620     JNIEnvWrapper envWrapper(env);
621
622     try
623     {
624         return newRCSValueObject(&envWrapper, value);
625     }
626     catch (const JavaException&)
627     {
628         return {};
629     }
630 }
631
632 jobject newRCSValueObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
633 {
634     LOGD("newRCSValueObject");
635
636     JavaLocalObject valueObj{ env, createJavaObject(env, value) };
637
638     if (env->get()->ExceptionCheck()) throw JavaException();
639
640     return env->NewObject(g_cls_RCSValue, g_ctor_RCSValue, valueObj.get());
641 }