1 /******************************************************************
3 * Copyright 2015 Samsung Electronics All Rights Reserved.
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 ******************************************************************/
21 #include "JniRcsValue.h"
23 #include "JniRcsObject.h"
24 #include "JniRcsResourceAttributes.h"
25 #include "JavaClasses.h"
26 #include "JavaExceptions.h"
27 #include "JavaLocalRef.h"
30 using namespace OIC::Service;
32 #define LOG_TAG "JNI-RCSValue"
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"
40 jclass g_cls_RCSValue;
44 jmethodID g_ctor_RCSValue;
46 jmethodID g_smethod_Type_getDepth;
47 jmethodID g_smethod_Type_getBaseTypeId;
49 jmethodID g_method_RCSValue_getType;
51 jfieldID g_field_RCSValue_mObject;
52 jfieldID g_field_RCSValue_sNullValue;
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;
66 template< int DEPTH, typename BASE_TYPE >
69 typedef std::vector< typename SeqType< DEPTH - 1, BASE_TYPE >::type > type;
72 template< typename BASE_TYPE >
73 struct SeqType< 0, BASE_TYPE >
75 typedef BASE_TYPE type;
78 template< typename T >
84 template< typename T >
85 struct BaseType< std::vector< T > >
87 typedef typename BaseType< T >::type type;
94 static constexpr char str[] = "";
97 constexpr char ArrayPrefix< D >::str[];
100 struct ArrayPrefix< 1 >
102 static constexpr char str[] = "[";
104 constexpr char ArrayPrefix< 1 >::str[];
107 struct ArrayPrefix< 2 >
109 static constexpr char str[] = "[[";
111 constexpr char ArrayPrefix< 2 >::str[];
113 struct PrimitiveType {
114 static constexpr bool isPrimitive = true;
118 static constexpr bool isPrimitive = false;
121 template< typename T >
125 struct JniTypeTrait< int >: public PrimitiveType
127 static_assert(sizeof(int) == sizeof(jint), "int and jint have different size!");
129 static constexpr decltype(&JNIEnvWrapper::NewIntArray) newArrayFunc =
130 &JNIEnvWrapper::NewIntArray;
131 static constexpr decltype(&JNIEnvWrapper::SetIntArrayRegion) setArrayRegionFunc =
132 &JNIEnvWrapper::SetIntArrayRegion;
134 static constexpr decltype(&invoke_Integer_intValue<JNIEnvWrapper>) converter =
135 &invoke_Integer_intValue<JNIEnvWrapper>;
137 static constexpr decltype(&newIntegerObject<JNIEnvWrapper>) newObjectFunc =
138 &newIntegerObject<JNIEnvWrapper>;
140 static constexpr char className[] = "I";
142 constexpr char JniTypeTrait< int >::className[];
145 struct JniTypeTrait< bool >: public PrimitiveType
147 static_assert(sizeof(bool) == sizeof(jboolean), "bool and jboolean have different size!");
149 static constexpr decltype(&JNIEnvWrapper::NewBooleanArray) newArrayFunc =
150 &JNIEnvWrapper::NewBooleanArray;
151 static constexpr decltype(&JNIEnvWrapper::SetBooleanArrayRegion) setArrayRegionFunc =
152 &JNIEnvWrapper::SetBooleanArrayRegion;
154 static constexpr decltype(&invoke_Boolean_booleanValue<JNIEnvWrapper>) converter =
155 &invoke_Boolean_booleanValue<JNIEnvWrapper>;
157 static constexpr decltype(&newBooleanObject<JNIEnvWrapper>) newObjectFunc =
158 &newBooleanObject<JNIEnvWrapper>;
160 static constexpr char className[] = "Z";
162 constexpr char JniTypeTrait< bool >::className[];
165 struct JniTypeTrait< double > : public PrimitiveType
167 static_assert(sizeof(double) == sizeof(jdouble), "double and jdouble have different size!");
169 static constexpr decltype(&JNIEnvWrapper::NewDoubleArray) newArrayFunc =
170 &JNIEnvWrapper::NewDoubleArray;
171 static constexpr decltype(&JNIEnvWrapper::SetDoubleArrayRegion) setArrayRegionFunc =
172 &JNIEnvWrapper::SetDoubleArrayRegion;
174 static constexpr decltype(&invoke_Double_doubleValue<JNIEnvWrapper>) converter =
175 &invoke_Double_doubleValue<JNIEnvWrapper>;
177 static constexpr decltype(&newDoubleObject<JNIEnvWrapper>) newObjectFunc =
178 &newDoubleObject<JNIEnvWrapper>;
180 static constexpr char className[] = "D";
182 constexpr char JniTypeTrait< double >::className[];
185 struct JniTypeTrait< std::string >: public ObjectType
187 static constexpr decltype(&newStringObject<JNIEnvWrapper>) newObjectFunc =
188 &newStringObject<JNIEnvWrapper>;
190 static constexpr char className[] = "L" CLS_NAME_STRING ";";
192 constexpr char JniTypeTrait< std::string >::className[];
193 template< typename ENV >
194 inline RCSByteString invoke_ByteString_byteStringValue(JNIEnvWrapper *env, jobject byteStringObj)
196 EXPECT_RET(byteStringObj, "byteStringObj is null!", { });
198 jclass g_cls_RCSByteString = env->FindClassAsGlobalRef(CLS_NAME_RESOURCEBYTESTRING);
200 static jfieldID field_data = env->GetFieldID(g_cls_RCSByteString, "mData", "[B");
201 static jfieldID field_length = env->GetFieldID(g_cls_RCSByteString, "mSize", "J");
203 jbyteArray jDataInfo = (jbyteArray)env->GetObjectField(byteStringObj, field_data);
204 jlong jDataLength = env->GetLongField(byteStringObj, field_length);
206 jbyte *byteStringData = env->GetByteArrayElements(jDataInfo, NULL);
208 RCSByteString byteString((uint8_t *)byteStringData, (size_t)jDataLength);
210 env->ReleaseByteArrayElements(jDataInfo, (jbyte*) byteStringData, JNI_ABORT);
211 env->DeleteGlobalRef(g_cls_RCSByteString);
216 template< typename ENV >
217 inline jobject newRCSByteStringObject(ENV* env, const RCSByteString& value)
219 jsize jSize = (jsize)value.size();
221 jbyteArray jData = env->NewByteArray(jSize);
223 std::vector<uint8_t> byteString = value.getByteString();
225 env->SetByteArrayRegion(jData, 0, jSize, (const jbyte*)&byteString[0]);
227 jclass g_cls_RCSByteString = env->FindClassAsGlobalRef(CLS_NAME_RESOURCEBYTESTRING);
228 jmethodID g_ctor_RCSByteString = env->GetConstructorID(g_cls_RCSByteString, "([BJ)V");
230 EXPECT_RET(g_ctor_RCSByteString, "g_ctor_RCSByteString is null!", { });
232 jobject jObj = (jobject)env->NewObject(g_cls_RCSByteString, g_ctor_RCSByteString, jData,
235 EXPECT_RET(jObj, "jObj is null!", { });
241 struct JniTypeTrait< RCSByteString >: public ObjectType
243 static decltype(&invoke_ByteString_byteStringValue<JNIEnvWrapper>) converter;
245 static decltype(&newRCSByteStringObject<JNIEnvWrapper>) newObjectFunc;
247 static constexpr char className[] = CLS_NAME_RESOURCEBYTESTRING;
249 constexpr char JniTypeTrait< RCSByteString >::className[];
250 decltype(&invoke_ByteString_byteStringValue<JNIEnvWrapper>) JniTypeTrait< RCSByteString >::converter =
251 &invoke_ByteString_byteStringValue<JNIEnvWrapper>;
253 decltype(&newRCSByteStringObject<JNIEnvWrapper>) JniTypeTrait< RCSByteString >::newObjectFunc =
254 &newRCSByteStringObject<JNIEnvWrapper>;
257 struct JniTypeTrait< RCSResourceAttributes >: public ObjectType
259 inline static jobject newObjectFunc(JNIEnvWrapper* env, const RCSResourceAttributes& value)
261 return newAttributesObject(env, value);
264 inline static RCSResourceAttributes converter(JNIEnvWrapper* env, jobject obj)
266 return toNativeAttributes(env, obj);
269 static constexpr char className[] = "L" CLS_NAME_RESOURCEATTRIBUTES ";";
271 constexpr char JniTypeTrait< RCSResourceAttributes >::className[];
273 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, std::string& result, Int2Type< 0 >)
275 result = toStdString(env, static_cast< jstring >(obj));
278 template< typename T >
279 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, T& result, Int2Type< 0 >)
281 result = JniTypeTrait< T >::converter(env, obj);
284 template< int DEPTH, typename RET >
285 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, RET& result, Int2Type< DEPTH >)
287 const auto arrayObj = static_cast< jobjectArray >(obj);
288 result.resize(env->GetArrayLength(arrayObj));
290 for (typename RET::size_type i = 0; i < result.size(); ++i)
292 JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
294 toNativeValue(env, elementObj, result[i], Int2Type< DEPTH - 1 >{ });
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 >)
302 const auto arrayObj = static_cast< jobjectArray >(obj);
303 const jsize arraySize = env->GetArrayLength(arrayObj);
305 T* raw = static_cast< T* >(env->GetPrimitiveArrayCritical(arrayObj, nullptr));
309 result = std::vector< T >(raw, raw + arraySize);
314 env->ReleasePrimitiveArrayCritical(arrayObj, raw, JNI_ABORT);
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 >)
321 const auto arrayObj = static_cast< jobjectArray >(obj);
322 const jsize arraySize = env->GetArrayLength(arrayObj);
324 result.resize(arraySize);
326 for (typename std::vector< T >::size_type i = 0; i < result.size(); ++i)
328 JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
329 toNativeValue(env, elementObj, result[i], Int2Type< 0 >{ });
334 template< typename T, int DEPTH, typename RET = typename SeqType< DEPTH, T >::type >
335 inline RET toNativeValue(JNIEnvWrapper* env, jobject obj)
337 static_assert(DEPTH >= 0, "DEPTH must be positive!");
339 typename SeqType< DEPTH, T >::type result;
341 toNativeValue(env, obj, result, Int2Type< DEPTH >{ });
346 template< typename T >
347 inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth)
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);
360 inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth,
361 RCSResourceAttributes::TypeId typeId)
363 LOGD("toNativeValue depth is %d", depth);
364 EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
368 case RCSResourceAttributes::TypeId::NULL_T: return { };
370 case RCSResourceAttributes::TypeId::BOOL:
371 return toNativeValue< bool >(env, val, depth);
373 case RCSResourceAttributes::TypeId::INT:
374 return toNativeValue< int >(env, val, depth);
376 case RCSResourceAttributes::TypeId::DOUBLE:
377 return toNativeValue< double >(env, val, depth);
379 case RCSResourceAttributes::TypeId::STRING:
380 return toNativeValue< std::string >(env, val, depth);
382 case RCSResourceAttributes::TypeId::BYTESTRING:
383 return toNativeValue< RCSByteString >(env, val, depth);
385 case RCSResourceAttributes::TypeId::ATTRIBUTES:
386 return toNativeValue< RCSResourceAttributes >(env, val, depth);
389 throwRCSException(env, "Failed to convert RCSValue : unknown type id");
393 template< typename T, int DEPTH, typename BASE_TYPE = typename BaseType< T >::type >
394 inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< DEPTH >)
396 const std::string elementClsName{ std::string{ ArrayPrefix< DEPTH - 1 >::str }
397 + JniTypeTrait< BASE_TYPE >::className };
399 LOGD("create array %dd, %s", DEPTH, elementClsName.c_str());
401 auto cls = env->FindClass(elementClsName.c_str());
403 const jsize len = value.size();
405 auto array = env->NewObjectArray(len, cls, nullptr);
407 for(jsize i = 0; i < len; ++i)
409 auto element = createJavaObject(env, value[i], Int2Type< DEPTH - 1>{ });
410 env->SetObjectArrayElement(array, i, element);
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 >)
420 LOGD("create array with newArray");
421 const jsize len = value.size();
423 auto array = (env->*TRAIT::newArrayFunc)(len);
425 if (!value.empty()) (env->*TRAIT::setArrayRegionFunc)(array, 0, len, &value[0]);
430 inline jobject createJavaObject(JNIEnvWrapper* env, const std::vector< bool >& value, Int2Type< 1 >)
432 const auto len = value.size();
433 LOGD("create bool array with newArray %d", len);
435 auto arrayObj = env->NewBooleanArray(len);
437 bool* raw = static_cast< bool* >(env->GetPrimitiveArrayCritical(arrayObj, 0));
439 std::copy(value.begin(), value.end(), raw);
441 env->ReleasePrimitiveArrayCritical(arrayObj, raw, 0);
446 template< typename T, typename TRAIT = JniTypeTrait< T > >
447 inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< 0 >)
449 LOGD("createJavaObject 0-depth");
450 return TRAIT::newObjectFunc(env, value);
453 template< int DEPTH >
454 inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
456 const auto type = value.getType();
457 const auto baseType = RCSResourceAttributes::Type::getBaseTypeId(type);
459 LOGD("createJavaObject with DEPTH. type is %d", static_cast< int >(baseType));
463 case RCSResourceAttributes::TypeId::NULL_T:
464 return env->GetStaticObjectField(g_cls_RCSValue, g_field_RCSValue_sNullValue);
466 case RCSResourceAttributes::TypeId::BOOL:
467 return createJavaObject(env, value.get< typename SeqType< DEPTH, bool >::type >(),
468 Int2Type< DEPTH >{ });
470 case RCSResourceAttributes::TypeId::INT:
471 return createJavaObject(env, value.get< typename SeqType< DEPTH, int >::type >(),
472 Int2Type< DEPTH >{ });
474 case RCSResourceAttributes::TypeId::DOUBLE:
475 return createJavaObject(env, value.get< typename SeqType< DEPTH, double >::type >(),
476 Int2Type< DEPTH >{ });
478 case RCSResourceAttributes::TypeId::STRING:
479 return createJavaObject(env,
480 value.get< typename SeqType< DEPTH, std::string >::type >(),
481 Int2Type< DEPTH >{ });
483 case RCSResourceAttributes::TypeId::BYTESTRING:
484 return createJavaObject(env,
485 value.get< typename SeqType< DEPTH, RCSByteString >::type >(),
486 Int2Type< DEPTH > { });
488 case RCSResourceAttributes::TypeId::ATTRIBUTES:
489 return createJavaObject(env,
490 value.get< typename SeqType< DEPTH, RCSResourceAttributes >::type >(),
491 Int2Type< DEPTH >{ });
494 LOGE("Unknown type!");
499 inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
501 const auto type = value.getType();
502 const auto depth = RCSResourceAttributes::Type::getDepth(type);
504 EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
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);
517 inline RCSResourceAttributes::TypeId toNativeTypeId(JNIEnvWrapper* env, jobject typeIdObj)
519 typedef RCSResourceAttributes::TypeId TypeId;
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;
530 throwRCSException(env, "Failed to convert RCSValue : unknown type id");
531 return TypeId::NULL_T;
534 jobject getTypeIdObj(JNIEnvWrapper* env, const char* name)
536 return env->NewGlobalRef(
537 env->GetStaticObjectField(g_cls_TypeId, name, AS_SIG(CLS_NAME_VALUE_TYPEID)));
541 void initRCSValue(JNIEnvWrapper* env)
543 g_cls_RCSValue = env->FindClassAsGlobalRef(CLS_NAME_VALUE);
544 g_ctor_RCSValue = env->GetConstructorID(g_cls_RCSValue, "(" AS_SIG(CLS_NAME_OBJECT) ")V");
546 g_method_RCSValue_getType = env->GetMethodID(g_cls_RCSValue, "getType",
547 "()" AS_SIG(CLS_NAME_VALUE_TYPE));
549 g_field_RCSValue_mObject = env->GetFieldID(g_cls_RCSValue, "mObject", AS_SIG(CLS_NAME_OBJECT));
551 g_field_RCSValue_sNullValue = env->GetStaticFieldID(g_cls_RCSValue, "sNullValue",
552 AS_SIG(CLS_NAME_VALUE_NULL_TYPE));
554 g_cls_Type = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPE);
556 g_smethod_Type_getBaseTypeId = env->GetStaticMethodID(g_cls_Type, "getBaseTypeId",
557 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")" AS_SIG(CLS_NAME_VALUE_TYPEID));
559 g_smethod_Type_getDepth = env->GetStaticMethodID(g_cls_Type, "getDepth",
560 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")I");
562 g_cls_TypeId = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPEID);
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");
574 void clearRCSValue(JNIEnvWrapper* env)
576 env->DeleteGlobalRef(g_cls_RCSValue);
577 env->DeleteGlobalRef(g_cls_Type);
578 env->DeleteGlobalRef(g_cls_TypeId);
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);
590 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnv* env, jobject valueObj)
592 JNIEnvWrapper envWrapper(env);
596 return toNativeAttrsValue(&envWrapper, valueObj);
598 catch (const JavaException&)
604 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnvWrapper* env, jobject valueObj)
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);
611 auto ret = toNativeValue(env, memObj, depth, toNativeTypeId(env, typeIdObj));
613 if (env->get()->ExceptionCheck()) throw JavaException();
618 jobject newRCSValueObject(JNIEnv* env, const RCSResourceAttributes::Value& value)
620 JNIEnvWrapper envWrapper(env);
624 return newRCSValueObject(&envWrapper, value);
626 catch (const JavaException&)
632 jobject newRCSValueObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
634 LOGD("newRCSValueObject");
636 JavaLocalObject valueObj{ env, createJavaObject(env, value) };
638 if (env->get()->ExceptionCheck()) throw JavaException();
640 return env->NewObject(g_cls_RCSValue, g_ctor_RCSValue, valueObj.get());