1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.text;
18
19 import java.util.Formattable;
20 import java.util.Formatter;
21
22 import static java.util.FormattableFlags.LEFT_JUSTIFY;
23
24 /**
25 * <p>Provides utilities for working with the {@code Formattable} interface.</p>
26 *
27 * <p>The {@link Formattable} interface provides basic control over formatting
28 * when using a {@code Formatter}. It is primarily concerned with numeric precision
29 * and padding, and is not designed to allow generalised alternate formats.</p>
30 *
31 * @since 1.0
32 *
33 */
34 public class FormattableUtils {
35
36 /**
37 * A format that simply outputs the value as a string.
38 */
39 private static final String SIMPLEST_FORMAT = "%s";
40
41 /**
42 * <p>{@code FormattableUtils} instances should NOT be constructed in
43 * standard programming. Instead, the methods of the class should be invoked
44 * statically.</p>
45 *
46 * <p>This constructor is public to permit tools that require a JavaBean
47 * instance to operate.</p>
48 */
49 public FormattableUtils() {
50 super();
51 }
52
53 //-----------------------------------------------------------------------
54 /**
55 * Get the default formatted representation of the specified
56 * {@code Formattable}.
57 *
58 * @param formattable the instance to convert to a string, not null
59 * @return the resulting string, not null
60 */
61 public static String toString(final Formattable formattable) {
62 return String.format(SIMPLEST_FORMAT, formattable);
63 }
64
65 /**
66 * Handles the common {@code Formattable} operations of truncate-pad-append,
67 * with no ellipsis on precision overflow, and padding width underflow with
68 * spaces.
69 *
70 * @param seq the string to handle, not null
71 * @param formatter the destination formatter, not null
72 * @param flags the flags for formatting, see {@code Formattable}
73 * @param width the width of the output, see {@code Formattable}
74 * @param precision the precision of the output, see {@code Formattable}
75 * @return the {@code formatter} instance, not null
76 */
77 public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
78 final int precision) {
79 return append(seq, formatter, flags, width, precision, ' ', null);
80 }
81
82 /**
83 * Handles the common {@link Formattable} operations of truncate-pad-append,
84 * with no ellipsis on precision overflow.
85 *
86 * @param seq the string to handle, not null
87 * @param formatter the destination formatter, not null
88 * @param flags the flags for formatting, see {@code Formattable}
89 * @param width the width of the output, see {@code Formattable}
90 * @param precision the precision of the output, see {@code Formattable}
91 * @param padChar the pad character to use
92 * @return the {@code formatter} instance, not null
93 */
94 public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
95 final int precision, final char padChar) {
96 return append(seq, formatter, flags, width, precision, padChar, null);
97 }
98
99 /**
100 * Handles the common {@link Formattable} operations of truncate-pad-append,
101 * padding width underflow with spaces.
102 *
103 * @param seq the string to handle, not null
104 * @param formatter the destination formatter, not null
105 * @param flags the flags for formatting, see {@code Formattable}
106 * @param width the width of the output, see {@code Formattable}
107 * @param precision the precision of the output, see {@code Formattable}
108 * @param ellipsis the ellipsis to use when precision dictates truncation, null or
109 * empty causes a hard truncation
110 * @return the {@code formatter} instance, not null
111 */
112 public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
113 final int precision, final CharSequence ellipsis) {
114 return append(seq, formatter, flags, width, precision, ' ', ellipsis);
115 }
116
117 /**
118 * Handles the common {@link Formattable} operations of truncate-pad-append.
119 *
120 * @param seq the string to handle, not null
121 * @param formatter the destination formatter, not null
122 * @param flags the flags for formatting, see {@code Formattable}
123 * @param width the width of the output, see {@code Formattable}
124 * @param precision the precision of the output, see {@code Formattable}
125 * @param padChar the pad character to use
126 * @param ellipsis the ellipsis to use when precision dictates truncation, null or
127 * empty causes a hard truncation
128 * @return the {@code formatter} instance, not null
129 */
130 public static Formatter append(final CharSequence seq, final Formatter formatter, final int flags, final int width,
131 final int precision, final char padChar, final CharSequence ellipsis) {
132 if ( ! (ellipsis == null || precision < 0 || ellipsis.length() <= precision) ) {
133 throw new IllegalArgumentException(String.format("Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, Integer.valueOf(precision)));
134 }
135 final StringBuilder buf = new StringBuilder(seq);
136 if (precision >= 0 && precision < seq.length()) {
137 final CharSequence _ellipsis;
138 if (ellipsis == null) {
139 _ellipsis = "";
140 } else {
141 _ellipsis = ellipsis;
142 }
143 buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
144 }
145 final boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
146 for (int i = buf.length(); i < width; i++) {
147 buf.insert(leftJustify ? i : 0, padChar);
148 }
149 formatter.format(buf.toString());
150 return formatter;
151 }
152
153 }