LANG-1093: Add ClassUtils.getAbbreviatedName(). This fixes #48 from github. Thanks to Fabian Lange.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1666362 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Benedikt Ritter 2015-03-13 07:29:21 +00:00
parent ce7f4ed073
commit d38919fcbd
3 changed files with 118 additions and 0 deletions

View File

@ -22,6 +22,7 @@
<body>
<release version="3.4" date="tba" description="tba">
<action issue="LANG-1093" type="add" dev="britter" due-to="Fabian Lange">Add ClassUtils.getAbbreviatedName()</action>
<action issue="LANG-1090" type="fix" dev="sebb">FastDateParser does not set error indication in ParsePosition</action>
<action issue="LANG-1089" type="fix" dev="sebb">FastDateParser does not handle excess hours as per SimpleDateFormat</action>
<action issue="LANG-1061" type="fix" dev="sebb" due-to="dmeneses">FastDateParser error - timezones not handled correctly</action>

View File

@ -314,6 +314,87 @@ public class ClassUtils {
return className.substring(0, i);
}
// Abbreviated name
// ----------------------------------------------------------------------
/**
* <p>Gets the abbreviated name of a {@code Class}.</p>
*
* @param cls the class to get the abbreviated name for, may be {@code null}
* @param len the desired length of the abbreviated name
* @return the abbreviated name or an empty string
* @throws IllegalArgumentException if len <= 0
* @see getAbbreviatedName(String, int)
* @since 3.4
*/
public static String getAbbreviatedName(final Class<?> cls, int len) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getAbbreviatedName(cls.getName(), len);
}
/**
* <p>Gets the abbreviated class name from a {@code String}.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
*
* <p>The abbreviation algorithm will shorten the class name, usually without
* significant loss of meaning.</p>
* <p>The abbreviated class name will always include the complete package hierarchy.
* If enough space is available, rightmost sub-packages will be displayed in full
* length.</p>
*
* <p>The following table illustrates the algorithm:</p>
* <table>
* <tr><td>className</td><td>len</td><td>return</td></tr>
* <tr><td> null</td><td> 1</td><td>""</td></tr>
* <tr><td>"java.lang.String"</td><td> 5</td><td>"j.l.String"</td></tr>
* <tr><td>"java.lang.String"</td><td>15</td><td>"j.lang.String"</td></tr>
* <tr><td>"java.lang.String"</td><td>30</td><td>"java.lang.String"</td></tr>
* </table>
* @param className the className to get the abbreviated name for, may be {@code null}
* @param len the desired length of the abbreviated name
* @return the abbreviated name or an empty string
* @throws IllegalArgumentException if len <= 0
* @since 3.4
*/
public static String getAbbreviatedName(String className, int len) {
if (len <= 0) {
throw new IllegalArgumentException("len must be > 0");
}
if (className == null) {
return StringUtils.EMPTY;
}
int availableSpace = len;
int packageLevels = StringUtils.countMatches(className, '.');
String[] output = new String[packageLevels + 1];
int endIndex = className.length() - 1;
for (int level = packageLevels; level >= 0; level--) {
int startIndex = className.lastIndexOf('.', endIndex);
String part = className.substring(startIndex + 1, endIndex + 1);
availableSpace -= part.length();
if (level > 0) {
// all elements except top level require an additional char space
availableSpace--;
}
if (level == packageLevels) {
// ClassName is always complete
output[level] = part;
} else {
if (availableSpace > 0) {
output[level] = part;
} else {
// if no space is left still the first char is used
output[level] = part.substring(0, 1);
}
}
endIndex = startIndex - 1;
}
return StringUtils.join(output, '.');
}
// Superclasses/Superinterfaces
// ----------------------------------------------------------------------
/**

View File

@ -230,6 +230,42 @@ public class ClassUtilsTest {
assertEquals("", ClassUtils.getPackageName(""));
}
// -------------------------------------------------------------------------
@Test
public void test_getAbbreviatedName_Class() {
assertEquals("", ClassUtils.getAbbreviatedName((Class<?>)null, 1));
assertEquals("j.l.String", ClassUtils.getAbbreviatedName(String.class, 1));
assertEquals("j.l.String", ClassUtils.getAbbreviatedName(String.class, 5));
assertEquals("j.lang.String", ClassUtils.getAbbreviatedName(String.class, 13));
assertEquals("j.lang.String", ClassUtils.getAbbreviatedName(String.class, 15));
assertEquals("java.lang.String", ClassUtils.getAbbreviatedName(String.class, 20));
}
@Test
public void test_getAbbreviatedName_Class_Exceptions() {
try {
ClassUtils.getAbbreviatedName(String.class, 0);
fail("ClassUtils.getAbbreviatedName() should fail with an "
+ "IllegalArgumentException for a len value of 0.");
} catch (final Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
try {
ClassUtils.getAbbreviatedName(String.class, -10);
fail("ClassUtils.getAbbreviatedName() should fail with an "
+ "IllegalArgumentException for negative values of len.");
} catch (final Exception e) {
assertTrue(e instanceof IllegalArgumentException);
}
}
@Test
public void test_getAbbreviatedName_String() {
assertEquals("", ClassUtils.getAbbreviatedName((String)null, 1));
assertEquals("WithoutPackage", ClassUtils.getAbbreviatedName("WithoutPackage", 1));
assertEquals("j.l.String", ClassUtils.getAbbreviatedName("java.lang.String", 1));
}
// -------------------------------------------------------------------------
@Test
public void test_getAllSuperclasses_Class() {