Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8141386

Unable to pass values to java functions which takes wrapper objects as arguments

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 9
    • 8u51
    • javafx
    • web
    • x86_64
    • linux

        FULL PRODUCT VERSION :
        java version "1.8.0_65"
        Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
        Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)


        ADDITIONAL OS VERSION INFORMATION :
        Linux linux-hj5y 3.11.10-29-desktop #1 SMP PREEMPT Thu Mar 5 16:24:00 UTC 2015 (338c513) x86_64 x86_64 x86_64 GNU/Linux

        A DESCRIPTION OF THE PROBLEM :
        I'm writing a connector for a solution written in JavaScript with a library written in Java. Several methods of this library are invoked from JavaScript scripts.
        When I invoke methods that have arguments java.lang.Double type, the argument values ​​are being converted to null.
        If these methods use double native types as arguments , it works perfectly.

        I made a simple class to exemplify:


        public class SimpleJavaObject {

            private Double doubleAttribute = null;
            
            private final StringBuilder sbDebugText = new StringBuilder();

            public SimpleJavaObject() {

            }
            
            public void setDoubleAttribute(Double doubleAttributeArgument) {
                debug("Double setter: "+doubleAttributeArgument);
                doubleAttribute = doubleAttributeArgument;
            }

        // public void setDoubleAttribute(double doubleAttributeArgument) {
        // debug("double setter: "+doubleAttributeArgument);
        // doubleAttribute = doubleAttributeArgument;
        // }

        // public void setDoubleAttribute(Object doubleAttributeArgument) {
        // debug("Object setter: "+doubleAttributeArgument);
        // doubleAttribute = (Double) doubleAttributeArgument;
        // }

        // public void setDoubleAttribute(String doubleAttributeArgument) {
        // debug("String setter: "+doubleAttributeArgument);
        // doubleAttribute = Double.valueOf(doubleAttributeArgument);
        // }

            public Double getDoubleAttribute() {
                return doubleAttribute;
            }
            
            private void debug(String str) {
                sbDebugText.append(str);
                sbDebugText.append("\n");
            }
            
            public String getDebugText() {
                return sbDebugText.toString();
            }

        }

        And a simple html page with one simple script:


        <!DOCTYPE html>
        <html>
            <head>
                <title>WebView tests</title>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <script type="text/javascript">
                    
                    var simpleJavaObject = null; // setted from outside like jsWindow.setMember("simpleJavaObject", new SimpleJavaObject());
                    function test() {
                        alert("simpleJavaObject: " + simpleJavaObject); // shows - simpleJavaObject: webviewtests.SimpleJavaObject@8abb96e

                        simpleJavaObject.setDoubleAttribute(15.5); // try to change the attribute value

                        alert("simpleJavaObject.getDoubleAttribute(): " + simpleJavaObject.getDoubleAttribute()); // shows - simpleJavaObject.getDoubleAttribute(): null

                        alert("Test summary:\n"+simpleJavaObject.getDebugText()); // Shows - Test summary:
                                                                                  // Double setter: null
                                                                                  // indicating the setter invoked
                    }

                </script>
            </head>
            <body>
                
            </body>
        </html>


        As I uncomment the overloaded setters (keeping commented the method with native double argument) I have the following precedence:

         - setDoubleAttribute(Object doubleAttributeArgument)
         - setDoubleAttribute(String doubleAttributeArgument)
         - setDoubleAttribute(Double doubleAttributeArgument) - with doubleAttributeArgument = null

        The question is: Why this method only works with native double, String and Object, and not work with java.lang.Double?

        Many thanks in advance for your attention.


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Call any method with java.lang.Double or java.lang.Integer argument from html page using javascript inside a webview component.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        Show the message with 15.5 value.
        ACTUAL -
        Show the message with null value.

        REPRODUCIBILITY :
        This bug can be reproduced always.

        ---------- BEGIN SOURCE ----------
        // Create all classes and resources in the same package named webviewtests in a simple JavaFX project

        // Main class WebViewTests.java


        package webviewtests;

        import javafx.application.Application;
        import javafx.fxml.FXMLLoader;
        import javafx.scene.Parent;
        import javafx.scene.Scene;
        import javafx.stage.Stage;

        /**
         *
         * @author Marcos Martinewski Alves
         */
        public class WebViewTests extends Application {
            
            @Override
            public void start(Stage stage) throws Exception {
                Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
                
                Scene scene = new Scene(root);
                
                stage.setMaximized(true);
                stage.setScene(scene);
                stage.show();
            }

            /**
             * @param args the command line arguments
             */
            public static void main(String[] args) {
                launch(args);
            }
            
        }

        // FXMLDocument.xml

        <?xml version="1.0" encoding="UTF-8"?>

        <?import java.lang.*?>
        <?import java.util.*?>
        <?import javafx.scene.*?>
        <?import javafx.scene.control.*?>
        <?import javafx.scene.layout.*?>

        <StackPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="webviewtests.FXMLDocumentController">
            <javafx.scene.web.WebView fx:id="webview"/>
        </StackPane>

        // FXMLDocumentController.java

        package webviewtests;

        import java.net.URL;
        import java.util.ResourceBundle;
        import javafx.beans.value.ObservableValue;
        import javafx.concurrent.Worker;
        import javafx.fxml.FXML;
        import javafx.fxml.Initializable;
        import javafx.scene.web.WebErrorEvent;
        import javafx.scene.web.WebEvent;
        import javafx.scene.web.WebView;
        import javax.swing.JOptionPane;
        import netscape.javascript.JSObject;

        /**
         *
         * @author Marcos Martinewski Alves
         */
        public class FXMLDocumentController implements Initializable {

            @FXML
            private WebView webview;

            @Override
            public void initialize(URL url, ResourceBundle rb) {
                initializeWebView();
                loadTestPage();
            }

            private void initializeWebView() {
                webview.getEngine().setOnAlert((WebEvent<String> event) -> {
                    JOptionPane.showMessageDialog(null, event.getData());
                });
                webview.getEngine().setOnError((WebErrorEvent event) -> {
                    event.getException().printStackTrace(System.err);
                });
                webview.getEngine().getLoadWorker().stateProperty().addListener((ObservableValue<? extends Worker.State> observable, Worker.State oldValue, Worker.State newValue) -> {
                    if (Worker.State.SUCCEEDED.equals(newValue)) {
                        initSimpleJavaObject();
                    }
                });
            }

            private void loadTestPage() {
                webview.getEngine().load(getClass().getResource("test.html").toExternalForm());
            }

            private void initSimpleJavaObject() {
                SimpleJavaObject simpleJavaObject = new SimpleJavaObject();
                JSObject jsWindow = (JSObject) webview.getEngine().executeScript("window");
                jsWindow.setMember("simpleJavaObject", simpleJavaObject);
                webview.getEngine().executeScript("test();");
            }

        }

        // SimpleJavaObject.java

        package webviewtests;

        /**
         *
         * @author Marcos Martinewski Alves
         */
        public class SimpleJavaObject {

            private Double doubleAttribute = null;
            
            private final StringBuilder sbDebugText = new StringBuilder();

            public SimpleJavaObject() {

            }
            
            public void setDoubleAttribute(Double doubleAttributeArgument) {
                debug("Double setter: "+doubleAttributeArgument);
                doubleAttribute = doubleAttributeArgument;
            }

        // public void setDoubleAttribute(double doubleAttributeArgument) {
        // debug("double setter: "+doubleAttributeArgument);
        // doubleAttribute = doubleAttributeArgument;
        // }

        // public void setDoubleAttribute(Object doubleAttributeArgument) {
        // debug("Object setter: "+doubleAttributeArgument);
        // doubleAttribute = (Double) doubleAttributeArgument;
        // }

        // public void setDoubleAttribute(String doubleAttributeArgument) {
        // debug("String setter: "+doubleAttributeArgument);
        // doubleAttribute = Double.valueOf(doubleAttributeArgument);
        // }

            public Double getDoubleAttribute() {
                return doubleAttribute;
            }
            
            private void debug(String str) {
                sbDebugText.append(str);
                sbDebugText.append("\n");
            }
            
            public String getDebugText() {
                return sbDebugText.toString();
            }

        }

        // test.html

        <!DOCTYPE html>
        <html>
            <head>
                <title>WebView tests</title>
                <meta charset="UTF-8">
                <meta name="viewport" content="width=device-width, initial-scale=1.0">
                <script type="text/javascript">
                    var simpleJavaObject = null;
                    function test() {
                        alert("simpleJavaObject: " + simpleJavaObject);
                        simpleJavaObject.setDoubleAttribute(15.5);
                        alert("simpleJavaObject.getDoubleAttribute(): " + simpleJavaObject.getDoubleAttribute());
                        alert("Test summary:\n"+simpleJavaObject.getDebugText());
                    }
                </script>
            </head>
            <body>
                
            </body>
        </html>



        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        There is a one workaround, reimplementing all methods that use java.lang.Double as arguments, to use native double, but this may imply in some alterations of expected behaviour of the app.

              arajkumar Arunprasad Rajkumar
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

                Created:
                Updated:
                Resolved: