--- old/src/java.base/share/classes/java/lang/Class.java 2018-10-17 12:13:15.464086864 -0700 +++ new/src/java.base/share/classes/java/lang/Class.java 2018-10-17 12:13:15.296086864 -0700 @@ -59,6 +59,8 @@ import java.util.Map; import java.util.Objects; import java.util.StringJoiner; +import java.util.stream.Stream; +import java.util.stream.Collectors; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.loader.BootLoader; @@ -200,7 +202,8 @@ * and {@code class}, {@code enum}, {@code interface}, or * @{@code interface}, as appropriate), followed * by the type's name, followed by an angle-bracketed - * comma-separated list of the type's type parameters, if any. + * comma-separated list of the type's type parameters, if any, + * including informative bounds on the type parameters, if any. * * A space is used to separate modifiers from one another and to * separate any modifiers from the kind of type. The modifiers @@ -262,11 +265,8 @@ TypeVariable[] typeparms = component.getTypeParameters(); if (typeparms.length > 0) { - StringJoiner sj = new StringJoiner(",", "<", ">"); - for(TypeVariable typeparm: typeparms) { - sj.add(typeparm.getTypeName()); - } - sb.append(sj.toString()); + sb.append(Stream.of(typeparms).map(t -> typeVarBounds(t)). + collect(Collectors.joining(",", "<", ">"))); } for (int i = 0; i < arrayDepth; i++) @@ -276,6 +276,17 @@ } } + String typeVarBounds(TypeVariable typeVar) { + Type[] bounds = typeVar.getBounds(); + if (bounds.length == 1 && bounds[0].equals(Object.class)) { + return typeVar.getName(); + } else { + return typeVar.getName() + " extends " + + Stream.of(bounds).map(e -> e.getTypeName()). + collect(Collectors.joining(" & ")); + } + } + /** * Returns the {@code Class} object associated with the class or * interface with the given string name. Invoking this method is --- old/src/java.base/share/classes/java/lang/reflect/Constructor.java 2018-10-17 12:13:15.888086864 -0700 +++ new/src/java.base/share/classes/java/lang/reflect/Constructor.java 2018-10-17 12:13:15.720086864 -0700 @@ -382,7 +382,8 @@ * including type parameters. The string is formatted as the * constructor access modifiers, if any, followed by an * angle-bracketed comma separated list of the constructor's type - * parameters, if any, followed by the fully-qualified name of the + * parameters, if any, including informative bounds of the + * type parameters, if any, followed by the fully-qualified name of the * declaring class, followed by a parenthesized, comma-separated * list of the constructor's generic formal parameter types. * --- old/src/java.base/share/classes/java/lang/reflect/Executable.java 2018-10-17 12:13:16.304086864 -0700 +++ new/src/java.base/share/classes/java/lang/reflect/Executable.java 2018-10-17 12:13:16.128086864 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2018, 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 @@ -26,9 +26,12 @@ package java.lang.reflect; import java.lang.annotation.*; +import java.util.Arrays; import java.util.Map; import java.util.Objects; import java.util.StringJoiner; +import java.util.stream.Stream; +import java.util.stream.Collectors; import jdk.internal.misc.SharedSecrets; import sun.reflect.annotation.AnnotationParser; @@ -109,19 +112,15 @@ printModifiersIfNonzero(sb, modifierMask, isDefault); specificToStringHeader(sb); sb.append('('); - StringJoiner sj = new StringJoiner(","); - for (Class parameterType : parameterTypes) { - sj.add(parameterType.getTypeName()); - } - sb.append(sj.toString()); + + sb.append(Stream.of(parameterTypes).map(p -> p.getTypeName()). + collect(Collectors.joining(","))); + sb.append(')'); if (exceptionTypes.length > 0) { - StringJoiner joiner = new StringJoiner(",", " throws ", ""); - for (Class exceptionType : exceptionTypes) { - joiner.add(exceptionType.getTypeName()); - } - sb.append(joiner.toString()); + sb.append(Stream.of(exceptionTypes).map(e -> e.getTypeName()). + collect(Collectors.joining(",", " throws ", ""))); } return sb.toString(); } catch (Exception e) { @@ -135,6 +134,17 @@ */ abstract void specificToStringHeader(StringBuilder sb); + String typeVarBounds(TypeVariable typeVar) { + Type[] bounds = typeVar.getBounds(); + if (bounds.length == 1 && bounds[0].equals(Object.class)) { + return typeVar.getName(); + } else { + return typeVar.getName() + " extends " + + Stream.of(bounds).map(e -> e.getTypeName()). + collect(Collectors.joining(" & ")); + } + } + String sharedToGenericString(int modifierMask, boolean isDefault) { try { StringBuilder sb = new StringBuilder(); @@ -143,11 +153,8 @@ TypeVariable[] typeparms = getTypeParameters(); if (typeparms.length > 0) { - StringJoiner sj = new StringJoiner(",", "<", "> "); - for(TypeVariable typeparm: typeparms) { - sj.add(typeparm.getTypeName()); - } - sb.append(sj.toString()); + sb.append(Stream.of(typeparms).map(t -> typeVarBounds(t)). + collect(Collectors.joining(",", "<", "> "))); } specificToGenericStringHeader(sb); --- old/src/java.base/share/classes/java/lang/reflect/Method.java 2018-10-17 12:13:16.712086864 -0700 +++ new/src/java.base/share/classes/java/lang/reflect/Method.java 2018-10-17 12:13:16.544086864 -0700 @@ -436,10 +436,11 @@ } /** - * Returns a string describing this {@code Method}, including - * type parameters. The string is formatted as the method access + * Returns a string describing this {@code Method}, including type + * parameters. The string is formatted as the method access * modifiers, if any, followed by an angle-bracketed * comma-separated list of the method's type parameters, if any, + * including informative bounds of the type parameters, if any, * followed by the method's generic return type, followed by a * space, followed by the class declaring the method, followed by * a period, followed by the method name, followed by a --- old/test/jdk/java/lang/Class/GenericStringTest.java 2018-10-17 12:13:17.124086864 -0700 +++ new/test/jdk/java/lang/Class/GenericStringTest.java 2018-10-17 12:13:16.948086864 -0700 @@ -23,7 +23,7 @@ /* * @test - * @bug 6298888 6992705 8161500 + * @bug 6298888 6992705 8161500 6304578 * @summary Check Class.toGenericString() * @author Joseph D. Darcy */ @@ -43,12 +43,20 @@ String[][] nested = {{""}}; int[][] intArray = {{1}}; - failures += checkToGenericString(int.class, "int"); - failures += checkToGenericString(void.class, "void"); - failures += checkToGenericString(args.getClass(), "java.lang.String[]"); - failures += checkToGenericString(nested.getClass(), "java.lang.String[][]"); - failures += checkToGenericString(intArray.getClass(), "int[][]"); - failures += checkToGenericString(java.util.Map.class, "public abstract interface java.util.Map"); + Map, String> testCases = + Map.of(int.class, "int", + void.class, "void", + args.getClass(), "java.lang.String[]", + nested.getClass(), "java.lang.String[][]", + intArray.getClass(), "int[][]", + java.lang.Enum.class, "public abstract class java.lang.Enum>", + java.util.Map.class, "public abstract interface java.util.Map", + java.util.EnumMap.class, "public class java.util.EnumMap,V>", + java.util.EventListenerProxy.class, "public abstract class java.util.EventListenerProxy"); + + for (Map.Entry, String> testCase : testCases.entrySet()) { + failures += checkToGenericString(testCase.getKey(), testCase.getValue()); + } Field f = GenericStringTest.class.getDeclaredField("mixed"); // The expected value includes "" rather than @@ -74,7 +82,7 @@ private static int checkToGenericString(Class clazz, String expected) { String genericString = clazz.toGenericString(); if (!genericString.equals(expected)) { - System.err.printf("Unexpected Class.toGenericString output; expected '%s', got '%s'.%n", + System.err.printf("Unexpected Class.toGenericString output; expected %n\t'%s',%n got %n\t'%s'.%n", expected, genericString); return 1; --- old/test/jdk/java/lang/reflect/Constructor/GenericStringTest.java 2018-10-17 12:13:17.528086864 -0700 +++ new/test/jdk/java/lang/reflect/Constructor/GenericStringTest.java 2018-10-17 12:13:17.360086864 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 5033583 6316717 6470106 8161500 8162539 + * @bug 5033583 6316717 6470106 8161500 8162539 6304578 * @summary Check toGenericString() and toString() methods * @author Joseph D. Darcy */ @@ -87,7 +87,13 @@ protected TestClass1(S s, T t) throws Exception{} @ExpectedGenericString( - " TestClass1() throws E") + "protected TestClass1(V)") + @ExpectedString( + "protected TestClass1(java.lang.Number)") + protected TestClass1(V v){} + + @ExpectedGenericString( + " TestClass1() throws E") @ExpectedString( "TestClass1() throws java.lang.Exception") TestClass1() throws E {} --- old/test/jdk/java/lang/reflect/Method/GenericStringTest.java 2018-10-17 12:13:17.928086864 -0700 +++ new/test/jdk/java/lang/reflect/Method/GenericStringTest.java 2018-10-17 12:13:17.760086864 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2018, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 5033583 6316717 6470106 8004979 8161500 8162539 + * @bug 5033583 6316717 6470106 8004979 8161500 8162539 6304578 * @summary Check toGenericString() and toString() methods * @author Joseph D. Darcy */ @@ -103,6 +103,10 @@ @ExpectedGenericString( "protected S TestClass1.method4(S,T) throws java.lang.Exception") protected S method4(S s, T t) throws Exception {return null;} + + @ExpectedGenericString( + "public static T TestClass1.max(java.util.Collection,java.util.Comparator)") + public static T max(Collection coll, Comparator comp) {return null;} } class TestClass2 { @@ -139,6 +143,10 @@ @ExpectedGenericString( "public java.util.Map TestClass2.method8()") public Map method8() {return null;} + + @ExpectedGenericString( + "public java.util.Set TestClass2.method9(V)") + public Set method9(V v) {return null;} } class Roebling implements Comparable {