[LANG-697] Add FormattableUtils class
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1095833 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 6358b8e..4bec62a 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -60,6 +60,7 @@
[LANG-676] Documented potential NPE if auto-boxing occurs for some BooleanUtils methods
[LANG-678] Add support for ConcurrentMap.putIfAbsent()
[LANG-692] Add hashCodeMulti varargs method
+ [LANG-697] Add FormattableUtils class
REMOVALS IN 3.0
===============
diff --git a/src/main/java/org/apache/commons/lang3/util/FormattableUtils.java b/src/main/java/org/apache/commons/lang3/util/FormattableUtils.java
new file mode 100644
index 0000000..93d0ef1
--- /dev/null
+++ b/src/main/java/org/apache/commons/lang3/util/FormattableUtils.java
@@ -0,0 +1,141 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.util;
+
+import static java.util.FormattableFlags.LEFT_JUSTIFY;
+
+import java.util.Formattable;
+import java.util.Formatter;
+
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.Validate;
+
+/**
+ * Provides utilities for working with {@link Formattable}s.
+ *
+ * @since Lang 3.0
+ * @version $Id$
+ */
+public class FormattableUtils {
+
+ private static final String SIMPLEST_FORMAT = "%1$s";
+
+ /**
+ * <p>{@link FormattableUtils} instances should NOT be constructed in
+ * standard programming. Instead, the methods of the class should be invoked
+ * statically.</p>
+ *
+ * <p>This constructor is public to permit tools that require a JavaBean
+ * instance to operate.</p>
+ */
+ public FormattableUtils() {
+ super();
+ }
+
+ /**
+ * Get the default formatted representation of the specified
+ * {@link Formattable}.
+ *
+ * @param formattable
+ * @return String
+ */
+ public static String toString(Formattable formattable) {
+ return String.format(SIMPLEST_FORMAT, formattable);
+ }
+
+ /**
+ * Handles the common {@link Formattable} operations of truncate-pad-append,
+ * with no ellipsis on precision overflow, and padding width underflow with
+ * spaces.
+ *
+ * @param seq to handle
+ * @param formatter destination
+ * @param flags for formatting
+ * @param width of output
+ * @param precision of output
+ * @return {@code formatter}
+ */
+ public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
+ int precision) {
+ return append(seq, formatter, flags, width, precision, ' ', null);
+ }
+
+ /**
+ * Handles the common {@link Formattable} operations of truncate-pad-append,
+ * with no ellipsis on precision overflow.
+ *
+ * @param seq to handle
+ * @param formatter destination
+ * @param flags for formatting
+ * @param width of output
+ * @param precision of output
+ * @param padChar to use
+ * @return {@code formatter}
+ */
+ public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
+ int precision, char padChar) {
+ return append(seq, formatter, flags, width, precision, padChar, null);
+ }
+
+ /**
+ * Handles the common {@link Formattable} operations of truncate-pad-append,
+ * padding width underflow with spaces.
+ *
+ * @param seq to handle
+ * @param formatter destination
+ * @param flags for formatting
+ * @param width of output
+ * @param precision of output
+ * @param ellipsis to use when precision dictates truncation; a {@code null}
+ * or empty value causes a hard truncation
+ * @return {@code formatter}
+ */
+ public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
+ int precision, CharSequence ellipsis) {
+ return append(seq, formatter, flags, width, precision, ' ', ellipsis);
+ }
+
+ /**
+ * Handles the common {@link Formattable} operations of truncate-pad-append.
+ *
+ * @param seq to handle
+ * @param formatter destination
+ * @param flags for formatting
+ * @param width of output
+ * @param precision of output
+ * @param padChar to use
+ * @param ellipsis to use when precision dictates truncation; a {@code null}
+ * or empty value causes a hard truncation
+ * @return {@code formatter}
+ */
+ public static Formatter append(CharSequence seq, Formatter formatter, int flags, int width,
+ int precision, char padChar, CharSequence ellipsis) {
+ Validate.isTrue(ellipsis == null || precision < 0 || ellipsis.length() <= precision,
+ "Specified ellipsis '%1$s' exceeds precision of %2$s", ellipsis, precision);
+ StringBuilder buf = new StringBuilder(seq);
+ if (precision >= 0 && precision < seq.length()) {
+ CharSequence _ellipsis = ObjectUtils.defaultIfNull(ellipsis, "");
+ buf.replace(precision - _ellipsis.length(), seq.length(), _ellipsis.toString());
+ }
+ boolean leftJustify = (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY;
+ for (int i = buf.length(); i < width; i++) {
+ buf.insert(leftJustify ? i : 0, padChar);
+ }
+ formatter.format(buf.toString());
+ return formatter;
+ }
+}
diff --git a/src/test/java/org/apache/commons/lang3/util/FormattableUtilsTest.java b/src/test/java/org/apache/commons/lang3/util/FormattableUtilsTest.java
new file mode 100644
index 0000000..0c91a2b
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/util/FormattableUtilsTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.lang3.util;
+
+import static java.util.FormattableFlags.LEFT_JUSTIFY;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Formatter;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.junit.Test;
+
+/**
+ * Unit tests {@link FormattableUtils}.
+ *
+ * @version $Id$
+ */
+public class FormattableUtilsTest {
+
+ @Test
+ public void testDefaultAppend() {
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1).toString());
+ assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2).toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1).toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1).toString());
+ assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2).toString());
+ assertEquals(" fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2).toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1).toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1).toString());
+ assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2).toString());
+ assertEquals("fo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2).toString());
+ }
+
+ @Test
+ public void testAlternatePadCharacter() {
+ char pad='_';
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, pad).toString());
+ assertEquals("fo", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, pad).toString());
+ assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, pad).toString());
+ assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, pad).toString());
+ assertEquals("_fo", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, pad).toString());
+ assertEquals("___fo", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, pad).toString());
+ assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, pad).toString());
+ assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, pad).toString());
+ assertEquals("fo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, pad).toString());
+ assertEquals("fo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, pad).toString());
+ }
+
+ @Test
+ public void testEllipsis() {
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "*").toString());
+ assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "*").toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "*").toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "*").toString());
+ assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "*").toString());
+ assertEquals(" f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "*").toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "*").toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "*").toString());
+ assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "*").toString());
+ assertEquals("f* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "*").toString());
+
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, "+*").toString());
+ assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, "+*").toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, "+*").toString());
+ assertEquals(" foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, "+*").toString());
+ assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, "+*").toString());
+ assertEquals(" +*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, "+*").toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, "+*").toString());
+ assertEquals("foo ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, "+*").toString());
+ assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, "+*").toString());
+ assertEquals("+* ", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, "+*").toString());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testIllegalEllipsis() {
+ FormattableUtils.append("foo", new Formatter(), 0, -1, 1, "xx");
+ }
+
+ @Test
+ public void testAlternatePadCharAndEllipsis() {
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "*").toString());
+ assertEquals("f*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "*").toString());
+ assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "*").toString());
+ assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "*").toString());
+ assertEquals("_f*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "*").toString());
+ assertEquals("___f*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "*").toString());
+ assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "*").toString());
+ assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "*").toString());
+ assertEquals("f*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "*").toString());
+ assertEquals("f*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "*").toString());
+
+ assertEquals("foo", FormattableUtils.append("foo", new Formatter(), 0, -1, -1, '_', "+*").toString());
+ assertEquals("+*", FormattableUtils.append("foo", new Formatter(), 0, -1, 2, '_', "+*").toString());
+ assertEquals("_foo", FormattableUtils.append("foo", new Formatter(), 0, 4, -1, '_', "+*").toString());
+ assertEquals("___foo", FormattableUtils.append("foo", new Formatter(), 0, 6, -1, '_', "+*").toString());
+ assertEquals("_+*", FormattableUtils.append("foo", new Formatter(), 0, 3, 2, '_', "+*").toString());
+ assertEquals("___+*", FormattableUtils.append("foo", new Formatter(), 0, 5, 2, '_', "+*").toString());
+ assertEquals("foo_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 4, -1, '_', "+*").toString());
+ assertEquals("foo___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 6, -1, '_', "+*").toString());
+ assertEquals("+*_", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 3, 2, '_', "+*").toString());
+ assertEquals("+*___", FormattableUtils.append("foo", new Formatter(), LEFT_JUSTIFY, 5, 2, '_', "+*").toString());
+ }
+
+ @Test
+ public void testToStringFormattable() {
+ assertEquals("(Key,Value)", FormattableUtils.toString(Pair.of("Key", "Value")));
+ }
+}