Skip to content

Commit acbd452

Browse files
tonygermanorPraml
andcommitted
Fix primitive arrays + refactor
Incorporated suggestions from #875 Co-authored-by: Roland Praml <roland.praml@foconis.de>
1 parent e9e8582 commit acbd452

File tree

2 files changed

+38
-28
lines changed

2 files changed

+38
-28
lines changed

src/org/mozilla/javascript/NativeJSON.java

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package org.mozilla.javascript;
88

9+
import java.lang.reflect.Array;
910
import java.util.Arrays;
1011
import java.util.Collection;
1112
import java.util.Iterator;
@@ -297,9 +298,12 @@ private static Object str(Object key, Scriptable holder, StringifyState state) {
297298
value = ((NativeBoolean) value).getDefaultValue(ScriptRuntime.BooleanClass);
298299
} else if (value instanceof NativeJavaObject) {
299300
unwrappedJavaValue = ((NativeJavaObject) value).unwrap();
300-
if (!isComplexJavaObject(unwrappedJavaValue)) {
301+
if (!(unwrappedJavaValue instanceof Map
302+
|| unwrappedJavaValue instanceof Collection
303+
|| unwrappedJavaValue.getClass().isArray())) {
301304
value = unwrappedJavaValue;
302305
} else {
306+
// Don't unwrap Java objects to be processed by jo() or ja()
303307
unwrappedJavaValue = null;
304308
}
305309
} else if (value instanceof XMLObject) {
@@ -351,22 +355,18 @@ private static String join(Collection<Object> objs, String delimiter) {
351355
}
352356

353357
private static String jo(Scriptable value, StringifyState state) {
354-
Object trackValue = value;
355-
final boolean isTrackValueUnwrapped;
358+
Object trackValue = value, unwrapped = null;
356359
if (value instanceof Wrapper) {
357-
trackValue = ((Wrapper) value).unwrap();
358-
isTrackValueUnwrapped = true;
359-
} else {
360-
isTrackValueUnwrapped = false;
360+
trackValue = unwrapped = ((Wrapper) value).unwrap();
361361
}
362362

363363
if (state.stack.search(trackValue) != -1) {
364364
throw ScriptRuntime.typeErrorById("msg.cyclic.value", trackValue.getClass().getName());
365365
}
366366
state.stack.push(trackValue);
367367

368-
if (isTrackValueUnwrapped && (trackValue instanceof Map)) {
369-
Map<?, ?> map = (Map<?, ?>) trackValue;
368+
if (unwrapped instanceof Map) {
369+
Map<?, ?> map = (Map<?, ?>) unwrapped;
370370
Scriptable nObj = state.cx.newObject(state.scope);
371371
for (Map.Entry<?, ?> entry : map.entrySet()) {
372372
if (entry.getKey() instanceof Symbol) continue;
@@ -437,9 +437,9 @@ private static String jo(Scriptable value, StringifyState state) {
437437
}
438438

439439
private static String ja(Scriptable value, StringifyState state) {
440-
Object trackValue = value;
440+
Object trackValue = value, unwrapped = null;
441441
if (value instanceof Wrapper) {
442-
trackValue = ((Wrapper) value).unwrap();
442+
trackValue = unwrapped = ((Wrapper) value).unwrap();
443443
}
444444
if (state.stack.search(trackValue) != -1) {
445445
throw ScriptRuntime.typeErrorById("msg.cyclic.value", trackValue.getClass().getName());
@@ -450,17 +450,25 @@ private static String ja(Scriptable value, StringifyState state) {
450450
state.indent = state.indent + state.gap;
451451
List<Object> partial = new LinkedList<Object>();
452452

453-
if (trackValue instanceof Collection) {
454-
Collection<?> col = (Collection<?>) trackValue;
455-
trackValue = col.toArray(new Object[col.size()]);
456-
}
457-
if (trackValue instanceof Object[]) {
458-
Object[] elements = (Object[]) trackValue;
459-
elements =
460-
Arrays.stream(elements)
461-
.map(o -> Context.javaToJS(o, state.scope, state.cx))
462-
.toArray();
463-
value = state.cx.newArray(state.scope, elements);
453+
if (unwrapped != null) {
454+
Object[] elements = null;
455+
if (unwrapped.getClass().isArray()) {
456+
int length = Array.getLength(unwrapped);
457+
elements = new Object[length];
458+
for (int i = 0; i < length; i++) {
459+
elements[i] = Context.javaToJS(Array.get(unwrapped, i), state.scope, state.cx);
460+
}
461+
} else if (unwrapped instanceof Collection) {
462+
Collection<?> collection = (Collection<?>) unwrapped;
463+
elements = new Object[collection.size()];
464+
int i = 0;
465+
for (Object o : collection) {
466+
elements[i++] = Context.javaToJS(o, state.scope, state.cx);
467+
}
468+
}
469+
if (elements != null) {
470+
value = state.cx.newArray(state.scope, elements);
471+
}
464472
}
465473

466474
long len = ((NativeArray) value).getLength();
@@ -548,17 +556,13 @@ private static Object javaToJSON(Object value, StringifyState state) {
548556
return stringify(state.cx, state.scope, value, state.replacer, state.gap);
549557
}
550558

551-
private static boolean isComplexJavaObject(Object o) {
552-
return (o instanceof Map) || (o instanceof Collection) || (o instanceof Object[]);
553-
}
554-
555559
private static boolean isObjectArrayLike(Object o) {
556560
if (o instanceof NativeArray) {
557561
return true;
558562
}
559563
if (o instanceof NativeJavaObject) {
560-
o = ((NativeJavaObject) o).unwrap();
561-
return (o instanceof Collection) || (o instanceof Object[]);
564+
Object unwrapped = ((NativeJavaObject) o).unwrap();
565+
return (unwrapped instanceof Collection) || (unwrapped.getClass().isArray());
562566
}
563567
return false;
564568
}

testsrc/jstests/stringify-java-objects.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,12 @@ list1.add(map2);
179179
map1.put('list2', list2);
180180
assertThrows(()=>JSON.stringify(map1), TypeError);
181181

182+
// primitive java arrays
183+
var obj = new java.util.HashMap({bytes: new java.lang.String('abc').getBytes('UTF-8')});
184+
var expected = JSON.stringify({bytes: [97, 98, 99]});
185+
var actual = JSON.stringify(obj);
186+
assertEquals(expected, actual);
187+
182188
// alternative converters
183189
var cx = org.mozilla.javascript.Context.getCurrentContext();
184190
var obj = {

0 commit comments

Comments
 (0)