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

Add Format adapter to bridge into string methods

XMLWordPrintable

    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      This request for enhancement is to consider creating a new java.text.Format subclass that is backed by the operations supported by the java.lang.String class. Such an adapter class could then be used by the java.text.MessageFormat to provide a category of operations on string datatypes. This would then allow java.util.logging to construct patterns to transform logger arguments such as removing new lines using a perl style regex match and replace, trimming whitespace, substring from tail, and printf support.

      Here is an example prototype (not production worthy) that shows such an adapter can be easily built

      import java.io.Serializable;
      import java.text.FieldPosition;
      import java.text.Format;
      import java.text.ParsePosition;
      import java.util.Arrays;
      import java.util.Locale;
      import java.util.Objects;
      import java.util.function.BiConsumer;
      import java.util.regex.Pattern;

      public final class StringFormat extends Format {
         //TODO: add serial-id

          private final Class<?> type;

          private final BiConsumer<Object, StringBuffer> transform;

          /**
           * MessageFormat pattern of {1,printf, %1$tm-%1$te-%1$tY}
           *
           * @param pattern any java.util.Formatter pattern
           * @param l
           * @return
           */
          public static StringFormat getFormatInstance(String pattern, Locale l) {
              return new StringFormat(java.util.Formatter.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          new java.util.Formatter(b, l)
                                  .format(pattern, t);
                      });
          }

          /**
           * MessageFormat pattern of {1,string, strip}
           *
           * @return
           */
          public static StringFormat getStripInstance() {
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t).strip());
                      });
          }

          /**
           * MessageFormat pattern of {1,string, strip-trailing}
           *
           * @return
           */
          public static StringFormat getStripTrailingInstance() {
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t).stripTrailing());
                      });
          }

          /**
           * MessageFormat pattern of {1,string, to-lower}
           *
           * @param l
           * @return
           */
          public static StringFormat getToLowerInstance(Locale l) {
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t).toLowerCase(l));
                      });
          }

          /**
           * MessageFormat pattern of {1,string, to-upper}
           *
           * @param l
           * @return
           */
          public static StringFormat getToUpperInstance(Locale l) {
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t).toUpperCase(l));
                      });
          }

          /**
           * MessageFormat pattern of {1,string, left#n}
           *
           * @param n
           * @return
           */
          public static StringFormat getLeftInstance(int n) {
              if (n < 0) {
                  throw new IllegalArgumentException();
              }
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          if (!(t instanceof CharSequence)) {
                              t = String.valueOf(t);
                          }

                          //TODO: Handle mutation of c and code points.
                          CharSequence c = (CharSequence) t;
                          b.append(c, 0, Math.min(n, c.length()));
                      });
          }

          /**
           * MessageFormat pattern of {1,string, right#n}
           *
           * @param n
           * @return
           */
          public static StringFormat getRightInstance(int n) {
              if (n < 0) {
                  throw new IllegalArgumentException();
              }
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          if (!(t instanceof CharSequence)) {
                              t = String.valueOf(t);
                          }

                          //TODO: Handle mutation of c and code points.
                          CharSequence c = (CharSequence) t;
                          int l = c.length();
                          b.append(c, l - n, l);
                      });
          }

          /**
           * MessageFormat pattern of {1,string, indent#n}
           *
           * @param n
           * @return
           */
          public static StringFormat getIndentInstance(int n) {

              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t).indent(n));
                      });
          }

          /**
           * MessageFormat pattern of {1,replace, s/foo/bar/g}
           *
           * @param pattern s/foo/bar/g
           * @return
           */
          public static StringFormat getReplaceInstance(String pattern) {
              String[] split = perlMatchReplace(pattern);
              return new StringFormat(java.util.regex.Matcher.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(String.valueOf(t)
                                  .replace(split[1], split[2]));
                      });
          }

          /**
           * MessageFormat pattern of {1,replace-all, s/foo/bar/g}
           *
           * @param pattern s/foo/bar/g
           * @return
           */
          public static StringFormat getReplaceAllInstance(String pattern) {
              String[] split = perlMatchReplace(pattern);
              Pattern p = Pattern.compile(split[1]);
              String r = split[2];
              return new StringFormat(java.util.regex.Matcher.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          if (!(t instanceof CharSequence)) {
                              t = String.valueOf(t);
                          }

                          b.append(p.matcher((CharSequence) t).replaceAll(r));
                      });
          }

          /**
           * MessageFormat pattern of {1,replace-first, s/foo/bar/g}
           *
           * @param pattern s/foo/bar/g
           * @return
           */
          public static StringFormat getReplaceFirstInstance(String pattern) {
              String[] split = perlMatchReplace(pattern);
              Pattern p = Pattern.compile(split[1]);
              String r = split[2];
              return new StringFormat(java.util.regex.Matcher.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          if (!(t instanceof CharSequence)) {
                              t = String.valueOf(t);
                          }

                          b.append(p.matcher((CharSequence) t).replaceFirst(r));
                      });
          }

          /**
           *
           * @param pattern message format of {1,split,regex}
           * @return
           */
          public static StringFormat getSplitInstance(String pattern) {
              return new StringFormat(String.class,
                      (BiConsumer<Object, StringBuffer> & Serializable) (t, b) -> {
                          b.append(Arrays.toString(String.valueOf(t).split(pattern)));
                      });
          }

          private static String[] perlMatchReplace(String pattern) {
              return pattern.split("/"); //TODO improve this.
          }

          public StringFormat(Class<?> type, BiConsumer<Object, StringBuffer> transform) {
              this.type = Objects.requireNonNull(type);
              this.transform = Objects.requireNonNull(transform);
          }

          public Class<?> getType() {
              return type;
          }

          @Override
          public StringBuffer format(Object o, StringBuffer sb, FieldPosition fp) {
              transform.accept(o, sb);
              //TODO deal with FieldPosition.
              return sb;
          }

          @Override
          public Object parseObject(String string, ParsePosition pp) {
              //Most things won't be able to transform back to original form.
              //However, padding operations would work for format and parse.
              throw new UnsupportedOperationException();
          }
      }


            naoto Naoto Sato
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: