Fix erroneous boxing of primitive return values by $entry()
Bug: issue 8548
Change-Id: I99938731ad8db81737a45a1d641bf3bd12ea4e68
(cherry picked from commit 2b54a63ccc1d7f68229fb04ae47abc21bfa205d1)
diff --git a/user/src/com/google/gwt/core/client/impl/Impl.java b/user/src/com/google/gwt/core/client/impl/Impl.java
index f138450..8f605ca 100644
--- a/user/src/com/google/gwt/core/client/impl/Impl.java
+++ b/user/src/com/google/gwt/core/client/impl/Impl.java
@@ -90,7 +90,16 @@
public static native JavaScriptObject entry(JavaScriptObject jsFunction) /*-{
return function() {
try {
- return @com.google.gwt.core.client.impl.Impl::entry0(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(jsFunction, this, arguments);
+ if (@com.google.gwt.core.client.GWT::isScript()()) {
+ return @com.google.gwt.core.client.impl.Impl::entry0(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(jsFunction, this, arguments);
+ } else {
+ var _ = @com.google.gwt.core.client.impl.Impl::entry0(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(jsFunction, this, arguments);
+ if (_ != null) {
+ // Unwraps for Development Mode (see #apply())
+ _ = _.val;
+ }
+ return _;
+ }
} catch (e) {
// This catch block is here to ensure that the finally block in entry0
// will be executed correctly on IE6/7. We can't put a catch Throwable
@@ -291,8 +300,8 @@
} else {
var _ = jsFunction.apply(thisObj, args);
if (_ != null) {
- // Wrap for Development Mode
- _ = Object(_);
+ // Wrap for Development Mode (unwrapped in #entry())
+ _ = { val: _ };
}
return _;
}
diff --git a/user/test/com/google/gwt/core/client/EntryTest.java b/user/test/com/google/gwt/core/client/EntryTest.java
new file mode 100644
index 0000000..6827682
--- /dev/null
+++ b/user/test/com/google/gwt/core/client/EntryTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.core.client;
+
+import com.google.gwt.junit.client.GWTTestCase;
+
+/**
+ * Tests for the $entry() method in JSNI.
+ */
+public class EntryTest extends GWTTestCase {
+
+ @Override
+ public String getModuleName() {
+ return "com.google.gwt.core.Core";
+ }
+
+ /**
+ * Tests that methods with primitive return types correctly return JS values
+ * when wrapped with {@code $entry} (rather than JS objects).
+ * <p>
+ * We test this with a boolean {@code false} that we coerce to a boolean. If the
+ * $entry-wrapped function returns it as a JS Boolean object, it'll coerce to
+ * {@code true} because it's non-null.
+ *
+ * @see <a href="https://code.google.com/p/google-web-toolkit/issues/detail?id=8548">issue 8548</a>
+ */
+ public native void testPrimitiveReturnType() /*-{
+ var assertStringEquals = @junit.framework.Assert::assertEquals(Ljava/lang/String;Ljava/lang/String;);
+ var assertFalse = @junit.framework.Assert::assertFalse(Z);
+ var assertTrue = @junit.framework.Assert::assertTrue(Z);
+
+ var assertIsBooleanValueFalse = function(shouldBeBooleanValueFalse) {
+ assertStringEquals("boolean", typeof shouldBeBooleanValueFalse);
+ assertFalse(!!shouldBeBooleanValueFalse);
+ };
+ var assertIsBooleanObjectFalse = function(shouldBeBooleanObjectFalse) {
+ assertStringEquals("object", typeof shouldBeBooleanObjectFalse);
+ assertTrue(shouldBeBooleanObjectFalse instanceof Boolean);
+ assertFalse(shouldBeBooleanObjectFalse.valueOf());
+ // that was the failing code in issue 8548, so test it explicitly:
+ assertTrue(!!shouldBeBooleanObjectFalse);
+ }
+
+ // Make sure we don't erroneously wrap values
+ var returnsBooleanValueFalse = $entry(function() { return false; });
+ assertIsBooleanValueFalse(returnsBooleanValueFalse());
+ // try if with a Java method returning a Java primitive boolean (issue 8548)
+ var returnsJavaPrimitiveBooleanFalse = $entry(@com.google.gwt.core.client.EntryTest::returnsFalse());
+ assertIsBooleanValueFalse(returnsJavaPrimitiveBooleanFalse());
+
+ // Make sure we don't erroneously unwrap objects
+ var returnsBooleanObjectFalse = $entry(function() { return new Boolean(false); });
+ assertIsBooleanObjectFalse(returnsBooleanObjectFalse());
+
+ // Just to be sure, make sure we round-trip values correctly:
+ var returnsFirstArgument = $entry(function(a) { return a; });
+ assertIsBooleanValueFalse(returnsFirstArgument(false));
+ assertIsBooleanObjectFalse(returnsFirstArgument(new Boolean(false)));
+ }-*/;
+
+ private static boolean returnsFalse() {
+ return false;
+ }
+}