8134939: Improve toString method of Dynalink DynamicMethod objects
authorattila
Wed, 02 Sep 2015 16:35:14 +0200
changeset 32441 8401a09d1b0d
parent 32440 fa99d7177674
child 32442 a29dbbbe10ef
8134939: Improve toString method of Dynalink DynamicMethod objects Reviewed-by: hannesw, sundar
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java
nashorn/test/script/basic/JDK-8043232.js.EXPECTED
nashorn/test/script/basic/JDK-8049242.js.EXPECTED
nashorn/test/script/basic/JDK-8079470.js.EXPECTED
nashorn/test/script/basic/JDK-8134939.js
nashorn/test/script/trusted/classfilter.js.EXPECTED
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/CallerSensitiveDynamicMethod.java	Wed Sep 02 16:35:14 2015 +0200
@@ -107,7 +107,7 @@
     private final AccessibleObject target;
     private final MethodType type;
 
-    public CallerSensitiveDynamicMethod(final AccessibleObject target) {
+    CallerSensitiveDynamicMethod(final AccessibleObject target) {
         super(getName(target));
         this.target = target;
         this.type = getMethodType(target);
@@ -115,8 +115,9 @@
 
     private static String getName(final AccessibleObject target) {
         final Member m = (Member)target;
-        return getMethodNameWithSignature(getMethodType(target), getClassAndMethodName(m.getDeclaringClass(),
-                m.getName()));
+        final boolean constructor = m instanceof Constructor;
+        return getMethodNameWithSignature(getMethodType(target), constructor ? m.getName() :
+            getClassAndMethodName(m.getDeclaringClass(), m.getName()), !constructor);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/OverloadedDynamicMethod.java	Wed Sep 02 16:35:14 2015 +0200
@@ -86,7 +86,9 @@
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
+import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -242,6 +244,35 @@
         return methods.getFirst().isConstructor();
     }
 
+    @Override
+    public String toString() {
+        // First gather the names and sort them. This makes it consistent and easier to read.
+        final List<String> names = new ArrayList<>(methods.size());
+        int len = 0;
+        for (final SingleDynamicMethod m: methods) {
+            final String name = m.getName();
+            len += name.length();
+            names.add(name);
+        }
+        // Case insensitive sorting, so e.g. "Object" doesn't come before "boolean".
+        final Collator collator = Collator.getInstance();
+        collator.setStrength(Collator.SECONDARY);
+        Collections.sort(names, collator);
+
+        final String className = getClass().getName();
+        // Class name length + length of signatures + 2 chars/per signature for indentation and newline +
+        // 3 for brackets and initial newline
+        final int totalLength = className.length() + len + 2 * names.size() + 3;
+        final StringBuilder b = new StringBuilder(totalLength);
+        b.append('[').append(className).append('\n');
+        for(final String name: names) {
+            b.append(' ').append(name).append('\n');
+        }
+        b.append(']');
+        assert b.length() == totalLength;
+        return b.toString();
+    };
+
     ClassLoader getClassLoader() {
         return classLoader;
     }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SimpleDynamicMethod.java	Wed Sep 02 16:35:14 2015 +0200
@@ -122,13 +122,13 @@
      * @param constructor does this represent a constructor?
      */
     SimpleDynamicMethod(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
-        super(getName(target, clazz, name));
+        super(getName(target, clazz, name, constructor));
         this.target = target;
         this.constructor = constructor;
     }
 
-    private static String getName(final MethodHandle target, final Class<?> clazz, final String name) {
-        return getMethodNameWithSignature(target.type(), getClassAndMethodName(clazz, name));
+    private static String getName(final MethodHandle target, final Class<?> clazz, final String name, final boolean constructor) {
+        return getMethodNameWithSignature(target.type(), constructor ? name : getClassAndMethodName(clazz, name), !constructor);
     }
 
     @Override
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/beans/SingleDynamicMethod.java	Wed Sep 02 16:35:14 2015 +0200
@@ -143,14 +143,18 @@
         return getMethodType().parameterList().equals(method.getMethodType().parameterList());
     }
 
-    static String getMethodNameWithSignature(final MethodType type, final String methodName) {
+    static String getMethodNameWithSignature(final MethodType type, final String methodName, final boolean withReturnType) {
         final String typeStr = type.toString();
         final int retTypeIndex = typeStr.lastIndexOf(')') + 1;
         int secondParamIndex = typeStr.indexOf(',') + 1;
         if(secondParamIndex == 0) {
             secondParamIndex = retTypeIndex - 1;
         }
-        return typeStr.substring(retTypeIndex) + " " + methodName + "(" + typeStr.substring(secondParamIndex, retTypeIndex);
+        final StringBuilder b = new StringBuilder();
+        if (withReturnType) {
+            b.append(typeStr, retTypeIndex, typeStr.length()).append(' ');
+        }
+        return b.append(methodName).append('(').append(typeStr, secondParamIndex, retTypeIndex).toString();
     }
 
     /**
--- a/nashorn/test/script/basic/JDK-8043232.js.EXPECTED	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/test/script/basic/JDK-8043232.js.EXPECTED	Wed Sep 02 16:35:14 2015 +0200
@@ -1,14 +1,28 @@
 bcd
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
 red
 TypeError: No such Java class: java.lang.NonExistent
 TypeError: No such Java constructor: Object(String)
 TypeError: Java constructor signature invalid: Object()xxxxx
 TypeError: Java constructor signature invalid: Object(
 TypeError: Java constructor signature invalid: Object)
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.lang.System.getProperty] cannot be used as a constructor.
-TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println] cannot be used as a constructor.
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ String java.lang.System.getProperty(String,String)
+ String java.lang.System.getProperty(String)
+] cannot be used as a constructor.
+TypeError: Java method [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+] cannot be used as a constructor.
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
 TypeError: No such Java constructor: Runnable()
 TypeError: No such Java constructor: Runnable(int)
 java.lang.InstantiationException: java.io.InputStream
--- a/nashorn/test/script/basic/JDK-8049242.js.EXPECTED	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/test/script/basic/JDK-8049242.js.EXPECTED	Wed Sep 02 16:35:14 2015 +0200
@@ -1,10 +1,10 @@
 abc
-[jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)]
+[jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)]
 ava
 TypeError: null is not a function
 TypeError: null is not a function
 TypeError: null is not a function
-TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod String java.lang.String.java.lang.String(char[],int,int)] requires "new".
+TypeError: Constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.lang.String(char[],int,int)] requires "new".
 TypeError: null is not a function
 TypeError: null is not a function
 java.lang.InstantiationException: java.io.InputStream
--- a/nashorn/test/script/basic/JDK-8079470.js.EXPECTED	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/test/script/basic/JDK-8079470.js.EXPECTED	Wed Sep 02 16:35:14 2015 +0200
@@ -1,2 +1,2 @@
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod File java.io.File.java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
-TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod Color java.awt.Color.java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.io.File(String,String)] with the passed arguments; they do not match any of its method signatures.
+TypeError: Can not create new object with constructor [jdk.internal.dynalink.beans.SimpleDynamicMethod java.awt.Color(int,int,int)] with the passed arguments; they do not match any of its method signatures.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8134939.js	Wed Sep 02 16:35:14 2015 +0200
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8134939: Improve toString method of Dynalink OverloadedDynamicMethod
+ *
+ * @test
+ * @run
+ */
+
+var overloadedSetter = new (Java.type("jdk.nashorn.test.models.OverloadedSetter"));
+
+Assert.assertEquals(String(overloadedSetter.foo),
+  "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+  " String jdk.nashorn.test.models.OverloadedSetter.foo(String)\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.foo(int)\n" +
+  "]");
+
+Assert.assertEquals(String(overloadedSetter.setColor),
+  "[jdk.internal.dynalink.beans.OverloadedDynamicMethod\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.setColor(int)\n" +
+  " void jdk.nashorn.test.models.OverloadedSetter.setColor(String)\n" +
+  "]");
--- a/nashorn/test/script/trusted/classfilter.js.EXPECTED	Wed Sep 02 17:16:57 2015 +0530
+++ b/nashorn/test/script/trusted/classfilter.js.EXPECTED	Wed Sep 02 16:35:14 2015 +0200
@@ -4,7 +4,18 @@
 typeof java.util.Map evalutes to function
 typeof java.util.HashMap evalutes to function
 var m = new java.util.HashMap(); m.put('foo', 42); m evalutes to {foo=42}
-java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod java.io.PrintStream.println]
+java.lang.System.out.println evalutes to [jdk.internal.dynalink.beans.OverloadedDynamicMethod
+ void java.io.PrintStream.println()
+ void java.io.PrintStream.println(boolean)
+ void java.io.PrintStream.println(char)
+ void java.io.PrintStream.println(char[])
+ void java.io.PrintStream.println(double)
+ void java.io.PrintStream.println(float)
+ void java.io.PrintStream.println(int)
+ void java.io.PrintStream.println(long)
+ void java.io.PrintStream.println(Object)
+ void java.io.PrintStream.println(String)
+]
 java.lang.System.exit evalutes to [jdk.internal.dynalink.beans.SimpleDynamicMethod void java.lang.System.exit(int)]
 new javax.script.SimpleBindings throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.SimpleBindings
 Java.type('javax.script.ScriptContext') throws java.lang.RuntimeException: java.lang.ClassNotFoundException: javax.script.ScriptContext