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 "JNIEnvWrapper.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_Attributes;
60 jobject g_obj_TypeId_Array;
65 template< int DEPTH, typename BASE_TYPE >
68 typedef std::vector< typename SeqType< DEPTH - 1, BASE_TYPE >::type > type;
71 template< typename BASE_TYPE >
72 struct SeqType< 0, BASE_TYPE >
74 typedef BASE_TYPE type;
77 template< typename T >
83 template< typename T >
84 struct BaseType< std::vector< T > >
86 typedef typename BaseType< T >::type type;
93 static constexpr char str[] = "";
96 constexpr char ArrayPrefix< D >::str[];
99 struct ArrayPrefix< 1 >
101 static constexpr char str[] = "[";
103 constexpr char ArrayPrefix< 1 >::str[];
106 struct ArrayPrefix< 2 >
108 static constexpr char str[] = "[[";
110 constexpr char ArrayPrefix< 2 >::str[];
112 struct PrimitiveType {
113 static constexpr bool isPrimitive = true;
117 static constexpr bool isPrimitive = false;
120 template< typename T >
124 struct JniTypeTrait< int >: public PrimitiveType
126 static_assert(sizeof(int) == sizeof(jint), "int and jint have different size!");
128 static constexpr decltype(&JNIEnvWrapper::NewIntArray) newArrayFunc =
129 &JNIEnvWrapper::NewIntArray;
130 static constexpr decltype(&JNIEnvWrapper::SetIntArrayRegion) setArrayRegionFunc =
131 &JNIEnvWrapper::SetIntArrayRegion;
133 static constexpr decltype(&invoke_Integer_intValue<JNIEnvWrapper>) converter =
134 &invoke_Integer_intValue<JNIEnvWrapper>;
136 static constexpr decltype(&newIntegerObject<JNIEnvWrapper>) newObjectFunc =
137 &newIntegerObject<JNIEnvWrapper>;
139 static constexpr char className[] = "I";
141 constexpr char JniTypeTrait< int >::className[];
144 struct JniTypeTrait< bool >: public PrimitiveType
146 static_assert(sizeof(bool) == sizeof(jboolean), "bool and jboolean have different size!");
148 static constexpr decltype(&JNIEnvWrapper::NewBooleanArray) newArrayFunc =
149 &JNIEnvWrapper::NewBooleanArray;
150 static constexpr decltype(&JNIEnvWrapper::SetBooleanArrayRegion) setArrayRegionFunc =
151 &JNIEnvWrapper::SetBooleanArrayRegion;
153 static constexpr decltype(&invoke_Boolean_booleanValue<JNIEnvWrapper>) converter =
154 &invoke_Boolean_booleanValue<JNIEnvWrapper>;
156 static constexpr decltype(&newBooleanObject<JNIEnvWrapper>) newObjectFunc =
157 &newBooleanObject<JNIEnvWrapper>;
159 static constexpr char className[] = "Z";
161 constexpr char JniTypeTrait< bool >::className[];
164 struct JniTypeTrait< double > : public PrimitiveType
166 static_assert(sizeof(double) == sizeof(jdouble), "double and jdouble have different size!");
168 static constexpr decltype(&JNIEnvWrapper::NewDoubleArray) newArrayFunc =
169 &JNIEnvWrapper::NewDoubleArray;
170 static constexpr decltype(&JNIEnvWrapper::SetDoubleArrayRegion) setArrayRegionFunc =
171 &JNIEnvWrapper::SetDoubleArrayRegion;
173 static constexpr decltype(&invoke_Double_doubleValue<JNIEnvWrapper>) converter =
174 &invoke_Double_doubleValue<JNIEnvWrapper>;
176 static constexpr decltype(&newDoubleObject<JNIEnvWrapper>) newObjectFunc =
177 &newDoubleObject<JNIEnvWrapper>;
179 static constexpr char className[] = "D";
181 constexpr char JniTypeTrait< double >::className[];
184 struct JniTypeTrait< std::string >: public ObjectType
186 static constexpr decltype(&newStringObject<JNIEnvWrapper>) newObjectFunc =
187 &newStringObject<JNIEnvWrapper>;
189 static constexpr char className[] = "L" CLS_NAME_STRING ";";
191 constexpr char JniTypeTrait< std::string >::className[];
194 struct JniTypeTrait< RCSResourceAttributes >: public ObjectType
196 inline static jobject newObjectFunc(JNIEnvWrapper* env, const RCSResourceAttributes& value)
198 return newAttributesObject(env, value);
201 inline static RCSResourceAttributes converter(JNIEnvWrapper* env, jobject obj)
203 return toNativeAttributes(env, obj);
206 static constexpr char className[] = "L" CLS_NAME_RESOURCEATTRIBUTES ";";
208 constexpr char JniTypeTrait< RCSResourceAttributes >::className[];
210 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, std::string& result, Int2Type< 0 >)
212 result = toStdString(env, static_cast< jstring >(obj));
215 template< typename T >
216 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, T& result, Int2Type< 0 >)
218 result = JniTypeTrait< T >::converter(env, obj);
221 template< int DEPTH, typename RET >
222 inline void toNativeValue(JNIEnvWrapper* env, jobject obj, RET& result, Int2Type< DEPTH >)
224 const auto arrayObj = static_cast< jobjectArray >(obj);
225 result.resize(env->GetArrayLength(arrayObj));
227 for (typename RET::size_type i = 0; i < result.size(); ++i)
229 JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
231 toNativeValue(env, elementObj, result[i], Int2Type< DEPTH - 1 >{ });
235 template< typename T >
236 inline typename std::enable_if< JniTypeTrait< T >::isPrimitive >::type
237 toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
239 const auto arrayObj = static_cast< jobjectArray >(obj);
240 const jsize arraySize = env->GetArrayLength(arrayObj);
242 T* raw = static_cast< T* >(env->GetPrimitiveArrayCritical(arrayObj, nullptr));
246 result = std::vector< T >(raw, raw + arraySize);
251 env->ReleasePrimitiveArrayCritical(arrayObj, raw, JNI_ABORT);
254 template< typename T >
255 inline typename std::enable_if< !JniTypeTrait< T >::isPrimitive >::type
256 toNativeValue(JNIEnvWrapper* env, jobject obj, std::vector< T >& result, Int2Type< 1 >)
258 const auto arrayObj = static_cast< jobjectArray >(obj);
259 const jsize arraySize = env->GetArrayLength(arrayObj);
261 result.resize(arraySize);
263 for (typename std::vector< T >::size_type i = 0; i < result.size(); ++i)
265 JavaLocalObject elementObj{ env, env->GetObjectArrayElement(arrayObj, i) };
266 toNativeValue(env, elementObj, result[i], Int2Type< 0 >{ });
271 template< typename T, int DEPTH, typename RET = typename SeqType< DEPTH, T >::type >
272 inline RET toNativeValue(JNIEnvWrapper* env, jobject obj)
274 static_assert(DEPTH >= 0, "DEPTH must be positive!");
276 typename SeqType< DEPTH, T >::type result;
278 toNativeValue(env, obj, result, Int2Type< DEPTH >{ });
283 template< typename T >
284 inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth)
288 case 0: return toNativeValue< T, 0 >(env, val);
289 case 1: return toNativeValue< T, 1 >(env, val);
290 case 2: return toNativeValue< T, 2 >(env, val);
291 case 3: return toNativeValue< T, 3 >(env, val);
297 inline RCSResourceAttributes::Value toNativeValue(JNIEnvWrapper* env, jobject val, int depth,
298 RCSResourceAttributes::TypeId typeId)
300 LOGD("toNativeValue depth is %d", depth);
301 EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
305 case RCSResourceAttributes::TypeId::NULL_T: return { };
307 case RCSResourceAttributes::TypeId::BOOL:
308 return toNativeValue< bool >(env, val, depth);
310 case RCSResourceAttributes::TypeId::INT:
311 return toNativeValue< int >(env, val, depth);
313 case RCSResourceAttributes::TypeId::DOUBLE:
314 return toNativeValue< double >(env, val, depth);
316 case RCSResourceAttributes::TypeId::STRING:
317 return toNativeValue< std::string >(env, val, depth);
319 case RCSResourceAttributes::TypeId::ATTRIBUTES:
320 return toNativeValue< RCSResourceAttributes >(env, val, depth);
323 throwRCSException(env, "Failed to convert RCSValue : unknown type id");
327 template< typename T, int DEPTH, typename BASE_TYPE = typename BaseType< T >::type >
328 inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< DEPTH >)
330 const std::string elementClsName{ std::string{ ArrayPrefix< DEPTH - 1 >::str }
331 + JniTypeTrait< BASE_TYPE >::className };
333 LOGD("create array %dd, %s", DEPTH, elementClsName.c_str());
335 auto cls = env->FindClass(elementClsName.c_str());
337 const jsize len = value.size();
339 auto array = env->NewObjectArray(len, cls, nullptr);
341 for(jsize i = 0; i < len; ++i)
343 auto element = createJavaObject(env, value[i], Int2Type< DEPTH - 1>{ });
344 env->SetObjectArrayElement(array, i, element);
350 template< typename T, typename TRAIT = JniTypeTrait< T > >
351 inline typename std::enable_if< TRAIT::isPrimitive, jobject >::type
352 createJavaObject(JNIEnvWrapper* env, const std::vector< T >& value, Int2Type< 1 >)
354 LOGD("create array with newArray");
355 const jsize len = value.size();
357 auto array = (env->*TRAIT::newArrayFunc)(len);
359 if (!value.empty()) (env->*TRAIT::setArrayRegionFunc)(array, 0, len, &value[0]);
364 inline jobject createJavaObject(JNIEnvWrapper* env, const std::vector< bool >& value, Int2Type< 1 >)
366 const auto len = value.size();
367 LOGD("create bool array with newArray %d", len);
369 auto arrayObj = env->NewBooleanArray(len);
371 bool* raw = static_cast< bool* >(env->GetPrimitiveArrayCritical(arrayObj, 0));
373 std::copy(value.begin(), value.end(), raw);
375 env->ReleasePrimitiveArrayCritical(arrayObj, raw, 0);
380 template< typename T, typename TRAIT = JniTypeTrait< T > >
381 inline jobject createJavaObject(JNIEnvWrapper* env, const T& value, Int2Type< 0 >)
383 LOGD("createJavaObject 0-depth");
384 return TRAIT::newObjectFunc(env, value);
387 template< int DEPTH >
388 inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
390 const auto type = value.getType();
391 const auto baseType = RCSResourceAttributes::Type::getBaseTypeId(type);
393 LOGD("createJavaObject with DEPTH. type is %d", static_cast< int >(baseType));
397 case RCSResourceAttributes::TypeId::NULL_T:
398 return env->GetStaticObjectField(g_cls_RCSValue, g_field_RCSValue_sNullValue);
400 case RCSResourceAttributes::TypeId::BOOL:
401 return createJavaObject(env, value.get< typename SeqType< DEPTH, bool >::type >(),
402 Int2Type< DEPTH >{ });
404 case RCSResourceAttributes::TypeId::INT:
405 return createJavaObject(env, value.get< typename SeqType< DEPTH, int >::type >(),
406 Int2Type< DEPTH >{ });
408 case RCSResourceAttributes::TypeId::DOUBLE:
409 return createJavaObject(env, value.get< typename SeqType< DEPTH, double >::type >(),
410 Int2Type< DEPTH >{ });
412 case RCSResourceAttributes::TypeId::STRING:
413 return createJavaObject(env,
414 value.get< typename SeqType< DEPTH, std::string >::type >(),
415 Int2Type< DEPTH >{ });
417 case RCSResourceAttributes::TypeId::ATTRIBUTES:
418 return createJavaObject(env,
419 value.get< typename SeqType< DEPTH, RCSResourceAttributes >::type >(),
420 Int2Type< DEPTH >{ });
423 LOGE("Unknown type!");
428 inline jobject createJavaObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
430 const auto type = value.getType();
431 const auto depth = RCSResourceAttributes::Type::getDepth(type);
433 EXPECT_RET(depth >= 0 && depth <= 3, "Unsupported depth!", {});
437 case 0: return createJavaObject< 0 >(env, value);
438 case 1: return createJavaObject< 1 >(env, value);
439 case 2: return createJavaObject< 2 >(env, value);
440 case 3: return createJavaObject< 3 >(env, value);
446 inline RCSResourceAttributes::TypeId toNativeTypeId(JNIEnvWrapper* env, jobject typeIdObj)
448 typedef RCSResourceAttributes::TypeId TypeId;
450 if (env->IsSameObject(g_obj_TypeId_Null, typeIdObj)) return TypeId::NULL_T;
451 if (env->IsSameObject(g_obj_TypeId_Boolean, typeIdObj)) return TypeId::BOOL;
452 if (env->IsSameObject(g_obj_TypeId_Integer, typeIdObj)) return TypeId::INT;
453 if (env->IsSameObject(g_obj_TypeId_Double, typeIdObj)) return TypeId::DOUBLE;
454 if (env->IsSameObject(g_obj_TypeId_String, typeIdObj)) return TypeId::STRING;
455 if (env->IsSameObject(g_obj_TypeId_Attributes, typeIdObj)) return TypeId::ATTRIBUTES;
456 if (env->IsSameObject(g_obj_TypeId_Array, typeIdObj)) return TypeId::VECTOR;
458 throwRCSException(env, "Failed to convert RCSValue : unknown type id");
459 return TypeId::NULL_T;
462 jobject getTypeIdObj(JNIEnvWrapper* env, const char* name)
464 return env->NewGlobalRef(
465 env->GetStaticObjectField(g_cls_TypeId, name, AS_SIG(CLS_NAME_VALUE_TYPEID)));
469 void initRCSValue(JNIEnvWrapper* env)
471 g_cls_RCSValue = env->FindClassAsGlobalRef(CLS_NAME_VALUE);
472 g_ctor_RCSValue = env->GetConstructorID(g_cls_RCSValue, "(" AS_SIG(CLS_NAME_OBJECT) ")V");
474 g_method_RCSValue_getType = env->GetMethodID(g_cls_RCSValue, "getType",
475 "()" AS_SIG(CLS_NAME_VALUE_TYPE));
477 g_field_RCSValue_mObject = env->GetFieldID(g_cls_RCSValue, "mObject", AS_SIG(CLS_NAME_OBJECT));
479 g_field_RCSValue_sNullValue = env->GetStaticFieldID(g_cls_RCSValue, "sNullValue",
480 AS_SIG(CLS_NAME_VALUE_NULL_TYPE));
482 g_cls_Type = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPE);
484 g_smethod_Type_getBaseTypeId = env->GetStaticMethodID(g_cls_Type, "getBaseTypeId",
485 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")" AS_SIG(CLS_NAME_VALUE_TYPEID));
487 g_smethod_Type_getDepth = env->GetStaticMethodID(g_cls_Type, "getDepth",
488 "(" AS_SIG(CLS_NAME_VALUE_TYPE) ")I");
490 g_cls_TypeId = env->FindClassAsGlobalRef(CLS_NAME_VALUE_TYPEID);
492 g_obj_TypeId_Null = getTypeIdObj(env, "NULL");
493 g_obj_TypeId_Boolean = getTypeIdObj(env, "BOOLEAN");
494 g_obj_TypeId_Integer = getTypeIdObj(env, "INTEGER");
495 g_obj_TypeId_Double = getTypeIdObj(env, "DOUBLE");
496 g_obj_TypeId_String = getTypeIdObj(env, "STRING");
497 g_obj_TypeId_Attributes = getTypeIdObj(env, "ATTRIBUTES");
498 g_obj_TypeId_Array = getTypeIdObj(env, "ARRAY");
501 void clearRCSValue(JNIEnvWrapper* env)
503 env->DeleteGlobalRef(g_cls_RCSValue);
504 env->DeleteGlobalRef(g_cls_Type);
505 env->DeleteGlobalRef(g_cls_TypeId);
507 env->DeleteGlobalRef(g_obj_TypeId_Null);
508 env->DeleteGlobalRef(g_obj_TypeId_Boolean);
509 env->DeleteGlobalRef(g_obj_TypeId_Integer);
510 env->DeleteGlobalRef(g_obj_TypeId_Double);
511 env->DeleteGlobalRef(g_obj_TypeId_String);
512 env->DeleteGlobalRef(g_obj_TypeId_Attributes);
513 env->DeleteGlobalRef(g_obj_TypeId_Array);
516 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnv* env, jobject valueObj)
518 JNIEnvWrapper envWrapper(env);
522 return toNativeAttrsValue(&envWrapper, valueObj);
524 catch (const JavaException&)
530 RCSResourceAttributes::Value toNativeAttrsValue(JNIEnvWrapper* env, jobject valueObj)
533 auto typeObj = env->CallObjectMethod(valueObj, g_method_RCSValue_getType);
534 LOGD("Type base type object");
535 auto typeIdObj = env->CallStaticObjectMethod(g_cls_Type, g_smethod_Type_getBaseTypeId, typeObj);
536 LOGD("Type getDepth");
537 auto depth = env->CallStaticIntMethod(g_cls_Type, g_smethod_Type_getDepth, typeObj);
538 LOGD("Type get object field");
539 auto memObj = env->GetObjectField(valueObj, g_field_RCSValue_mObject);
541 LOGD("Type to native value");
542 auto ret = toNativeValue(env, memObj, depth, toNativeTypeId(env, typeIdObj));
544 if (env->get()->ExceptionCheck()) throw JavaException();
549 jobject newRCSValueObject(JNIEnv* env, const RCSResourceAttributes::Value& value)
551 JNIEnvWrapper envWrapper(env);
555 return newRCSValueObject(&envWrapper, value);
557 catch (const JavaException&)
563 jobject newRCSValueObject(JNIEnvWrapper* env, const RCSResourceAttributes::Value& value)
565 LOGD("newRCSValueObject");
567 JavaLocalObject valueObj{ env, createJavaObject(env, value) };
569 if (env->get()->ExceptionCheck()) throw JavaException();
571 return env->NewObject(g_cls_RCSValue, g_ctor_RCSValue, valueObj.get());