blob: 8b7c789a37ea48d306ddc222eb3ad364c2392e12 [file] [log] [blame]
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" lang="en"><head><meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/><link rel="stylesheet" href="../../jacoco-resources/report.css" type="text/css"/><link rel="shortcut icon" href="../../jacoco-resources/report.gif" type="image/gif"/><title>StringUtils.java</title><link rel="stylesheet" href="../../jacoco-resources/prettify.css" type="text/css"/><script type="text/javascript" src="../../jacoco-resources/prettify.js"></script></head><body onload="window['PR_TAB_WIDTH']=4;prettyPrint()"><div class="breadcrumb" id="breadcrumb"><span class="info"><a href="../../jacoco-sessions.html" class="el_session">Sessions</a></span><a href="../../index.html" class="el_report">Apache Shiro :: Test Coverage</a> &gt; <a href="../index.html" class="el_bundle">shiro-lang</a> &gt; <a href="index.source.html" class="el_package">org.apache.shiro.util</a> &gt; <span class="el_source">StringUtils.java</span></div><h1>StringUtils.java</h1><pre class="source lang-java linenums">/*
* 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
* &quot;License&quot;); 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
* &quot;AS IS&quot; 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.shiro.util;
import java.text.ParseException;
import java.util.*;
/**
* &lt;p&gt;Simple utility class for String operations useful across the framework.
* &lt;p/&gt;
* &lt;p&gt;Some methods in this class were copied from the Spring Framework so we didn't have to re-invent the wheel,
* and in these cases, we have retained all license, copyright and author information.
*
* @since 0.9
*/
<span class="nc" id="L32">public class StringUtils {</span>
//TODO - complete JavaDoc
/**
* Constant representing the empty string, equal to &amp;quot;&amp;quot;
*/
public static final String EMPTY_STRING = &quot;&quot;;
/**
* Constant representing the default delimiter character (comma), equal to &lt;code&gt;','&lt;/code&gt;
*/
public static final char DEFAULT_DELIMITER_CHAR = ',';
/**
* Constant representing the default quote character (double quote), equal to '&amp;quot;'&lt;/code&gt;
*/
public static final char DEFAULT_QUOTE_CHAR = '&quot;';
/**
* Check whether the given String has actual text.
* More specifically, returns &lt;code&gt;true&lt;/code&gt; if the string not &lt;code&gt;null&lt;/code&gt;,
* its length is greater than 0, and it contains at least one non-whitespace character.
* &lt;p/&gt;
* &lt;code&gt;StringUtils.hasText(null) == false&lt;br/&gt;
* StringUtils.hasText(&quot;&quot;) == false&lt;br/&gt;
* StringUtils.hasText(&quot; &quot;) == false&lt;br/&gt;
* StringUtils.hasText(&quot;12345&quot;) == true&lt;br/&gt;
* StringUtils.hasText(&quot; 12345 &quot;) == true&lt;/code&gt;
* &lt;p/&gt;
* &lt;p&gt;Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param str the String to check (may be &lt;code&gt;null&lt;/code&gt;)
* @return &lt;code&gt;true&lt;/code&gt; if the String is not &lt;code&gt;null&lt;/code&gt;, its length is
* greater than 0, and it does not contain whitespace only
* @see java.lang.Character#isWhitespace
*/
public static boolean hasText(String str) {
<span class="fc bfc" id="L70" title="All 2 branches covered."> if (!hasLength(str)) {</span>
<span class="fc" id="L71"> return false;</span>
}
<span class="fc" id="L73"> int strLen = str.length();</span>
<span class="fc bfc" id="L74" title="All 2 branches covered."> for (int i = 0; i &lt; strLen; i++) {</span>
<span class="fc bfc" id="L75" title="All 2 branches covered."> if (!Character.isWhitespace(str.charAt(i))) {</span>
<span class="fc" id="L76"> return true;</span>
}
}
<span class="fc" id="L79"> return false;</span>
}
/**
* Check that the given String is neither &lt;code&gt;null&lt;/code&gt; nor of length 0.
* Note: Will return &lt;code&gt;true&lt;/code&gt; for a String that purely consists of whitespace.
* &lt;p/&gt;
* &lt;code&gt;StringUtils.hasLength(null) == false&lt;br/&gt;
* StringUtils.hasLength(&quot;&quot;) == false&lt;br/&gt;
* StringUtils.hasLength(&quot; &quot;) == true&lt;br/&gt;
* StringUtils.hasLength(&quot;Hello&quot;) == true&lt;/code&gt;
* &lt;p/&gt;
* Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param str the String to check (may be &lt;code&gt;null&lt;/code&gt;)
* @return &lt;code&gt;true&lt;/code&gt; if the String is not null and has length
* @see #hasText(String)
*/
public static boolean hasLength(String str) {
<span class="fc bfc" id="L98" title="All 4 branches covered."> return (str != null &amp;&amp; str.length() &gt; 0);</span>
}
/**
* Test if the given String starts with the specified prefix,
* ignoring upper/lower case.
* &lt;p/&gt;
* &lt;p&gt;Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param str the String to check
* @param prefix the prefix to look for
* @return &lt;code&gt;true&lt;/code&gt; starts with the specified prefix (ignoring case), &lt;code&gt;false&lt;/code&gt; if it does not.
* @see java.lang.String#startsWith
*/
public static boolean startsWithIgnoreCase(String str, String prefix) {
<span class="pc bpc" id="L114" title="1 of 4 branches missed."> if (str == null || prefix == null) {</span>
<span class="fc" id="L115"> return false;</span>
}
<span class="fc bfc" id="L117" title="All 2 branches covered."> if (str.startsWith(prefix)) {</span>
<span class="fc" id="L118"> return true;</span>
}
<span class="pc bpc" id="L120" title="1 of 2 branches missed."> if (str.length() &lt; prefix.length()) {</span>
<span class="nc" id="L121"> return false;</span>
}
<span class="fc" id="L123"> String lcStr = str.substring(0, prefix.length()).toLowerCase();</span>
<span class="fc" id="L124"> String lcPrefix = prefix.toLowerCase();</span>
<span class="fc" id="L125"> return lcStr.equals(lcPrefix);</span>
}
/**
* Returns a 'cleaned' representation of the specified argument. 'Cleaned' is defined as the following:
* &lt;p/&gt;
* &lt;ol&gt;
* &lt;li&gt;If the specified &lt;code&gt;String&lt;/code&gt; is &lt;code&gt;null&lt;/code&gt;, return &lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
* &lt;li&gt;If not &lt;code&gt;null&lt;/code&gt;, {@link String#trim() trim()} it.&lt;/li&gt;
* &lt;li&gt;If the trimmed string is equal to the empty String (i.e. &amp;quot;&amp;quot;), return &lt;code&gt;null&lt;/code&gt;&lt;/li&gt;
* &lt;li&gt;If the trimmed string is not the empty string, return the trimmed version&lt;/li&gt;.
* &lt;/ol&gt;
* &lt;p/&gt;
* Therefore this method always ensures that any given string has trimmed text, and if it doesn't, &lt;code&gt;null&lt;/code&gt;
* is returned.
*
* @param in the input String to clean.
* @return a populated-but-trimmed String or &lt;code&gt;null&lt;/code&gt; otherwise
*/
public static String clean(String in) {
<span class="fc" id="L145"> String out = in;</span>
<span class="fc bfc" id="L147" title="All 2 branches covered."> if (in != null) {</span>
<span class="fc" id="L148"> out = in.trim();</span>
<span class="fc bfc" id="L149" title="All 2 branches covered."> if (out.equals(EMPTY_STRING)) {</span>
<span class="fc" id="L150"> out = null;</span>
}
}
<span class="fc" id="L154"> return out;</span>
}
/**
* Returns the specified array as a comma-delimited (',') string.
*
* @param array the array whose contents will be converted to a string.
* @return the array's contents as a comma-delimited (',') string.
* @since 1.0
*/
public static String toString(Object[] array) {
<span class="fc" id="L165"> return toDelimitedString(array, &quot;,&quot;);</span>
}
/**
* Returns the array's contents as a string, with each element delimited by the specified
* {@code delimiter} argument. Useful for {@code toString()} implementations and log messages.
*
* @param array the array whose contents will be converted to a string
* @param delimiter the delimiter to use between each element
* @return a single string, delimited by the specified {@code delimiter}.
* @since 1.0
*/
public static String toDelimitedString(Object[] array, String delimiter) {
<span class="pc bpc" id="L178" title="2 of 4 branches missed."> if (array == null || array.length == 0) {</span>
<span class="nc" id="L179"> return EMPTY_STRING;</span>
}
<span class="fc" id="L181"> StringBuilder sb = new StringBuilder();</span>
<span class="fc bfc" id="L182" title="All 2 branches covered."> for (int i = 0; i &lt; array.length; i++) {</span>
<span class="fc bfc" id="L183" title="All 2 branches covered."> if (i &gt; 0) {</span>
<span class="fc" id="L184"> sb.append(delimiter);</span>
}
<span class="fc" id="L186"> sb.append(array[i]);</span>
}
<span class="fc" id="L188"> return sb.toString();</span>
}
/**
* Returns the collection's contents as a string, with each element delimited by the specified
* {@code delimiter} argument. Useful for {@code toString()} implementations and log messages.
*
* @param c the collection whose contents will be converted to a string
* @param delimiter the delimiter to use between each element
* @return a single string, delimited by the specified {@code delimiter}.
* @since 1.2
*/
public static String toDelimitedString(Collection c, String delimiter) {
<span class="nc bnc" id="L201" title="All 4 branches missed."> if (c == null || c.isEmpty()) {</span>
<span class="nc" id="L202"> return EMPTY_STRING;</span>
}
<span class="nc" id="L204"> return join(c.iterator(), delimiter);</span>
}
/**
* Tokenize the given String into a String array via a StringTokenizer.
* Trims tokens and omits empty tokens.
* &lt;p&gt;The given delimiters string is supposed to consist of any number of
* delimiter characters. Each of those characters can be used to separate
* tokens. A delimiter is always a single character; for multi-character
* delimiters, consider using &lt;code&gt;delimitedListToStringArray&lt;/code&gt;
* &lt;p/&gt;
* &lt;p&gt;Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param str the String to tokenize
* @param delimiters the delimiter characters, assembled as String
* (each of those characters is individually considered as delimiter).
* @return an array of the tokens
* @see java.util.StringTokenizer
* @see java.lang.String#trim()
*/
public static String[] tokenizeToStringArray(String str, String delimiters) {
<span class="fc" id="L225"> return tokenizeToStringArray(str, delimiters, true, true);</span>
}
/**
* Tokenize the given String into a String array via a StringTokenizer.
* &lt;p&gt;The given delimiters string is supposed to consist of any number of
* delimiter characters. Each of those characters can be used to separate
* tokens. A delimiter is always a single character; for multi-character
* delimiters, consider using &lt;code&gt;delimitedListToStringArray&lt;/code&gt;
* &lt;p/&gt;
* &lt;p&gt;Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param str the String to tokenize
* @param delimiters the delimiter characters, assembled as String
* (each of those characters is individually considered as delimiter)
* @param trimTokens trim the tokens via String's &lt;code&gt;trim&lt;/code&gt;
* @param ignoreEmptyTokens omit empty tokens from the result array
* (only applies to tokens that are empty after trimming; StringTokenizer
* will not consider subsequent delimiters as token in the first place).
* @return an array of the tokens (&lt;code&gt;null&lt;/code&gt; if the input String
* was &lt;code&gt;null&lt;/code&gt;)
* @see java.util.StringTokenizer
* @see java.lang.String#trim()
*/
@SuppressWarnings({&quot;unchecked&quot;})
public static String[] tokenizeToStringArray(
String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
<span class="pc bpc" id="L253" title="1 of 2 branches missed."> if (str == null) {</span>
<span class="nc" id="L254"> return null;</span>
}
<span class="fc" id="L256"> StringTokenizer st = new StringTokenizer(str, delimiters);</span>
<span class="fc" id="L257"> List tokens = new ArrayList();</span>
<span class="fc bfc" id="L258" title="All 2 branches covered."> while (st.hasMoreTokens()) {</span>
<span class="fc" id="L259"> String token = st.nextToken();</span>
<span class="pc bpc" id="L260" title="1 of 2 branches missed."> if (trimTokens) {</span>
<span class="fc" id="L261"> token = token.trim();</span>
}
<span class="pc bpc" id="L263" title="2 of 4 branches missed."> if (!ignoreEmptyTokens || token.length() &gt; 0) {</span>
<span class="fc" id="L264"> tokens.add(token);</span>
}
<span class="fc" id="L266"> }</span>
<span class="fc" id="L267"> return toStringArray(tokens);</span>
}
/**
* Copy the given Collection into a String array.
* The Collection must contain String elements only.
* &lt;p/&gt;
* &lt;p&gt;Copied from the Spring Framework while retaining all license, copyright and author information.
*
* @param collection the Collection to copy
* @return the String array (&lt;code&gt;null&lt;/code&gt; if the passed-in
* Collection was &lt;code&gt;null&lt;/code&gt;)
*/
@SuppressWarnings({&quot;unchecked&quot;})
public static String[] toStringArray(Collection collection) {
<span class="pc bpc" id="L282" title="1 of 2 branches missed."> if (collection == null) {</span>
<span class="nc" id="L283"> return null;</span>
}
<span class="fc" id="L285"> return (String[]) collection.toArray(new String[collection.size()]);</span>
}
public static String[] splitKeyValue(String aLine) throws ParseException {
<span class="fc" id="L289"> String line = clean(aLine);</span>
<span class="pc bpc" id="L290" title="1 of 2 branches missed."> if (line == null) {</span>
<span class="nc" id="L291"> return null;</span>
}
<span class="fc" id="L293"> String[] split = line.split(&quot; &quot;, 2);</span>
<span class="fc bfc" id="L294" title="All 2 branches covered."> if (split.length != 2) {</span>
//fallback to checking for an equals sign
<span class="fc" id="L296"> split = line.split(&quot;=&quot;, 2);</span>
<span class="pc bpc" id="L297" title="1 of 2 branches missed."> if (split.length != 2) {</span>
<span class="nc" id="L298"> String msg = &quot;Unable to determine Key/Value pair from line [&quot; + line + &quot;]. There is no space from &quot; +</span>
&quot;which the split location could be determined.&quot;;
<span class="nc" id="L300"> throw new ParseException(msg, 0);</span>
}
}
<span class="fc" id="L305"> split[0] = clean(split[0]);</span>
<span class="fc" id="L306"> split[1] = clean(split[1]);</span>
<span class="fc bfc" id="L307" title="All 2 branches covered."> if (split[1].startsWith(&quot;=&quot;)) {</span>
//they used spaces followed by an equals followed by zero or more spaces to split the key/value pair, so
//remove the equals sign to result in only the key and values in the
<span class="fc" id="L310"> split[1] = clean(split[1].substring(1));</span>
}
<span class="pc bpc" id="L313" title="1 of 2 branches missed."> if (split[0] == null) {</span>
<span class="nc" id="L314"> String msg = &quot;No valid key could be found in line [&quot; + line + &quot;] to form a key/value pair.&quot;;</span>
<span class="nc" id="L315"> throw new ParseException(msg, 0);</span>
}
<span class="pc bpc" id="L317" title="1 of 2 branches missed."> if (split[1] == null) {</span>
<span class="nc" id="L318"> String msg = &quot;No corresponding value could be found in line [&quot; + line + &quot;] for key [&quot; + split[0] + &quot;]&quot;;</span>
<span class="nc" id="L319"> throw new ParseException(msg, 0);</span>
}
<span class="fc" id="L322"> return split;</span>
}
public static String[] split(String line) {
<span class="fc" id="L326"> return split(line, DEFAULT_DELIMITER_CHAR);</span>
}
public static String[] split(String line, char delimiter) {
<span class="fc" id="L330"> return split(line, delimiter, DEFAULT_QUOTE_CHAR);</span>
}
public static String[] split(String line, char delimiter, char quoteChar) {
<span class="fc" id="L334"> return split(line, delimiter, quoteChar, quoteChar);</span>
}
public static String[] split(String line, char delimiter, char beginQuoteChar, char endQuoteChar) {
<span class="fc" id="L338"> return split(line, delimiter, beginQuoteChar, endQuoteChar, false, true);</span>
}
/**
* Splits the specified delimited String into tokens, supporting quoted tokens so that quoted strings themselves
* won't be tokenized.
* &lt;p/&gt;
* This method's implementation is very loosely based (with significant modifications) on
* &lt;a href=&quot;http://blogs.bytecode.com.au/glen&quot;&gt;Glen Smith&lt;/a&gt;'s open-source
* &lt;a href=&quot;http://opencsv.svn.sourceforge.net/viewvc/opencsv/trunk/src/au/com/bytecode/opencsv/CSVReader.java?&amp;view=markup&quot;&gt;CSVReader.java&lt;/a&gt;
* file.
* &lt;p/&gt;
* That file is Apache 2.0 licensed as well, making Glen's code a great starting point for us to modify to
* our needs.
*
* @param aLine the String to parse
* @param delimiter the delimiter by which the &lt;tt&gt;line&lt;/tt&gt; argument is to be split
* @param beginQuoteChar the character signifying the start of quoted text (so the quoted text will not be split)
* @param endQuoteChar the character signifying the end of quoted text
* @param retainQuotes if the quotes themselves should be retained when constructing the corresponding token
* @param trimTokens if leading and trailing whitespace should be trimmed from discovered tokens.
* @return the tokens discovered from parsing the given delimited &lt;tt&gt;line&lt;/tt&gt;.
*/
public static String[] split(String aLine, char delimiter, char beginQuoteChar, char endQuoteChar,
boolean retainQuotes, boolean trimTokens) {
<span class="fc" id="L363"> String line = clean(aLine);</span>
<span class="fc bfc" id="L364" title="All 2 branches covered."> if (line == null) {</span>
<span class="fc" id="L365"> return null;</span>
}
<span class="fc" id="L368"> List&lt;String&gt; tokens = new ArrayList&lt;String&gt;();</span>
<span class="fc" id="L369"> StringBuilder sb = new StringBuilder();</span>
<span class="fc" id="L370"> boolean inQuotes = false;</span>
<span class="fc bfc" id="L372" title="All 2 branches covered."> for (int i = 0; i &lt; line.length(); i++) {</span>
<span class="fc" id="L374"> char c = line.charAt(i);</span>
<span class="fc bfc" id="L375" title="All 2 branches covered."> if (c == beginQuoteChar) {</span>
// this gets complex... the quote may end a quoted block, or escape another quote.
// do a 1-char lookahead:
<span class="fc bfc" id="L378" title="All 2 branches covered."> if (inQuotes // we are in quotes, therefore there can be escaped quotes in here.</span>
<span class="fc bfc" id="L379" title="All 2 branches covered."> &amp;&amp; line.length() &gt; (i + 1) // there is indeed another character to check.</span>
<span class="fc bfc" id="L380" title="All 2 branches covered."> &amp;&amp; line.charAt(i + 1) == beginQuoteChar) { // ..and that char. is a quote also.</span>
// we have two quote chars in a row == one quote char, so consume them both and
// put one on the token. we do *not* exit the quoted text.
<span class="fc" id="L383"> sb.append(line.charAt(i + 1));</span>
<span class="fc" id="L384"> i++;</span>
} else {
<span class="fc bfc" id="L386" title="All 2 branches covered."> inQuotes = !inQuotes;</span>
<span class="fc bfc" id="L387" title="All 2 branches covered."> if (retainQuotes) {</span>
<span class="fc" id="L388"> sb.append(c);</span>
}
}
<span class="fc bfc" id="L391" title="All 2 branches covered."> } else if (c == endQuoteChar) {</span>
<span class="pc bpc" id="L392" title="1 of 2 branches missed."> inQuotes = !inQuotes;</span>
<span class="fc bfc" id="L393" title="All 2 branches covered."> if (retainQuotes) {</span>
<span class="fc" id="L394"> sb.append(c);</span>
}
<span class="fc bfc" id="L396" title="All 4 branches covered."> } else if (c == delimiter &amp;&amp; !inQuotes) {</span>
<span class="fc" id="L397"> String s = sb.toString();</span>
<span class="pc bpc" id="L398" title="1 of 2 branches missed."> if (trimTokens) {</span>
<span class="fc" id="L399"> s = s.trim();</span>
}
<span class="fc" id="L401"> tokens.add(s);</span>
<span class="fc" id="L402"> sb = new StringBuilder(); // start work on next token</span>
<span class="fc" id="L403"> } else {</span>
<span class="fc" id="L404"> sb.append(c);</span>
}
}
<span class="fc" id="L407"> String s = sb.toString();</span>
<span class="pc bpc" id="L408" title="1 of 2 branches missed."> if (trimTokens) {</span>
<span class="fc" id="L409"> s = s.trim();</span>
}
<span class="fc" id="L411"> tokens.add(s);</span>
<span class="fc" id="L412"> return tokens.toArray(new String[tokens.size()]);</span>
}
/**
* Joins the elements of the provided {@code Iterator} into
* a single String containing the provided elements.&lt;/p&gt;
* &lt;p/&gt;
* No delimiter is added before or after the list.
* A {@code null} separator is the same as an empty String (&quot;&quot;).&lt;/p&gt;
* &lt;p/&gt;
* Copied from Commons Lang, version 3 (r1138702).&lt;/p&gt;
*
* @param iterator the {@code Iterator} of values to join together, may be null
* @param separator the separator character to use, null treated as &quot;&quot;
* @return the joined String, {@code null} if null iterator input
* @since 1.2
*/
public static String join(Iterator&lt;?&gt; iterator, String separator) {
<span class="nc" id="L430"> final String empty = &quot;&quot;;</span>
// handle null, zero and one elements before building a buffer
<span class="nc bnc" id="L433" title="All 2 branches missed."> if (iterator == null) {</span>
<span class="nc" id="L434"> return null;</span>
}
<span class="nc bnc" id="L436" title="All 2 branches missed."> if (!iterator.hasNext()) {</span>
<span class="nc" id="L437"> return empty;</span>
}
<span class="nc" id="L439"> Object first = iterator.next();</span>
<span class="nc bnc" id="L440" title="All 2 branches missed."> if (!iterator.hasNext()) {</span>
<span class="nc bnc" id="L441" title="All 2 branches missed."> return first == null ? empty : first.toString();</span>
}
// two or more elements
<span class="nc" id="L445"> StringBuilder buf = new StringBuilder(256); // Java default is 16, probably too small</span>
<span class="nc bnc" id="L446" title="All 2 branches missed."> if (first != null) {</span>
<span class="nc" id="L447"> buf.append(first);</span>
}
<span class="nc bnc" id="L450" title="All 2 branches missed."> while (iterator.hasNext()) {</span>
<span class="nc bnc" id="L451" title="All 2 branches missed."> if (separator != null) {</span>
<span class="nc" id="L452"> buf.append(separator);</span>
}
<span class="nc" id="L454"> Object obj = iterator.next();</span>
<span class="nc bnc" id="L455" title="All 2 branches missed."> if (obj != null) {</span>
<span class="nc" id="L456"> buf.append(obj);</span>
}
<span class="nc" id="L458"> }</span>
<span class="nc" id="L459"> return buf.toString();</span>
}
/**
* Splits the {@code delimited} string (delimited by the specified {@code separator} character) and returns the
* delimited values as a {@code Set}.
* &lt;p/&gt;
* If either argument is {@code null}, this method returns {@code null}.
*
* @param delimited the string to split
* @param separator the character that delineates individual tokens to split
* @return the delimited values as a {@code Set}.
* @since 1.2
*/
public static Set&lt;String&gt; splitToSet(String delimited, String separator) {
<span class="pc bpc" id="L474" title="2 of 4 branches missed."> if (delimited == null || separator == null) {</span>
<span class="nc" id="L475"> return null;</span>
}
<span class="fc" id="L477"> String[] split = split(delimited, separator.charAt(0));</span>
<span class="fc" id="L478"> return asSet(split);</span>
}
/**
* Returns the input argument, but ensures the first character is capitalized (if possible).
* @param in the string to uppercase the first character.
* @return the input argument, but with the first character capitalized (if possible).
* @since 1.2
*/
public static String uppercaseFirstChar(String in) {
<span class="pc bpc" id="L488" title="2 of 4 branches missed."> if (in == null || in.length() == 0) {</span>
<span class="nc" id="L489"> return in;</span>
}
<span class="fc" id="L491"> int length = in.length();</span>
<span class="fc" id="L492"> StringBuilder sb = new StringBuilder(length);</span>
<span class="fc" id="L494"> sb.append(Character.toUpperCase(in.charAt(0)));</span>
<span class="pc bpc" id="L495" title="1 of 2 branches missed."> if (length &gt; 1) {</span>
<span class="fc" id="L496"> String remaining = in.substring(1);</span>
<span class="fc" id="L497"> sb.append(remaining);</span>
}
<span class="fc" id="L499"> return sb.toString();</span>
}
//////////////////////////
// From CollectionUtils //
//////////////////////////
// CollectionUtils cannot be removed from shiro-core until 2.0 as it has a dependency on PrincipalCollection
private static &lt;E&gt; Set&lt;E&gt; asSet(E... elements) {
<span class="pc bpc" id="L509" title="2 of 4 branches missed."> if (elements == null || elements.length == 0) {</span>
<span class="nc" id="L510"> return Collections.emptySet();</span>
}
<span class="fc bfc" id="L513" title="All 2 branches covered."> if (elements.length == 1) {</span>
<span class="fc" id="L514"> return Collections.singleton(elements[0]);</span>
}
<span class="fc" id="L517"> LinkedHashSet&lt;E&gt; set = new LinkedHashSet&lt;E&gt;(elements.length * 4 / 3 + 1);</span>
<span class="fc" id="L518"> Collections.addAll(set, elements);</span>
<span class="fc" id="L519"> return set;</span>
}
}
</pre><div class="footer"><span class="right">Created with <a href="http://www.jacoco.org/jacoco">JaCoCo</a> 0.8.3.201901230119</span></div></body></html>