# HG changeset patch # User naoto # Date 1520268647 28800 # Node ID fb9f590b9eeecae202277c0606ed12b4d3f674c3 # Parent 97288886180cf6b6ca69358026495eaf76c2ae04 4993841: (str) java.lang.Character should have a toString(int) method Reviewed-by: martin, rriggs, sherman, smarks diff -r 97288886180c -r fb9f590b9eee src/java.base/share/classes/java/lang/Character.java --- a/src/java.base/share/classes/java/lang/Character.java Mon Mar 05 08:27:42 2018 -0800 +++ b/src/java.base/share/classes/java/lang/Character.java Mon Mar 05 08:50:47 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -7568,6 +7568,11 @@ * specified {@code char}. The result is a string of length * 1 consisting solely of the specified {@code char}. * + * @apiNote This method cannot handle supplementary characters. To support + * all Unicode characters, including supplementary characters, use + * the {@link #toString(int)} method. + * * @param c the {@code char} to be converted * @return the string representation of the specified {@code char} * @since 1.4 @@ -7577,6 +7582,22 @@ } /** + * Returns a {@code String} object representing the + * specified character (Unicode code point). The result is a string of + * length 1 or 2, consisting solely of the specified {@code codePoint}. + * + * @param codePoint the {@code codePoint} to be converted + * @return the string representation of the specified {@code codePoint} + * @exception IllegalArgumentException if the specified + * {@code codePoint} is not a {@linkplain #isValidCodePoint + * valid Unicode code point}. + * @since 11 + */ + public static String toString(int codePoint) { + return String.valueOfCodePoint(codePoint); + } + + /** * Determines whether the specified code point is a valid * * Unicode code point value. diff -r 97288886180c -r fb9f590b9eee src/java.base/share/classes/java/lang/String.java --- a/src/java.base/share/classes/java/lang/String.java Mon Mar 05 08:27:42 2018 -0800 +++ b/src/java.base/share/classes/java/lang/String.java Mon Mar 05 08:50:47 2018 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 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 @@ -3157,4 +3157,27 @@ "begin " + begin + ", end " + end + ", length " + length); } } + + /** + * Returns the string representation of the {@code codePoint} + * argument. + * + * @param codePoint a {@code codePoint}. + * @return a string of length {@code 1} or {@code 2} containing + * as its single character the argument {@code codePoint}. + * @throws IllegalArgumentException if the specified + * {@code codePoint} is not a {@linkplain Character#isValidCodePoint + * valid Unicode code point}. + */ + static String valueOfCodePoint(int codePoint) { + if (COMPACT_STRINGS && StringLatin1.canEncode(codePoint)) { + return new String(StringLatin1.toBytes((char)codePoint), LATIN1); + } else if (Character.isBmpCodePoint(codePoint)) { + return new String(StringUTF16.toBytes((char)codePoint), UTF16); + } else if (Character.isSupplementaryCodePoint(codePoint)) { + return new String(StringUTF16.toBytesSupplementary(codePoint), UTF16); + } + + throw new IllegalArgumentException("Not a valid Unicode code point"); + } } diff -r 97288886180c -r fb9f590b9eee src/java.base/share/classes/java/lang/StringUTF16.java --- a/src/java.base/share/classes/java/lang/StringUTF16.java Mon Mar 05 08:27:42 2018 -0800 +++ b/src/java.base/share/classes/java/lang/StringUTF16.java Mon Mar 05 08:50:47 2018 -0800 @@ -235,6 +235,13 @@ return result; } + static byte[] toBytesSupplementary(int cp) { + byte[] result = new byte[4]; + putChar(result, 0, Character.highSurrogate(cp)); + putChar(result, 1, Character.lowSurrogate(cp)); + return result; + } + @HotSpotIntrinsicCandidate public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) { // We need a range check here because 'getChar' has no checks diff -r 97288886180c -r fb9f590b9eee test/jdk/java/lang/Character/Supplementary.java --- a/test/jdk/java/lang/Character/Supplementary.java Mon Mar 05 08:27:42 2018 -0800 +++ b/test/jdk/java/lang/Character/Supplementary.java Mon Mar 05 08:50:47 2018 -0800 @@ -23,7 +23,7 @@ /* * @test - * @bug 4533872 4985214 4985217 5017268 5017280 + * @bug 4533872 4985214 4985217 4993841 5017268 5017280 * @summary Unit tests for supplementary character support (JSR-204) * @compile Supplementary.java * @run main/timeout=600 Supplementary @@ -59,6 +59,9 @@ test04(str); test05(str); + // Test for toString(int) + test06(); + // Test unpaired surrogates testUnpaired(); @@ -454,6 +457,23 @@ checkNewIndex(a, 0, index, length); } + /** + * Test toString(int) + * + * This test case assumes that Character.toChars()/String(char[]) work + * correctly. + */ + static void test06() { + for (int cp = Character.MIN_CODE_POINT; cp <= Character.MAX_CODE_POINT; cp++) { + String result = Character.toString(cp); + String expected = new String(Character.toChars(cp)); + if (!result.equals(expected)) { + throw new RuntimeException("Wrong string is created. code point: " + + cp + ", result: " + result + ", expected: " + expected); + } + } + } + private static void checkNewIndex(Object data, int offset, int result, int expected) { String type = getType(data); String offsetType = (offset > 0) ? "positive" : (offset < 0) ? "negative" : "0"; @@ -580,6 +600,7 @@ // Test toChar(int) // toChar(int, char[], int) + // toString(int) // for exceptions static void testExceptions00() { callToChars1(-1, IllegalArgumentException.class); @@ -595,6 +616,9 @@ callToChars3(MIN_SUPPLEMENTARY, new char[1], 0, IndexOutOfBoundsException.class); callToChars3(MIN_SUPPLEMENTARY, new char[2], -1, IndexOutOfBoundsException.class); callToChars3(MIN_SUPPLEMENTARY, new char[2], 1, IndexOutOfBoundsException.class); + + callToString(Character.MIN_CODE_POINT - 1, IllegalArgumentException.class); + callToString(Character.MAX_CODE_POINT + 1, IllegalArgumentException.class); } static final boolean At = true, Before = false; @@ -834,6 +858,19 @@ + expectedException.getName()); } + private static void callToString(int codePoint, Class expectedException) { + try { + String s = Character.toString(codePoint); + } catch (Exception e) { + if (expectedException.isInstance(e)) { + return; + } + throw new RuntimeException("Unspecified exception", e); + } + throw new RuntimeException("toString(int) didn't throw " + + expectedException.getName()); + } + private static String getType(Object data) { return (data instanceof CharSequence) ? "CharSequence" : "char[]"; }