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

(fmt) Formatter misses IOExceptions when formatting Formattable with explicit Locale

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • None
    • 7
    • core-libs
    • x86
    • windows_xp

      FULL PRODUCT VERSION :
      java version "1.7.0_01"
      Java(TM) SE Runtime Environment (build 1.7.0_01-b08)
      Java HotSpot(TM) Client VM (build 21.1-b02, mixed mode, sharing)


      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]


      A DESCRIPTION OF THE PROBLEM :
      When formatting to an Appendable using a java.util.Formatter, IOExceptions thrown by the Appendable during formatting can usually be accessed using the ioException() method of the Formatter.

      However, this does not work if (a) an Object implementing the Formattable interface is formatted and (b) a specific Locale which is different from the Formatters Locale is specified using the formatTo(Locale, String, Object...) method. In that case IOExceptions are ignored.

      The reason can easily be seen in the source code of Formatter (lines 2826ff in the Oracle JDK 1.7.1_01 sources):

              private void printString(Object arg, Locale l) throws IOException {
                  if (arg instanceof Formattable) {
                      Formatter fmt = Formatter.this;
                      if (fmt.locale() != l)
                          fmt = new Formatter(fmt.out(), l);
                      ((Formattable)arg).formatTo(fmt, f.valueOf(), width, precision);
                  } else {
                      if (f.contains(Flags.ALTERNATE))
                          failMismatch(Flags.ALTERNATE, 's');
                      if (arg == null)
                          print("null");
                      else
                          print(arg.toString());
                  }
              }

      It's obvious that if conditions (a) and (b) both apply, formatTo(...) will not receive the original Formatter instance but a newly created one, using the same Appendable but the Locale specified in the method call instead of the Formatters Locale. Since after calling formatTo(...) there is no check if an IOException has been catched by this "temporary" Formatter. Therefore, if any IOException has been thrown, it will be lost and not accessible through ioException() in the original Formatter.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      I included some source code to demonstrate the problem. Just compile FormattableIOExceptionBug and execute it as a Java application.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      When executing FormattableIOExceptionBug, the following output would be expected:

      (1) java.io.IOException: testing
      (2) java.io.IOException: testing
      (3) java.io.IOException: testing
      (4) java.io.IOException: testing
      (5) java.io.IOException: testing

      ACTUAL -
      The actual output of FormattableIOExceptionBug is:

      (1) java.io.IOException: testing
      (2) java.io.IOException: testing
      (3) java.io.IOException: testing
      (4) java.io.IOException: testing
      (5) null


      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.IOException;
      import java.util.Formattable;
      import java.util.Formatter;
      import java.util.Locale;


      public class FormattableIOExceptionBug {

        public static void main (String[] args) {
          // an Appendable which always throws IOException:
          Appendable apd = new ThrowingAppendable();
          Formatter fmt = null;

          // (1) no locale, not Formattable:
          fmt = new Formatter(apd, Locale.US);
          fmt.format("%s", "some-string");
          System.out.println("(1) " + fmt.ioException());

          // (2) no locale, Formattable:
          fmt = new Formatter(apd, Locale.US);
          fmt.format("%s", new MyFormattable());
          System.out.println("(2) " + fmt.ioException());

          // (3) with different locale, not Formattable:
          fmt = new Formatter(apd, Locale.US);
          fmt.format(Locale.GERMANY, "%s", "some-string");
          System.out.println("(3) " + fmt.ioException());

          // (4) with the Formatters locale, Formattable:
          fmt = new Formatter(apd, Locale.US);
          fmt.format(Locale.US, "%s", new MyFormattable());
          System.out.println("(4) " + fmt.ioException());

          // (5) BUG HERE - different locale, Formattable:
          fmt = new Formatter(apd, Locale.US);
          fmt.format(Locale.GERMANY, "%s", new MyFormattable());
          System.out.println("(5) " + fmt.ioException());
        }

        private static final class ThrowingAppendable implements Appendable {

          @Override
          public Appendable append (CharSequence csq) throws IOException {
            throw new IOException("testing");
          }

          @Override
          public Appendable append (CharSequence csq, int start, int end) throws IOException {
            throw new IOException("testing");
          }

          @Override
          public Appendable append (char c) throws IOException {
            throw new IOException("testing");
          }
        }

        private static final class MyFormattable implements Formattable {

          @Override
          public void formatTo (Formatter formatter, int flags, int width, int precision) {
            formatter.format("Simple demo implementation ignoring flags, width and precision.");
          }
        }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Sorry, no workaround. But it should be easy to fix.

            sherman Xueming Shen
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Imported:
              Indexed: