Path: blob/master/test/jdk/java/text/Format/MessageFormat/MessageRegression.java
41152 views
/*1* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 4031438 4058973 4074764 4094906 4104976 4105380 4106659 4106660 410666126* 4111739 4112104 4113018 4114739 4114743 4116444 4118592 4118594 412055227* 4142938 4169959 4232154 4293229 818755128* @summary Regression tests for MessageFormat and associated classes29* @library /java/text/testlib30* @run main MessageRegression31*/32/*33(C) Copyright Taligent, Inc. 1996 - All Rights Reserved34(C) Copyright IBM Corp. 1996 - All Rights Reserved3536The original version of this source code and documentation is copyrighted and37owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These materials are38provided under terms of a License Agreement between Taligent and Sun. This39technology is protected by multiple US and International patents. This notice and40attribution to Taligent may not be removed.41Taligent is a registered trademark of Taligent, Inc.42*/4344import java.text.*;45import java.util.*;46import java.io.IOException;47import java.io.FileOutputStream;48import java.io.FileInputStream;49import java.io.ByteArrayInputStream;50import java.io.ByteArrayOutputStream;51import java.io.ObjectOutputStream;52import java.io.ObjectInputStream;53import java.io.Serializable;5455public class MessageRegression extends IntlTest {5657public static void main(String[] args) throws Exception {58new MessageRegression().run(args);59}6061/* @bug 407476462* Null exception when formatting pattern with MessageFormat63* with no parameters.64*/65public void Test4074764() {66String[] pattern = {"Message without param",67"Message with param:{0}",68"Longer Message with param {0}"};69//difference between the two param strings are that70//in the first one, the param position is within the71//length of the string without param while it is not so72//in the other case.7374MessageFormat messageFormatter = new MessageFormat("");7576try {77//Apply pattern with param and print the result78messageFormatter.applyPattern(pattern[1]);79Object[] params = {new String("BUG"), new Date()};80String tempBuffer = messageFormatter.format(params);81if (!tempBuffer.equals("Message with param:BUG"))82errln("MessageFormat with one param test failed.");83logln("Formatted with one extra param : " + tempBuffer);8485//Apply pattern without param and print the result86messageFormatter.applyPattern(pattern[0]);87tempBuffer = messageFormatter.format(null);88if (!tempBuffer.equals("Message without param"))89errln("MessageFormat with no param test failed.");90logln("Formatted with no params : " + tempBuffer);9192tempBuffer = messageFormatter.format(params);93if (!tempBuffer.equals("Message without param"))94errln("Formatted with arguments > subsitution failed. result = " + tempBuffer.toString());95logln("Formatted with extra params : " + tempBuffer);96//This statement gives an exception while formatting...97//If we use pattern[1] for the message with param,98//we get an NullPointerException in MessageFormat.java(617)99//If we use pattern[2] for the message with param,100//we get an StringArrayIndexOutOfBoundsException in MessageFormat.java(614)101//Both are due to maxOffset not being reset to -1102//in applyPattern() when the pattern does not103//contain any param.104} catch (Exception foo) {105errln("Exception when formatting with no params.");106}107}108109/* @bug 4058973110* MessageFormat.toPattern has weird rounding behavior.111*/112public void Test4058973() {113114MessageFormat fmt = new MessageFormat("{0,choice,0#no files|1#one file|1< {0,number,integer} files}");115String pat = fmt.toPattern();116if (!pat.equals("{0,choice,0.0#no files|1.0#one file|1.0< {0,number,integer} files}")) {117errln("MessageFormat.toPattern failed");118}119}120/* @bug 4031438121* More robust message formats.122*/123public void Test4031438() {124Locale locale = Locale.getDefault();125if (!TestUtils.usesAsciiDigits(locale)) {126logln("Skipping this test because locale is " + locale);127return;128}129130String pattern1 = "Impossible {1} has occurred -- status code is {0} and message is {2}.";131String pattern2 = "Double '' Quotes {0} test and quoted '{1}' test plus 'other {2} stuff'.";132133MessageFormat messageFormatter = new MessageFormat("");134135try {136logln("Apply with pattern : " + pattern1);137messageFormatter.applyPattern(pattern1);138Object[] params = {7};139String tempBuffer = messageFormatter.format(params);140if (!tempBuffer.equals("Impossible {1} has occurred -- status code is 7 and message is {2}."))141errln("Tests arguments < substitution failed. Formatted text=" +142"<" + tempBuffer + ">");143logln("Formatted with 7 : " + tempBuffer);144ParsePosition status = new ParsePosition(0);145Object[] objs = messageFormatter.parse(tempBuffer, status);146if (objs[params.length] != null)147errln("Parse failed with more than expected arguments");148for (int i = 0; i < objs.length; i++) {149if (objs[i] != null && !objs[i].toString().equals(params[i].toString())) {150errln("Parse failed on object " + objs[i] + " at index : " + i);151}152}153tempBuffer = messageFormatter.format(null);154if (!tempBuffer.equals("Impossible {1} has occurred -- status code is {0} and message is {2}."))155errln("Tests with no arguments failed");156logln("Formatted with null : " + tempBuffer);157logln("Apply with pattern : " + pattern2);158messageFormatter.applyPattern(pattern2);159tempBuffer = messageFormatter.format(params);160if (!tempBuffer.equals("Double ' Quotes 7 test and quoted {1} test plus other {2} stuff."))161errln("quote format test (w/ params) failed.");162logln("Formatted with params : " + tempBuffer);163tempBuffer = messageFormatter.format(null);164if (!tempBuffer.equals("Double ' Quotes {0} test and quoted {1} test plus other {2} stuff."))165errln("quote format test (w/ null) failed.");166logln("Formatted with null : " + tempBuffer);167logln("toPattern : " + messageFormatter.toPattern());168} catch (Exception foo) {169errln("Exception when formatting in bug 4031438. "+foo.getMessage());170}171}172public void Test4052223()173{174ParsePosition pos = new ParsePosition(0);175if (pos.getErrorIndex() != -1) {176errln("ParsePosition.getErrorIndex initialization failed.");177}178MessageFormat fmt = new MessageFormat("There are {0} apples growing on the {1} tree.");179String str = new String("There is one apple growing on the peach tree.");180Object[] objs = fmt.parse(str, pos);181logln("unparsable string , should fail at " + pos.getErrorIndex());182if (pos.getErrorIndex() == -1)183errln("Bug 4052223 failed : parsing string " + str);184pos.setErrorIndex(4);185if (pos.getErrorIndex() != 4)186errln("setErrorIndex failed, got " + pos.getErrorIndex() + " instead of 4");187ChoiceFormat f = new ChoiceFormat(188"-1#are negative|0#are no or fraction|1#is one|1.0<is 1+|2#are two|2<are more than 2.");189pos.setIndex(0); pos.setErrorIndex(-1);190Number obj = f.parse("are negative", pos);191if (pos.getErrorIndex() != -1 && obj.doubleValue() == -1.0)192errln("Parse with \"are negative\" failed, at " + pos.getErrorIndex());193pos.setIndex(0); pos.setErrorIndex(-1);194obj = f.parse("are no or fraction ", pos);195if (pos.getErrorIndex() != -1 && obj.doubleValue() == 0.0)196errln("Parse with \"are no or fraction\" failed, at " + pos.getErrorIndex());197pos.setIndex(0); pos.setErrorIndex(-1);198obj = f.parse("go postal", pos);199if (pos.getErrorIndex() == -1 && !Double.isNaN(obj.doubleValue()))200errln("Parse with \"go postal\" failed, at " + pos.getErrorIndex());201}202/* @bug 4104976203* ChoiceFormat.equals(null) throws NullPointerException204*/205public void Test4104976()206{207double[] limits = {1, 20};208String[] formats = {"xyz", "abc"};209ChoiceFormat cf = new ChoiceFormat(limits, formats);210try {211log("Compares to null is always false, returned : ");212logln(cf.equals(null) ? "TRUE" : "FALSE");213} catch (Exception foo) {214errln("ChoiceFormat.equals(null) throws exception.");215}216}217/* @bug 4106659218* ChoiceFormat.ctor(double[], String[]) doesn't check219* whether lengths of input arrays are equal.220*/221public void Test4106659()222{223double[] limits = {1, 2, 3};224String[] formats = {"one", "two"};225ChoiceFormat cf = null;226try {227cf = new ChoiceFormat(limits, formats);228} catch (Exception foo) {229logln("ChoiceFormat constructor should check for the array lengths");230cf = null;231}232if (cf != null) errln(cf.format(5));233}234235/* @bug 4106660236* ChoiceFormat.ctor(double[], String[]) allows unordered double array.237* This is not a bug, added javadoc to emphasize the use of limit238* array must be in ascending order.239*/240public void Test4106660()241{242double[] limits = {3, 1, 2};243String[] formats = {"Three", "One", "Two"};244ChoiceFormat cf = new ChoiceFormat(limits, formats);245double d = 5.0;246String str = cf.format(d);247if (!str.equals("Two"))248errln("format(" + d + ") = " + cf.format(d));249}250251/* @bug 4111739252* MessageFormat is incorrectly serialized/deserialized.253*/254public void Test4111739()255{256MessageFormat format1 = null;257MessageFormat format2 = null;258ObjectOutputStream ostream = null;259ByteArrayOutputStream baos = null;260ObjectInputStream istream = null;261262try {263baos = new ByteArrayOutputStream();264ostream = new ObjectOutputStream(baos);265} catch(IOException e) {266errln("Unexpected exception : " + e.getMessage());267return;268}269270try {271format1 = new MessageFormat("pattern{0}");272ostream.writeObject(format1);273ostream.flush();274275byte bytes[] = baos.toByteArray();276277istream = new ObjectInputStream(new ByteArrayInputStream(bytes));278format2 = (MessageFormat)istream.readObject();279} catch(Exception e) {280errln("Unexpected exception : " + e.getMessage());281}282283if (!format1.equals(format2)) {284errln("MessageFormats before and after serialization are not" +285" equal\nformat1 = " + format1 + "(" + format1.toPattern() + ")\nformat2 = " +286format2 + "(" + format2.toPattern() + ")");287} else {288logln("Serialization for MessageFormat is OK.");289}290}291/* @bug 4114743292* MessageFormat.applyPattern allows illegal patterns.293*/294public void Test4114743()295{296String originalPattern = "initial pattern";297MessageFormat mf = new MessageFormat(originalPattern);298try {299String illegalPattern = "ab { '}' de";300mf.applyPattern(illegalPattern);301errln("illegal pattern: \"" + illegalPattern + "\"");302} catch (IllegalArgumentException foo) {303if (!originalPattern.equals(mf.toPattern()))304errln("pattern after: \"" + mf.toPattern() + "\"");305}306}307308/* @bug 4116444309* MessageFormat.parse has different behavior in case of null.310*/311public void Test4116444()312{313String[] patterns = {"", "one", "{0,date,short}"};314MessageFormat mf = new MessageFormat("");315316for (int i = 0; i < patterns.length; i++) {317String pattern = patterns[i];318mf.applyPattern(pattern);319try {320Object[] array = mf.parse(null, new ParsePosition(0));321logln("pattern: \"" + pattern + "\"");322log(" parsedObjects: ");323if (array != null) {324log("{");325for (int j = 0; j < array.length; j++) {326if (array[j] != null)327err("\"" + array[j].toString() + "\"");328else329log("null");330if (j < array.length - 1) log(",");331}332log("}") ;333} else {334log("null");335}336logln("");337} catch (Exception e) {338errln("pattern: \"" + pattern + "\"");339errln(" Exception: " + e.getMessage());340}341}342343}344/* @bug 4114739 (FIX and add javadoc)345* MessageFormat.format has undocumented behavior about empty format objects.346*/347public void Test4114739()348{349350MessageFormat mf = new MessageFormat("<{0}>");351Object[] objs1 = null;352Object[] objs2 = {};353Object[] objs3 = {null};354try {355logln("pattern: \"" + mf.toPattern() + "\"");356log("format(null) : ");357logln("\"" + mf.format(objs1) + "\"");358log("format({}) : ");359logln("\"" + mf.format(objs2) + "\"");360log("format({null}) :");361logln("\"" + mf.format(objs3) + "\"");362} catch (Exception e) {363errln("Exception thrown for null argument tests.");364}365}366367/* @bug 4113018368* MessageFormat.applyPattern works wrong with illegal patterns.369*/370public void Test4113018()371{372String originalPattern = "initial pattern";373MessageFormat mf = new MessageFormat(originalPattern);374String illegalPattern = "format: {0, xxxYYY}";375logln("pattern before: \"" + mf.toPattern() + "\"");376logln("illegal pattern: \"" + illegalPattern + "\"");377try {378mf.applyPattern(illegalPattern);379errln("Should have thrown IllegalArgumentException for pattern : " + illegalPattern);380} catch (IllegalArgumentException e) {381if (!originalPattern.equals(mf.toPattern()))382errln("pattern after: \"" + mf.toPattern() + "\"");383}384}385/* @bug 4106661386* ChoiceFormat is silent about the pattern usage in javadoc.387*/388public void Test4106661()389{390ChoiceFormat fmt = new ChoiceFormat(391"-1#are negative| 0#are no or fraction | 1#is one |1.0<is 1+ |2#are two |2<are more than 2.");392logln("Formatter Pattern : " + fmt.toPattern());393394logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));395logln("Format with -1.0 : " + fmt.format(-1.0));396logln("Format with 0 : " + fmt.format(0));397logln("Format with 0.9 : " + fmt.format(0.9));398logln("Format with 1.0 : " + fmt.format(1));399logln("Format with 1.5 : " + fmt.format(1.5));400logln("Format with 2 : " + fmt.format(2));401logln("Format with 2.1 : " + fmt.format(2.1));402logln("Format with NaN : " + fmt.format(Double.NaN));403logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));404}405/* @bug 4094906406* ChoiceFormat should accept \u221E as eq. to INF.407*/408public void Test4094906()409{410ChoiceFormat fmt = new ChoiceFormat(411"-\u221E<are negative|0<are no or fraction|1#is one|1.0<is 1+|\u221E<are many.");412if (!fmt.toPattern().startsWith("-\u221E<are negative|0.0<are no or fraction|1.0#is one|1.0<is 1+|\u221E<are many."))413errln("Formatter Pattern : " + fmt.toPattern());414logln("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));415logln("Format with -1.0 : " + fmt.format(-1.0));416logln("Format with 0 : " + fmt.format(0));417logln("Format with 0.9 : " + fmt.format(0.9));418logln("Format with 1.0 : " + fmt.format(1));419logln("Format with 1.5 : " + fmt.format(1.5));420logln("Format with 2 : " + fmt.format(2));421logln("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));422}423424/* @bug 4118592425* MessageFormat.parse fails with ChoiceFormat.426*/427public void Test4118592()428{429MessageFormat mf = new MessageFormat("");430String pattern = "{0,choice,1#YES|2#NO}";431String prefix = "";432for (int i = 0; i < 5; i++) {433String formatted = prefix + "YES";434mf.applyPattern(prefix + pattern);435prefix += "x";436Object[] objs = mf.parse(formatted, new ParsePosition(0));437logln(i + ". pattern :\"" + mf.toPattern() + "\"");438log(" \"" + formatted + "\" parsed as ");439if (objs == null) logln(" null");440else logln(" " + objs[0]);441}442}443/* @bug 4118594444* MessageFormat.parse fails for some patterns.445*/446public void Test4118594()447{448MessageFormat mf = new MessageFormat("{0}, {0}, {0}");449String forParsing = "x, y, z";450Object[] objs = mf.parse(forParsing, new ParsePosition(0));451logln("pattern: \"" + mf.toPattern() + "\"");452logln("text for parsing: \"" + forParsing + "\"");453if (!objs[0].toString().equals("z"))454errln("argument0: \"" + objs[0] + "\"");455mf.setLocale(Locale.US);456mf.applyPattern("{0,number,#.##}, {0,number,#.#}");457Object[] oldobjs = {3.1415};458String result = mf.format( oldobjs );459logln("pattern: \"" + mf.toPattern() + "\"");460logln("text for parsing: \"" + result + "\"");461// result now equals "3.14, 3.1"462if (!result.equals("3.14, 3.1"))463errln("result = " + result);464Object[] newobjs = mf.parse(result, new ParsePosition(0));465// newobjs now equals {new Double(3.1)}466if (((Double)newobjs[0]).doubleValue() != 3.1)467errln( "newobjs[0] = " + newobjs[0]);468}469/* @bug 4105380470* When using ChoiceFormat, MessageFormat is not good for I18n.471*/472public void Test4105380()473{474String patternText1 = "The disk \"{1}\" contains {0}.";475String patternText2 = "There are {0} on the disk \"{1}\"";476MessageFormat form1 = new MessageFormat(patternText1);477MessageFormat form2 = new MessageFormat(patternText2);478double[] filelimits = {0,1,2};479String[] filepart = {"no files","one file","{0,number} files"};480ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);481form1.setFormat(1, fileform);482form2.setFormat(0, fileform);483Object[] testArgs = {12373L, "MyDisk"};484logln(form1.format(testArgs));485logln(form2.format(testArgs));486}487/* @bug 4120552488* MessageFormat.parse incorrectly sets errorIndex.489*/490public void Test4120552()491{492MessageFormat mf = new MessageFormat("pattern");493String texts[] = {"pattern", "pat", "1234"};494logln("pattern: \"" + mf.toPattern() + "\"");495for (int i = 0; i < texts.length; i++) {496ParsePosition pp = new ParsePosition(0);497Object[] objs = mf.parse(texts[i], pp);498log(" text for parsing: \"" + texts[i] + "\"");499if (objs == null) {500logln(" (incorrectly formatted string)");501if (pp.getErrorIndex() == -1)502errln("Incorrect error index: " + pp.getErrorIndex());503} else {504logln(" (correctly formatted string)");505}506}507}508509/**510* @bug 4142938511* MessageFormat handles single quotes in pattern wrong.512* This is actually a problem in ChoiceFormat; it doesn't513* understand single quotes.514*/515public void Test4142938() {516String pat = "''Vous'' {0,choice,0#n''|1#}avez s\u00E9lectionne\u00E9 " +517"{0,choice,0#aucun|1#{0}} client{0,choice,0#s|1#|2#s} " +518"personnel{0,choice,0#s|1#|2#s}.";519MessageFormat mf = new MessageFormat(pat);520521String[] PREFIX = {522"'Vous' n'avez s\u00E9lectionne\u00E9 aucun clients personnels.",523"'Vous' avez s\u00E9lectionne\u00E9 ",524"'Vous' avez s\u00E9lectionne\u00E9 "525};526String[] SUFFIX = {527null,528" client personnel.",529" clients personnels."530};531532for (int i=0; i<3; i++) {533String out = mf.format(new Object[]{i});534if (SUFFIX[i] == null) {535if (!out.equals(PREFIX[i]))536errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"");537}538else {539if (!out.startsWith(PREFIX[i]) ||540!out.endsWith(SUFFIX[i]))541errln("" + i + ": Got \"" + out + "\"; Want \"" + PREFIX[i] + "\"...\"" +542SUFFIX[i] + "\"");543}544}545}546547/**548* @bug 4142938549* Test the applyPattern and toPattern handling of single quotes550* by ChoiceFormat. (This is in here because this was a bug reported551* against MessageFormat.) The single quote is used to quote the552* pattern characters '|', '#', '<', and '\u2264'. Two quotes in a row553* is a quote literal.554*/555public void TestChoicePatternQuote() {556String[] DATA = {557// Pattern 0 value 1 value558"0#can''t|1#can", "can't", "can",559"0#'pound(#)=''#'''|1#xyz", "pound(#)='#'", "xyz",560"0#'1<2 | 1\u22641'|1#''", "1<2 | 1\u22641", "'",561};562for (int i=0; i<DATA.length; i+=3) {563try {564ChoiceFormat cf = new ChoiceFormat(DATA[i]);565for (int j=0; j<=1; ++j) {566String out = cf.format(j);567if (!out.equals(DATA[i+1+j]))568errln("Fail: Pattern \"" + DATA[i] + "\" x "+j+" -> " +569out + "; want \"" + DATA[i+1+j] + '"');570}571String pat = cf.toPattern();572String pat2 = new ChoiceFormat(pat).toPattern();573if (!pat.equals(pat2))574errln("Fail: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');575else576logln("Ok: Pattern \"" + DATA[i] + "\" x toPattern -> \"" + pat + '"');577}578catch (IllegalArgumentException e) {579errln("Fail: Pattern \"" + DATA[i] + "\" -> " + e);580}581}582}583584/**585* @bug 4112104586* MessageFormat.equals(null) throws a NullPointerException. The JLS states587* that it should return false.588*/589public void Test4112104() {590MessageFormat format = new MessageFormat("");591try {592// This should NOT throw an exception593if (format.equals(null)) {594// It also should return false595errln("MessageFormat.equals(null) returns false");596}597}598catch (NullPointerException e) {599errln("MessageFormat.equals(null) throws " + e);600}601}602603/**604* @bug 4169959605* MessageFormat does not format null objects. CANNOT REPRODUCE THIS BUG.606*/607public void Test4169959() {608// This works609logln(MessageFormat.format( "This will {0}", "work"));610611// This fails612logln(MessageFormat.format( "This will {0}",613new Object[]{ null } ) );614}615616public void test4232154() {617boolean gotException = false;618try {619MessageFormat format = new MessageFormat("The date is {0:date}");620} catch (Exception e) {621gotException = true;622if (!(e instanceof IllegalArgumentException)) {623throw new RuntimeException("got wrong exception type");624}625if ("argument number too large at ".equals(e.getMessage())) {626throw new RuntimeException("got wrong exception message");627}628}629if (!gotException) {630throw new RuntimeException("didn't get exception for invalid input");631}632}633634public void test4293229() {635MessageFormat format = new MessageFormat("'''{'0}'' '''{0}'''");636Object[] args = { null };637String expected = "'{0}' '{0}'";638String result = format.format(args);639if (!result.equals(expected)) {640throw new RuntimeException("wrong format result - expected \"" +641expected + "\", got \"" + result + "\"");642}643}644645/**646* @bug 8187551647* test MessageFormat.setFormat() method to throw AIOOBE on invalid index.648*/649public void test8187551() {650//invalid cases ("pattern", "invalid format element index")651String[][] invalidCases = {{"The disk \"{1}\" contains {0}.", "2"},652{"The disk \"{1}\" contains {0}.", "9"},653{"On {1}, there are {0} and {2} folders", "3"}};654655//invalid cases (must throw exception)656Arrays.stream(invalidCases).forEach(entry -> messageSetFormat(entry[0],657Integer.valueOf(entry[1])));658}659660// test MessageFormat.setFormat() method for the given pattern and661// format element index662private void messageSetFormat(String pattern, int elemIndex) {663MessageFormat form = new MessageFormat(pattern);664665double[] fileLimits = {0, 1, 2};666String[] filePart = {"no files", "one file", "{0,number} files"};667ChoiceFormat fileForm = new ChoiceFormat(fileLimits, filePart);668669boolean AIOOBEThrown = false;670try {671form.setFormat(elemIndex, fileForm);672} catch (ArrayIndexOutOfBoundsException ex) {673AIOOBEThrown = true;674}675676if (!AIOOBEThrown) {677throw new RuntimeException("[FAILED: Must throw" +678" ArrayIndexOutOfBoundsException for" +679" invalid index " + elemIndex + " used in" +680" MessageFormat.setFormat(index, format)]");681}682}683684}685686687