FULL PRODUCT VERSION : java version "1.9.0-ea" Java(TM) SE Runtime Environment (build 1.9.0-ea-b13) Java HotSpot(TM) 64-Bit Server VM (build 1.9.0-ea-b13, mixed mode) java version "1.8.0_20-ea" Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.20-b10, mixed mode) java version "1.8.0_20-ea" Java(TM) SE Runtime Environment (build 1.8.0_20-ea-b15) Java HotSpot(TM) 64-Bit Server VM (build 25.20-b15, mixed mode) ADDITIONAL OS VERSION INFORMATION : Microsoft Windows [Version 6.1.7601] A DESCRIPTION OF THE PROBLEM : A small conversion script of mine is failing to correctly handle script objects after they have been transferred to a different Global. The immediate cause of this is the fact that access to undefined properties / functions does not return "undefined" as they should, instead returning null when the conversion script is run against the object in the second Global. This incorrectly triggers a conditional block in the conversion script that is designed to handle String-like values. This issue manifests itself in a very peculiar constellation for which the causality escapes my understanding. - a prior execution (in an unrelated Global) has to include an instance of a Map as the value of a property of the script object to be converted - the conversion script has to contain a conditional block that handles conversion of native JavaScript objects into Map instances If either of these parameters is altered (e.g. the Map instance in the prior execution replace by a simple Object) the issue does not occur. The test case works correctly when run in JDK 1.8.0_05 REGRESSION. Last worked in version 8 ADDITIONAL REGRESSION INFORMATION: java version "1.8.0_05" Java(TM) SE Runtime Environment (build 1.8.0_05-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.5-b02, mixed mode) STEPS TO FOLLOW TO REPRODUCE THE PROBLEM : Execute the test case with assertions enabled (-ea) EXPECTED VERSUS ACTUAL BEHAVIOR : EXPECTED - The program completes without failing any of the assertions. ACTUAL - The pogram fails the second to last of the assertion. The result of the conversion is an instance of java.lang.String instead of the expected java.util.Map ERROR MESSAGES/STACK TRACES THAT OCCUR : Exception in thread "main" java.lang.AssertionError at Test2.main(Test2.java:52) REPRODUCIBILITY : This bug can be reproduced always. ---------- BEGIN SOURCE ---------- import java.util.Collections; import java.util.Map; import javax.script.Bindings; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; public class Test2 { private static final String TEST_SCRIPT = "function convert(o) {" + "var b = o, c, d, e, f, g;" + // test for native or Java String "if (typeof o === 'string' || o.toUpperCase!== undefined) {" + "c = Java.type('java.lang.String');" + "b = new c(o);" + "} else if (typeof o === 'object') {" + "c = Java.type('java.util.HashMap');" + "b = new c();" + "for (d in o) { b.put(convert(d), convert(o[d])); }" + "} return b; }" + "javaObj = convert(nashornObj);"; public static void main(final String[] args) throws Exception { final ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn"); // construct object with reference to a Java Map (this somehow triggers the assert to fail in the end) // Note: replacing map with Object => everything works fine again final Bindings globalBindings = engine.createBindings(); globalBindings.put("map", Collections.<String, Object> emptyMap()); engine.eval("nashornObj = { test: map };", globalBindings); engine.eval(TEST_SCRIPT, globalBindings); assert !(globalBindings.get("javaObj") instanceof String); assert globalBindings.get("javaObj") instanceof Map<?, ?>; // construct object in new Global final Bindings originalBindings = engine.createBindings(); engine.eval("nashornObj = { test: 12 }", originalBindings); // show that it works in original Global engine.eval(TEST_SCRIPT, originalBindings); assert !(originalBindings.get("javaObj") instanceof String); assert originalBindings.get("javaObj") instanceof Map<?, ?>; // transfer to a different Global final Bindings secondaryBindings = engine.createBindings(); secondaryBindings.put("nashornObj", originalBindings.get("nashornObj")); // it should also work in different Global, but doesn't engine.eval(TEST_SCRIPT, secondaryBindings); assert !(secondaryBindings.get("javaObj") instanceof String); assert secondaryBindings.get("javaObj") instanceof Map<?, ?>; } } ---------- END SOURCE ---------- CUSTOMER SUBMITTED WORKAROUND : The primary workaround for the test case is to always combine checks against undefined with checks against null, even though null is 100 % certain to either undefined or a function reference.
|