Skip to content

Commit 2c9cb2f

Browse files
committed
Infer best Java type for an array
1 parent 7fdd829 commit 2c9cb2f

1 file changed

Lines changed: 64 additions & 1 deletion

File tree

src/utils.cpp

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include <string.h>
33
#include <algorithm>
44
#include <sstream>
5+
#include <set>
56
#include "javaObject.h"
67
#include "java.h"
78

@@ -244,6 +245,67 @@ jobject javaFindField(JNIEnv* env, jclass clazz, std::string& fieldName) {
244245
return result;
245246
}
246247

248+
const std::string kObject("java/lang/Object");
249+
const std::string kString("java/lang/String");
250+
const std::string kInteger("java/lang/Integer");
251+
const std::string kNumber("java/lang/Number");
252+
const std::string kLong("java/lang/Long");
253+
const std::string kDouble("java/lang/Double");
254+
const std::string kBoolean("java/lang/Boolean");
255+
256+
static std::string getArrayElementType(v8::Local<v8::Array> array, uint32_t arraySize) {
257+
std::set<std::string> types;
258+
259+
if (arraySize == 0) {
260+
return kObject;
261+
}
262+
263+
for(uint32_t i=0; i<arraySize; i++) {
264+
v8::Local<v8::Value> arg = array->Get(i);
265+
if (arg->IsArray()) {
266+
return kObject; // We can exit as soon as we know java/lang/Object is required.
267+
}
268+
else if(arg->IsString()) {
269+
types.insert(kString);
270+
}
271+
else if(arg->IsInt32() || arg->IsUint32()) {
272+
types.insert(kInteger);
273+
}
274+
else if(arg->IsNumber()) {
275+
types.insert(kDouble);
276+
}
277+
else if(arg->IsBoolean()) {
278+
types.insert(kBoolean);
279+
}
280+
else if(arg->IsObject()) {
281+
v8::Local<v8::Object> obj = v8::Local<v8::Object>::Cast(arg);
282+
v8::Local<v8::Value> isJavaLong = obj->GetHiddenValue(NanNew<v8::String>(V8_HIDDEN_MARKER_JAVA_LONG));
283+
if(!isJavaLong.IsEmpty() && isJavaLong->IsBoolean()) {
284+
types.insert(kLong);
285+
}
286+
else {
287+
return kObject; // We can exit as soon as we know java/lang/Object is required.
288+
}
289+
}
290+
}
291+
292+
if(types.size() == 1) {
293+
return *(types.begin());
294+
}
295+
296+
assert(types.size() >= 1);
297+
assert(types.find(kObject)==types.end());
298+
299+
// We have an array with two or more types. All types can be converted to Object, but there is one other
300+
// case we support, which is when all the types are numeric types.
301+
// We currently have only two non-numeric types. If neither is present in the set, the rest must be numeric.
302+
if (types.find(kString)==types.end() && types.find(kBoolean)==types.end()) {
303+
return kNumber;
304+
}
305+
306+
return kObject;
307+
}
308+
247309
jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg) {
248310
if(arg.IsEmpty() || arg->IsNull() || arg->IsUndefined()) {
249311
return NULL;
@@ -252,7 +314,8 @@ jobject v8ToJava(JNIEnv* env, v8::Local<v8::Value> arg) {
252314
if(arg->IsArray()) {
253315
v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arg);
254316
uint32_t arraySize = array->Length();
255-
jclass objectClazz = env->FindClass("java/lang/Object");
317+
std::string arrayType = getArrayElementType(array, arraySize);
318+
jclass objectClazz = env->FindClass(arrayType.c_str());
256319
jobjectArray result = env->NewObjectArray(arraySize, objectClazz, NULL);
257320
for(uint32_t i=0; i<arraySize; i++) {
258321
jobject val = v8ToJava(env, array->Get(i));

0 commit comments

Comments
 (0)