-
Bug
-
Resolution: Fixed
-
P3
-
8u92, 9
-
b148
-
x86
-
generic
FULL PRODUCT VERSION :
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.10586]
A DESCRIPTION OF THE PROBLEM :
When calling the native array function "concat", an argument that is an AbstractJSObject array is not treated as an array. Array.concat should use the items of an array argument, but instead it treats the entire AbstractJSObject array as a single item.
However, the documentation for JSObject states that "Nashorn will treat objects of such classes just like nashorn script objects." (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/JSObject.html)
(This kind of behavior applies in other situations as well, Array.concat is just an example.)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
first,red,green,blue
ACTUAL -
first,ArrayLike{items=[red, green, blue]}
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package org.lab;
import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
JSObject array = new ArrayLike(new String[] { "red", "green", "blue" });
bindings.put("theArray", array);
String script = "print(['first'].concat(theArray));";
engine.eval(script, bindings);
}
static class ArrayLike extends AbstractJSObject {
private final String[] items;
ArrayLike(String[] items) {
this.items = items;
}
@Override
public Object getMember(String name) {
if ("length".equals(name)) return items.length;
if ("toString".equals(name)) return ValueAsFunction.forValue(toString());
return null;
}
@Override
public Object getSlot(int index) {
return hasSlot(index) ? items[index] : null;
}
@Override
public boolean hasSlot(int slot) {
return slot >= 0 && slot < items.length;
}
@Override
public boolean isArray() {
return true;
}
@Override
public String toString() {
return "ArrayLike{items=" + Arrays.toString(items) + "}";
}
}
static class ValueAsFunction extends AbstractJSObject {
private final Object value;
ValueAsFunction(Object value) {
this.value = value;
}
@Override
public Object call(Object thiz, Object... args) {
return value;
}
@Override
public boolean isFunction() {
return true;
}
static ValueAsFunction forValue(Object value) {
return new ValueAsFunction(value);
}
}
}
---------- END SOURCE ----------
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.10586]
A DESCRIPTION OF THE PROBLEM :
When calling the native array function "concat", an argument that is an AbstractJSObject array is not treated as an array. Array.concat should use the items of an array argument, but instead it treats the entire AbstractJSObject array as a single item.
However, the documentation for JSObject states that "Nashorn will treat objects of such classes just like nashorn script objects." (https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/JSObject.html)
(This kind of behavior applies in other situations as well, Array.concat is just an example.)
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the attached Java program.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
first,red,green,blue
ACTUAL -
first,ArrayLike{items=[red, green, blue]}
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package org.lab;
import jdk.nashorn.api.scripting.AbstractJSObject;
import jdk.nashorn.api.scripting.JSObject;
import jdk.nashorn.api.scripting.NashornScriptEngineFactory;
import javax.script.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws ScriptException {
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine();
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
JSObject array = new ArrayLike(new String[] { "red", "green", "blue" });
bindings.put("theArray", array);
String script = "print(['first'].concat(theArray));";
engine.eval(script, bindings);
}
static class ArrayLike extends AbstractJSObject {
private final String[] items;
ArrayLike(String[] items) {
this.items = items;
}
@Override
public Object getMember(String name) {
if ("length".equals(name)) return items.length;
if ("toString".equals(name)) return ValueAsFunction.forValue(toString());
return null;
}
@Override
public Object getSlot(int index) {
return hasSlot(index) ? items[index] : null;
}
@Override
public boolean hasSlot(int slot) {
return slot >= 0 && slot < items.length;
}
@Override
public boolean isArray() {
return true;
}
@Override
public String toString() {
return "ArrayLike{items=" + Arrays.toString(items) + "}";
}
}
static class ValueAsFunction extends AbstractJSObject {
private final Object value;
ValueAsFunction(Object value) {
this.value = value;
}
@Override
public Object call(Object thiz, Object... args) {
return value;
}
@Override
public boolean isFunction() {
return true;
}
static ValueAsFunction forValue(Object value) {
return new ValueAsFunction(value);
}
}
}
---------- END SOURCE ----------