You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
406 lines
14 KiB
406 lines
14 KiB
/* |
|
* Copyright 2011 the original author or authors. |
|
* Licensed 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 com.jayway.jsonpath.internal; |
|
|
|
import com.jayway.jsonpath.JsonPathException; |
|
|
|
import java.io.Closeable; |
|
import java.io.IOException; |
|
import java.io.StringWriter; |
|
import java.util.Iterator; |
|
|
|
public final class Utils { |
|
|
|
// accept a collection of objects, since all objects have toString() |
|
public static String join(String delimiter, String wrap, Iterable<? extends Object> objs) { |
|
Iterator<? extends Object> iter = objs.iterator(); |
|
if (!iter.hasNext()) { |
|
return ""; |
|
} |
|
StringBuilder buffer = new StringBuilder(); |
|
buffer.append(wrap).append(iter.next()).append(wrap); |
|
while (iter.hasNext()) { |
|
buffer.append(delimiter).append(wrap).append(iter.next()).append(wrap); |
|
} |
|
return buffer.toString(); |
|
} |
|
|
|
// accept a collection of objects, since all objects have toString() |
|
public static String join(String delimiter, Iterable<? extends Object> objs) { |
|
return join(delimiter, "", objs); |
|
} |
|
|
|
public static String concat(CharSequence... strings) { |
|
if (strings.length == 0) { |
|
return ""; |
|
} |
|
if (strings.length == 1) { |
|
return strings[0].toString(); |
|
} |
|
int length = 0; |
|
// -1 = no result, -2 = multiple results |
|
int indexOfSingleNonEmptyString = -1; |
|
for (int i = 0; i < strings.length; i++) { |
|
CharSequence charSequence = strings[i]; |
|
int len = charSequence.length(); |
|
length += len; |
|
if (indexOfSingleNonEmptyString != -2 && len > 0) { |
|
if (indexOfSingleNonEmptyString == -1) { |
|
indexOfSingleNonEmptyString = i; |
|
} else { |
|
indexOfSingleNonEmptyString = -2; |
|
} |
|
} |
|
} |
|
if (length == 0) { |
|
return ""; |
|
} |
|
if (indexOfSingleNonEmptyString > 0) { |
|
return strings[indexOfSingleNonEmptyString].toString(); |
|
} |
|
StringBuilder sb = new StringBuilder(length); |
|
for (CharSequence charSequence : strings) { |
|
sb.append(charSequence); |
|
} |
|
return sb.toString(); |
|
|
|
} |
|
|
|
//--------------------------------------------------------- |
|
// |
|
// IO |
|
// |
|
//--------------------------------------------------------- |
|
|
|
public static void closeQuietly(Closeable closeable) { |
|
try { |
|
if (closeable != null) { |
|
closeable.close(); |
|
} |
|
} catch (IOException ignore) { |
|
} |
|
} |
|
|
|
public static String escape(String str, boolean escapeSingleQuote) { |
|
if (str == null) { |
|
return null; |
|
} |
|
int len = str.length(); |
|
StringWriter writer = new StringWriter(len * 2); |
|
|
|
for (int i = 0; i < len; i++) { |
|
char ch = str.charAt(i); |
|
|
|
// handle unicode |
|
if (ch > 0xfff) { |
|
writer.write("\\u" + hex(ch)); |
|
} else if (ch > 0xff) { |
|
writer.write("\\u0" + hex(ch)); |
|
} else if (ch > 0x7f) { |
|
writer.write("\\u00" + hex(ch)); |
|
} else if (ch < 32) { |
|
switch (ch) { |
|
case '\b': |
|
writer.write('\\'); |
|
writer.write('b'); |
|
break; |
|
case '\n': |
|
writer.write('\\'); |
|
writer.write('n'); |
|
break; |
|
case '\t': |
|
writer.write('\\'); |
|
writer.write('t'); |
|
break; |
|
case '\f': |
|
writer.write('\\'); |
|
writer.write('f'); |
|
break; |
|
case '\r': |
|
writer.write('\\'); |
|
writer.write('r'); |
|
break; |
|
default : |
|
if (ch > 0xf) { |
|
writer.write("\\u00" + hex(ch)); |
|
} else { |
|
writer.write("\\u000" + hex(ch)); |
|
} |
|
break; |
|
} |
|
} else { |
|
switch (ch) { |
|
case '\'': |
|
if (escapeSingleQuote) { |
|
writer.write('\\'); |
|
} |
|
writer.write('\''); |
|
break; |
|
case '"': |
|
writer.write('\\'); |
|
writer.write('"'); |
|
break; |
|
case '\\': |
|
writer.write('\\'); |
|
writer.write('\\'); |
|
break; |
|
case '/': |
|
writer.write('\\'); |
|
writer.write('/'); |
|
break; |
|
default : |
|
writer.write(ch); |
|
break; |
|
} |
|
} |
|
} |
|
return writer.toString(); |
|
} |
|
|
|
public static String unescape(String str) { |
|
if (str == null) { |
|
return null; |
|
} |
|
int len = str.length(); |
|
StringWriter writer = new StringWriter(len); |
|
StringBuffer unicode = new StringBuffer(4); |
|
boolean hadSlash = false; |
|
boolean inUnicode = false; |
|
for (int i = 0; i < len; i++) { |
|
char ch = str.charAt(i); |
|
if (inUnicode) { |
|
unicode.append(ch); |
|
if (unicode.length() == 4) { |
|
try { |
|
int value = Integer.parseInt(unicode.toString(), 16); |
|
writer.write((char) value); |
|
unicode.setLength(0); |
|
inUnicode = false; |
|
hadSlash = false; |
|
} catch (NumberFormatException nfe) { |
|
throw new JsonPathException("Unable to parse unicode value: " + unicode, nfe); |
|
} |
|
} |
|
continue; |
|
} |
|
if (hadSlash) { |
|
hadSlash = false; |
|
switch (ch) { |
|
case '\\': |
|
writer.write('\\'); |
|
break; |
|
case '\'': |
|
writer.write('\''); |
|
break; |
|
case '\"': |
|
writer.write('"'); |
|
break; |
|
case 'r': |
|
writer.write('\r'); |
|
break; |
|
case 'f': |
|
writer.write('\f'); |
|
break; |
|
case 't': |
|
writer.write('\t'); |
|
break; |
|
case 'n': |
|
writer.write('\n'); |
|
break; |
|
case 'b': |
|
writer.write('\b'); |
|
break; |
|
case 'u': |
|
{ |
|
inUnicode = true; |
|
break; |
|
} |
|
default : |
|
writer.write(ch); |
|
break; |
|
} |
|
continue; |
|
} else if (ch == '\\') { |
|
hadSlash = true; |
|
continue; |
|
} |
|
writer.write(ch); |
|
} |
|
if (hadSlash) { |
|
writer.write('\\'); |
|
} |
|
return writer.toString(); |
|
} |
|
|
|
/** |
|
* Returns an upper case hexadecimal <code>String</code> for the given |
|
* character. |
|
* |
|
* @param ch The character to convert. |
|
* @return An upper case hexadecimal <code>String</code> |
|
*/ |
|
public static String hex(char ch) { |
|
return Integer.toHexString(ch).toUpperCase(); |
|
} |
|
|
|
/** |
|
* <p>Checks if a CharSequence is empty ("") or null.</p> |
|
* <p/> |
|
* <pre> |
|
* StringUtils.isEmpty(null) = true |
|
* StringUtils.isEmpty("") = true |
|
* StringUtils.isEmpty(" ") = false |
|
* StringUtils.isEmpty("bob") = false |
|
* StringUtils.isEmpty(" bob ") = false |
|
* </pre> |
|
* <p/> |
|
* <p>NOTE: This method changed in Lang version 2.0. |
|
* It no longer trims the CharSequence. |
|
* That functionality is available in isBlank().</p> |
|
* |
|
* @param cs the CharSequence to check, may be null |
|
* @return {@code true} if the CharSequence is empty or null |
|
* @since 3.0 Changed signature from isEmpty(String) to isEmpty(CharSequence) |
|
*/ |
|
public static boolean isEmpty(CharSequence cs) { |
|
return cs == null || cs.length() == 0; |
|
} |
|
|
|
/** |
|
* Used by the indexOf(CharSequence methods) as a green implementation of indexOf. |
|
* |
|
* @param cs the {@code CharSequence} to be processed |
|
* @param searchChar the {@code CharSequence} to be searched for |
|
* @param start the start index |
|
* @return the index where the search sequence was found |
|
*/ |
|
static int indexOf(CharSequence cs, CharSequence searchChar, int start) { |
|
return cs.toString().indexOf(searchChar.toString(), start); |
|
} |
|
|
|
|
|
|
|
//--------------------------------------------------------- |
|
// |
|
// Validators |
|
// |
|
//--------------------------------------------------------- |
|
|
|
/** |
|
* <p>Validate that the specified argument is not {@code null}; |
|
* otherwise throwing an exception with the specified message. |
|
* <p/> |
|
* <pre>Validate.notNull(myObject, "The object must not be null");</pre> |
|
* |
|
* @param <T> the object type |
|
* @param object the object to check |
|
* @param message the {@link String#format(String, Object...)} exception message if invalid, not null |
|
* @param values the optional values for the formatted exception message |
|
* @return the validated object (never {@code null} for method chaining) |
|
* @throws NullPointerException if the object is {@code null} |
|
*/ |
|
public static <T> T notNull(T object, String message, Object... values) { |
|
if (object == null) { |
|
throw new IllegalArgumentException(String.format(message, values)); |
|
} |
|
return object; |
|
} |
|
|
|
/** |
|
* <p>Validate that the argument condition is {@code true}; otherwise |
|
* throwing an exception with the specified message. This method is useful when |
|
* validating according to an arbitrary boolean expression, such as validating a |
|
* primitive number or using your own custom validation expression.</p> |
|
* <p/> |
|
* <pre>Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);</pre> |
|
* <p/> |
|
* <p>For performance reasons, the long value is passed as a separate parameter and |
|
* appended to the exception message only in the case of an error.</p> |
|
* |
|
* @param expression the boolean expression to check |
|
* @param message |
|
* @throws IllegalArgumentException if expression is {@code false} |
|
*/ |
|
public static void isTrue(boolean expression, String message) { |
|
if (expression == false) { |
|
throw new IllegalArgumentException(message); |
|
} |
|
} |
|
|
|
/** |
|
* Check if one and only one condition is true; otherwise |
|
* throw an exception with the specified message. |
|
* |
|
* @param message error describing message |
|
* @param expressions the boolean expressions to check |
|
* @throws IllegalArgumentException if zero or more than one expressions are true |
|
*/ |
|
public static void onlyOneIsTrue(final String message, final boolean... expressions) { |
|
if (!onlyOneIsTrueNonThrow(expressions)) { |
|
throw new IllegalArgumentException(message); |
|
} |
|
} |
|
|
|
public static boolean onlyOneIsTrueNonThrow(final boolean... expressions) { |
|
int count = 0; |
|
for (final boolean expression : expressions) { |
|
if (expression && ++count > 1) { |
|
return false; |
|
} |
|
} |
|
return 1 == count; |
|
} |
|
|
|
/** |
|
* <p>Validate that the specified argument character sequence is |
|
* neither {@code null} nor a length of zero (no characters); |
|
* otherwise throwing an exception with the specified message. |
|
* <p/> |
|
* <pre>Validate.notEmpty(myString, "The string must not be empty");</pre> |
|
* |
|
* @param <T> the character sequence type |
|
* @param chars the character sequence to check, validated not null by this method |
|
* @param message the {@link String#format(String, Object...)} exception message if invalid, not null |
|
* @param values the optional values for the formatted exception message, null array not recommended |
|
* @return the validated character sequence (never {@code null} method for chaining) |
|
* @throws NullPointerException if the character sequence is {@code null} |
|
* @throws IllegalArgumentException if the character sequence is empty |
|
*/ |
|
public static <T extends CharSequence> T notEmpty(T chars, String message, Object... values) { |
|
if (chars == null) { |
|
throw new IllegalArgumentException(String.format(message, values)); |
|
} |
|
if (chars.length() == 0) { |
|
throw new IllegalArgumentException(String.format(message, values)); |
|
} |
|
return chars; |
|
} |
|
|
|
|
|
//--------------------------------------------------------- |
|
// |
|
// Converters |
|
// |
|
//--------------------------------------------------------- |
|
public static String toString(Object o) { |
|
if (null == o) { |
|
return null; |
|
} |
|
return o.toString(); |
|
} |
|
|
|
private Utils() { |
|
} |
|
}
|
|
|