Commit c39baed1 authored by swift_gan's avatar swift_gan Committed by swift_gan

add

parent 95189eff
...@@ -3,10 +3,6 @@ package de.robv.android.xposed; ...@@ -3,10 +3,6 @@ package de.robv.android.xposed;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.util.Log; import android.util.Log;
import com.elderdrivers.riru.xposed.core.HookMain;
import com.elderdrivers.riru.xposed.dexmaker.DynamicBridge;
import com.elderdrivers.riru.xposed.dexmaker.MethodInfo;
import com.elderdrivers.riru.xposed.util.MethodHookUtils;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* 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 external.org.apache.commons.lang3;
/**
* <p>Operations on {@link CharSequence} that are
* {@code null} safe.</p>
*
* @see CharSequence
* @since 3.0
* @version $Id: CharSequenceUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
*/
public class CharSequenceUtils {
/**
* <p>{@code CharSequenceUtils} instances should NOT be constructed in
* standard programming. </p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public CharSequenceUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* <p>Returns a new {@code CharSequence} that is a subsequence of this
* sequence starting with the {@code char} value at the specified index.</p>
*
* <p>This provides the {@code CharSequence} equivalent to {@link String#substring(int)}.
* The length (in {@code char}) of the returned sequence is {@code length() - start},
* so if {@code start == end} then an empty sequence is returned.</p>
*
* @param cs the specified subsequence, null returns null
* @param start the start index, inclusive, valid
* @return a new subsequence, may be null
* @throws IndexOutOfBoundsException if {@code start} is negative or if
* {@code start} is greater than {@code length()}
*/
public static CharSequence subSequence(CharSequence cs, int start) {
return cs == null ? null : cs.subSequence(start, cs.length());
}
//-----------------------------------------------------------------------
/**
* <p>Finds the first index in the {@code CharSequence} that matches the
* specified character.</p>
*
* @param cs the {@code CharSequence} to be processed, not null
* @param searchChar the char to be searched for
* @param start the start index, negative starts at the string start
* @return the index where the search char was found, -1 if not found
*/
static int indexOf(CharSequence cs, int searchChar, int start) {
if (cs instanceof String) {
return ((String) cs).indexOf(searchChar, start);
} else {
int sz = cs.length();
if (start < 0) {
start = 0;
}
for (int i = start; i < sz; i++) {
if (cs.charAt(i) == searchChar) {
return i;
}
}
return -1;
}
}
/**
* 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);
// if (cs instanceof String && searchChar instanceof String) {
// // TODO: Do we assume searchChar is usually relatively small;
// // If so then calling toString() on it is better than reverting to
// // the green implementation in the else block
// return ((String) cs).indexOf((String) searchChar, start);
// } else {
// // TODO: Implement rather than convert to String
// return cs.toString().indexOf(searchChar.toString(), start);
// }
}
/**
* <p>Finds the last index in the {@code CharSequence} that matches the
* specified character.</p>
*
* @param cs the {@code CharSequence} to be processed
* @param searchChar the char to be searched for
* @param start the start index, negative returns -1, beyond length starts at end
* @return the index where the search char was found, -1 if not found
*/
static int lastIndexOf(CharSequence cs, int searchChar, int start) {
if (cs instanceof String) {
return ((String) cs).lastIndexOf(searchChar, start);
} else {
int sz = cs.length();
if (start < 0) {
return -1;
}
if (start >= sz) {
start = sz - 1;
}
for (int i = start; i >= 0; --i) {
if (cs.charAt(i) == searchChar) {
return i;
}
}
return -1;
}
}
/**
* Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf
*
* @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 lastIndexOf(CharSequence cs, CharSequence searchChar, int start) {
return cs.toString().lastIndexOf(searchChar.toString(), start);
// if (cs instanceof String && searchChar instanceof String) {
// // TODO: Do we assume searchChar is usually relatively small;
// // If so then calling toString() on it is better than reverting to
// // the green implementation in the else block
// return ((String) cs).lastIndexOf((String) searchChar, start);
// } else {
// // TODO: Implement rather than convert to String
// return cs.toString().lastIndexOf(searchChar.toString(), start);
// }
}
/**
* Green implementation of toCharArray.
*
* @param cs the {@code CharSequence} to be processed
* @return the resulting char array
*/
static char[] toCharArray(CharSequence cs) {
if (cs instanceof String) {
return ((String) cs).toCharArray();
} else {
int sz = cs.length();
char[] array = new char[cs.length()];
for (int i = 0; i < sz; i++) {
array[i] = cs.charAt(i);
}
return array;
}
}
/**
* Green implementation of regionMatches.
*
* @param cs the {@code CharSequence} to be processed
* @param ignoreCase whether or not to be case insensitive
* @param thisStart the index to start on the {@code cs} CharSequence
* @param substring the {@code CharSequence} to be looked for
* @param start the index to start on the {@code substring} CharSequence
* @param length character length of the region
* @return whether the region matched
*/
static boolean regionMatches(CharSequence cs, boolean ignoreCase, int thisStart,
CharSequence substring, int start, int length) {
if (cs instanceof String && substring instanceof String) {
return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length);
} else {
// TODO: Implement rather than convert to String
return cs.toString().regionMatches(ignoreCase, thisStart, substring.toString(), start, length);
}
}
}
/*
* 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 external.org.apache.commons.lang3;
/**
* <p>Operations on char primitives and Character objects.</p>
*
* <p>This class tries to handle {@code null} input gracefully.
* An exception will not be thrown for a {@code null} input.
* Each method documents its behaviour in more detail.</p>
*
* <p>#ThreadSafe#</p>
* @since 2.1
* @version $Id: CharUtils.java 1158279 2011-08-16 14:06:45Z ggregory $
*/
public class CharUtils {
private static final String[] CHAR_STRING_ARRAY = new String[128];
/**
* {@code \u000a} linefeed LF ('\n').
*
* @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
* for Character and String Literals</a>
* @since 2.2
*/
public static final char LF = '\n';
/**
* {@code \u000d} carriage return CR ('\r').
*
* @see <a href="http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#101089">JLF: Escape Sequences
* for Character and String Literals</a>
* @since 2.2
*/
public static final char CR = '\r';
static {
for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) {
CHAR_STRING_ARRAY[c] = String.valueOf(c);
}
}
/**
* <p>{@code CharUtils} instances should NOT be constructed in standard programming.
* Instead, the class should be used as {@code CharUtils.toString('c');}.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean instance
* to operate.</p>
*/
public CharUtils() {
super();
}
//-----------------------------------------------------------------------
/**
* <p>Converts the character to a Character.</p>
*
* <p>For ASCII 7 bit characters, this uses a cache that will return the
* same Character object each time.</p>
*
* <pre>
* CharUtils.toCharacterObject(' ') = ' '
* CharUtils.toCharacterObject('A') = 'A'
* </pre>
*
* @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127.
* @param ch the character to convert
* @return a Character of the specified character
*/
@Deprecated
public static Character toCharacterObject(char ch) {
return Character.valueOf(ch);
}
/**
* <p>Converts the String to a Character using the first character, returning
* null for empty Strings.</p>
*
* <p>For ASCII 7 bit characters, this uses a cache that will return the
* same Character object each time.</p>
*
* <pre>
* CharUtils.toCharacterObject(null) = null
* CharUtils.toCharacterObject("") = null
* CharUtils.toCharacterObject("A") = 'A'
* CharUtils.toCharacterObject("BA") = 'B'
* </pre>
*
* @param str the character to convert
* @return the Character value of the first letter of the String
*/
public static Character toCharacterObject(String str) {
if (StringUtils.isEmpty(str)) {
return null;
}
return Character.valueOf(str.charAt(0));
}
//-----------------------------------------------------------------------
/**
* <p>Converts the Character to a char throwing an exception for {@code null}.</p>
*
* <pre>
* CharUtils.toChar(' ') = ' '
* CharUtils.toChar('A') = 'A'
* CharUtils.toChar(null) throws IllegalArgumentException
* </pre>
*
* @param ch the character to convert
* @return the char value of the Character
* @throws IllegalArgumentException if the Character is null
*/
public static char toChar(Character ch) {
if (ch == null) {
throw new IllegalArgumentException("The Character must not be null");
}
return ch.charValue();
}
/**
* <p>Converts the Character to a char handling {@code null}.</p>
*
* <pre>
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar(' ', 'X') = ' '
* CharUtils.toChar('A', 'X') = 'A'
* </pre>
*
* @param ch the character to convert
* @param defaultValue the value to use if the Character is null
* @return the char value of the Character or the default if null
*/
public static char toChar(Character ch, char defaultValue) {
if (ch == null) {
return defaultValue;
}
return ch.charValue();
}
//-----------------------------------------------------------------------
/**
* <p>Converts the String to a char using the first character, throwing
* an exception on empty Strings.</p>
*
* <pre>
* CharUtils.toChar("A") = 'A'
* CharUtils.toChar("BA") = 'B'
* CharUtils.toChar(null) throws IllegalArgumentException
* CharUtils.toChar("") throws IllegalArgumentException
* </pre>
*
* @param str the character to convert
* @return the char value of the first letter of the String
* @throws IllegalArgumentException if the String is empty
*/
public static char toChar(String str) {
if (StringUtils.isEmpty(str)) {
throw new IllegalArgumentException("The String must not be empty");
}
return str.charAt(0);
}
/**
* <p>Converts the String to a char using the first character, defaulting
* the value on empty Strings.</p>
*
* <pre>
* CharUtils.toChar(null, 'X') = 'X'
* CharUtils.toChar("", 'X') = 'X'
* CharUtils.toChar("A", 'X') = 'A'
* CharUtils.toChar("BA", 'X') = 'B'
* </pre>
*
* @param str the character to convert
* @param defaultValue the value to use if the Character is null
* @return the char value of the first letter of the String or the default if null
*/
public static char toChar(String str, char defaultValue) {
if (StringUtils.isEmpty(str)) {
return defaultValue;
}
return str.charAt(0);
}
//-----------------------------------------------------------------------
/**
* <p>Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.</p>
*
* <p>This method coverts the char '1' to the int 1 and so on.</p>
*
* <pre>
* CharUtils.toIntValue('3') = 3
* CharUtils.toIntValue('A') throws IllegalArgumentException
* </pre>
*
* @param ch the character to convert
* @return the int value of the character
* @throws IllegalArgumentException if the character is not ASCII numeric
*/
public static int toIntValue(char ch) {
if (isAsciiNumeric(ch) == false) {
throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'");
}
return ch - 48;
}
/**
* <p>Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.</p>
*
* <p>This method coverts the char '1' to the int 1 and so on.</p>
*
* <pre>
* CharUtils.toIntValue('3', -1) = 3
* CharUtils.toIntValue('A', -1) = -1
* </pre>
*
* @param ch the character to convert
* @param defaultValue the default value to use if the character is not numeric
* @return the int value of the character
*/
public static int toIntValue(char ch, int defaultValue) {
if (isAsciiNumeric(ch) == false) {
return defaultValue;
}
return ch - 48;
}
/**
* <p>Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.</p>
*
* <p>This method coverts the char '1' to the int 1 and so on.</p>
*
* <pre>
* CharUtils.toIntValue('3') = 3
* CharUtils.toIntValue(null) throws IllegalArgumentException
* CharUtils.toIntValue('A') throws IllegalArgumentException
* </pre>
*
* @param ch the character to convert, not null
* @return the int value of the character
* @throws IllegalArgumentException if the Character is not ASCII numeric or is null
*/
public static int toIntValue(Character ch) {
if (ch == null) {
throw new IllegalArgumentException("The character must not be null");
}
return toIntValue(ch.charValue());
}
/**
* <p>Converts the character to the Integer it represents, throwing an
* exception if the character is not numeric.</p>
*
* <p>This method coverts the char '1' to the int 1 and so on.</p>
*
* <pre>
* CharUtils.toIntValue(null, -1) = -1
* CharUtils.toIntValue('3', -1) = 3
* CharUtils.toIntValue('A', -1) = -1
* </pre>
*
* @param ch the character to convert
* @param defaultValue the default value to use if the character is not numeric
* @return the int value of the character
*/
public static int toIntValue(Character ch, int defaultValue) {
if (ch == null) {
return defaultValue;
}
return toIntValue(ch.charValue(), defaultValue);
}
//-----------------------------------------------------------------------
/**
* <p>Converts the character to a String that contains the one character.</p>
*
* <p>For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.</p>
*
* <pre>
* CharUtils.toString(' ') = " "
* CharUtils.toString('A') = "A"
* </pre>
*
* @param ch the character to convert
* @return a String containing the one specified character
*/
public static String toString(char ch) {
if (ch < 128) {
return CHAR_STRING_ARRAY[ch];
}
return new String(new char[] {ch});
}
/**
* <p>Converts the character to a String that contains the one character.</p>
*
* <p>For ASCII 7 bit characters, this uses a cache that will return the
* same String object each time.</p>
*
* <p>If {@code null} is passed in, {@code null} will be returned.</p>
*
* <pre>
* CharUtils.toString(null) = null
* CharUtils.toString(' ') = " "
* CharUtils.toString('A') = "A"
* </pre>
*
* @param ch the character to convert
* @return a String containing the one specified character
*/
public static String toString(Character ch) {
if (ch == null) {
return null;
}
return toString(ch.charValue());
}
//--------------------------------------------------------------------------
/**
* <p>Converts the string to the Unicode format '\u0020'.</p>
*
* <p>This format is the Java source code format.</p>
*
* <pre>
* CharUtils.unicodeEscaped(' ') = "\u0020"
* CharUtils.unicodeEscaped('A') = "\u0041"
* </pre>
*
* @param ch the character to convert
* @return the escaped Unicode string
*/
public static String unicodeEscaped(char ch) {
if (ch < 0x10) {
return "\\u000" + Integer.toHexString(ch);
} else if (ch < 0x100) {
return "\\u00" + Integer.toHexString(ch);
} else if (ch < 0x1000) {
return "\\u0" + Integer.toHexString(ch);
}
return "\\u" + Integer.toHexString(ch);
}
/**
* <p>Converts the string to the Unicode format '\u0020'.</p>
*
* <p>This format is the Java source code format.</p>
*
* <p>If {@code null} is passed in, {@code null} will be returned.</p>
*
* <pre>
* CharUtils.unicodeEscaped(null) = null
* CharUtils.unicodeEscaped(' ') = "\u0020"
* CharUtils.unicodeEscaped('A') = "\u0041"
* </pre>
*
* @param ch the character to convert, may be null
* @return the escaped Unicode string, null if null input
*/
public static String unicodeEscaped(Character ch) {
if (ch == null) {
return null;
}
return unicodeEscaped(ch.charValue());
}
//--------------------------------------------------------------------------
/**
* <p>Checks whether the character is ASCII 7 bit.</p>
*
* <pre>
* CharUtils.isAscii('a') = true
* CharUtils.isAscii('A') = true
* CharUtils.isAscii('3') = true
* CharUtils.isAscii('-') = true
* CharUtils.isAscii('\n') = true
* CharUtils.isAscii('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if less than 128
*/
public static boolean isAscii(char ch) {
return ch < 128;
}
/**
* <p>Checks whether the character is ASCII 7 bit printable.</p>
*
* <pre>
* CharUtils.isAsciiPrintable('a') = true
* CharUtils.isAsciiPrintable('A') = true
* CharUtils.isAsciiPrintable('3') = true
* CharUtils.isAsciiPrintable('-') = true
* CharUtils.isAsciiPrintable('\n') = false
* CharUtils.isAsciiPrintable('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 32 and 126 inclusive
*/
public static boolean isAsciiPrintable(char ch) {
return ch >= 32 && ch < 127;
}
/**
* <p>Checks whether the character is ASCII 7 bit control.</p>
*
* <pre>
* CharUtils.isAsciiControl('a') = false
* CharUtils.isAsciiControl('A') = false
* CharUtils.isAsciiControl('3') = false
* CharUtils.isAsciiControl('-') = false
* CharUtils.isAsciiControl('\n') = true
* CharUtils.isAsciiControl('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if less than 32 or equals 127
*/
public static boolean isAsciiControl(char ch) {
return ch < 32 || ch == 127;
}
/**
* <p>Checks whether the character is ASCII 7 bit alphabetic.</p>
*
* <pre>
* CharUtils.isAsciiAlpha('a') = true
* CharUtils.isAsciiAlpha('A') = true
* CharUtils.isAsciiAlpha('3') = false
* CharUtils.isAsciiAlpha('-') = false
* CharUtils.isAsciiAlpha('\n') = false
* CharUtils.isAsciiAlpha('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlpha(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
}
/**
* <p>Checks whether the character is ASCII 7 bit alphabetic upper case.</p>
*
* <pre>
* CharUtils.isAsciiAlphaUpper('a') = false
* CharUtils.isAsciiAlphaUpper('A') = true
* CharUtils.isAsciiAlphaUpper('3') = false
* CharUtils.isAsciiAlphaUpper('-') = false
* CharUtils.isAsciiAlphaUpper('\n') = false
* CharUtils.isAsciiAlphaUpper('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 65 and 90 inclusive
*/
public static boolean isAsciiAlphaUpper(char ch) {
return ch >= 'A' && ch <= 'Z';
}
/**
* <p>Checks whether the character is ASCII 7 bit alphabetic lower case.</p>
*
* <pre>
* CharUtils.isAsciiAlphaLower('a') = true
* CharUtils.isAsciiAlphaLower('A') = false
* CharUtils.isAsciiAlphaLower('3') = false
* CharUtils.isAsciiAlphaLower('-') = false
* CharUtils.isAsciiAlphaLower('\n') = false
* CharUtils.isAsciiAlphaLower('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 97 and 122 inclusive
*/
public static boolean isAsciiAlphaLower(char ch) {
return ch >= 'a' && ch <= 'z';
}
/**
* <p>Checks whether the character is ASCII 7 bit numeric.</p>
*
* <pre>
* CharUtils.isAsciiNumeric('a') = false
* CharUtils.isAsciiNumeric('A') = false
* CharUtils.isAsciiNumeric('3') = true
* CharUtils.isAsciiNumeric('-') = false
* CharUtils.isAsciiNumeric('\n') = false
* CharUtils.isAsciiNumeric('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 48 and 57 inclusive
*/
public static boolean isAsciiNumeric(char ch) {
return ch >= '0' && ch <= '9';
}
/**
* <p>Checks whether the character is ASCII 7 bit numeric.</p>
*
* <pre>
* CharUtils.isAsciiAlphanumeric('a') = true
* CharUtils.isAsciiAlphanumeric('A') = true
* CharUtils.isAsciiAlphanumeric('3') = true
* CharUtils.isAsciiAlphanumeric('-') = false
* CharUtils.isAsciiAlphanumeric('\n') = false
* CharUtils.isAsciiAlphanumeric('&copy;') = false
* </pre>
*
* @param ch the character to check
* @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive
*/
public static boolean isAsciiAlphanumeric(char ch) {
return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
}
}
/*
* 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 external.org.apache.commons.lang3;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
/**
* <p>Operates on classes without using reflection.</p>
*
* <p>This class handles invalid {@code null} inputs as best it can.
* Each method documents its behaviour in more detail.</p>
*
* <p>The notion of a {@code canonical name} includes the human
* readable name for the type, for example {@code int[]}. The
* non-canonical method variants work with the JVM names, such as
* {@code [I}. </p>
*
* @since 2.0
* @version $Id: ClassUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
*/
public class ClassUtils {
/**
* <p>The package separator character: <code>'&#x2e;' == {@value}</code>.</p>
*/
public static final char PACKAGE_SEPARATOR_CHAR = '.';
/**
* <p>The package separator String: {@code "&#x2e;"}.</p>
*/
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
/**
* <p>The inner class separator character: <code>'$' == {@value}</code>.</p>
*/
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
/**
* <p>The inner class separator String: {@code "$"}.</p>
*/
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
/**
* Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
*/
private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>();
static {
primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
primitiveWrapperMap.put(Byte.TYPE, Byte.class);
primitiveWrapperMap.put(Character.TYPE, Character.class);
primitiveWrapperMap.put(Short.TYPE, Short.class);
primitiveWrapperMap.put(Integer.TYPE, Integer.class);
primitiveWrapperMap.put(Long.TYPE, Long.class);
primitiveWrapperMap.put(Double.TYPE, Double.class);
primitiveWrapperMap.put(Float.TYPE, Float.class);
primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
}
/**
* Maps wrapper {@code Class}es to their corresponding primitive types.
*/
private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>();
static {
for (Class<?> primitiveClass : primitiveWrapperMap.keySet()) {
Class<?> wrapperClass = primitiveWrapperMap.get(primitiveClass);
if (!primitiveClass.equals(wrapperClass)) {
wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
}
}
}
/**
* Maps a primitive class name to its corresponding abbreviation used in array class names.
*/
private static final Map<String, String> abbreviationMap = new HashMap<String, String>();
/**
* Maps an abbreviation used in array class names to corresponding primitive class name.
*/
private static final Map<String, String> reverseAbbreviationMap = new HashMap<String, String>();
/**
* Add primitive type abbreviation to maps of abbreviations.
*
* @param primitive Canonical name of primitive type
* @param abbreviation Corresponding abbreviation of primitive type
*/
private static void addAbbreviation(String primitive, String abbreviation) {
abbreviationMap.put(primitive, abbreviation);
reverseAbbreviationMap.put(abbreviation, primitive);
}
/**
* Feed abbreviation maps
*/
static {
addAbbreviation("int", "I");
addAbbreviation("boolean", "Z");
addAbbreviation("float", "F");
addAbbreviation("long", "J");
addAbbreviation("short", "S");
addAbbreviation("byte", "B");
addAbbreviation("double", "D");
addAbbreviation("char", "C");
}
/**
* <p>ClassUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* {@code ClassUtils.getShortClassName(cls)}.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public ClassUtils() {
super();
}
// Short class name
// ----------------------------------------------------------------------
/**
* <p>Gets the class name minus the package name for an {@code Object}.</p>
*
* @param object the class to get the short name for, may be null
* @param valueIfNull the value to return if null
* @return the class name of the object without the package name, or the null value
*/
public static String getShortClassName(Object object, String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getShortClassName(object.getClass());
}
/**
* <p>Gets the class name minus the package name from a {@code Class}.</p>
*
* <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead.
* The one known difference is that this code will return {@code "Map.Entry"} while
* the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p>
*
* @param cls the class to get the short name for.
* @return the class name without the package name or an empty string
*/
public static String getShortClassName(Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getShortClassName(cls.getName());
}
/**
* <p>Gets the class name minus the package name from a String.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
* <p>Note that this method differs from Class.getSimpleName() in that this will
* return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
* return {@code "Entry"}. </p>
*
* @param className the className to get the short name for
* @return the class name of the class without the package name or an empty string
*/
public static String getShortClassName(String className) {
if (className == null) {
return StringUtils.EMPTY;
}
if (className.length() == 0) {
return StringUtils.EMPTY;
}
StringBuilder arrayPrefix = new StringBuilder();
// Handle array encoding
if (className.startsWith("[")) {
while (className.charAt(0) == '[') {
className = className.substring(1);
arrayPrefix.append("[]");
}
// Strip Object type encoding
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
className = className.substring(1, className.length() - 1);
}
}
if (reverseAbbreviationMap.containsKey(className)) {
className = reverseAbbreviationMap.get(className);
}
int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
int innerIdx = className.indexOf(
INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
String out = className.substring(lastDotIdx + 1);
if (innerIdx != -1) {
out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
}
return out + arrayPrefix;
}
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
*
* @param cls the class for which to get the simple name.
* @return the simple class name.
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return cls.getSimpleName();
}
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
*
* @param object the object for which to get the simple class name.
* @param valueIfNull the value to return if <code>object</code> is <code>null</code>
* @return the simple class name.
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(Object object, String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getSimpleName(object.getClass());
}
// Package name
// ----------------------------------------------------------------------
/**
* <p>Gets the package name of an {@code Object}.</p>
*
* @param object the class to get the package name for, may be null
* @param valueIfNull the value to return if null
* @return the package name of the object, or the null value
*/
public static String getPackageName(Object object, String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getPackageName(object.getClass());
}
/**
* <p>Gets the package name of a {@code Class}.</p>
*
* @param cls the class to get the package name for, may be {@code null}.
* @return the package name or an empty string
*/
public static String getPackageName(Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getPackageName(cls.getName());
}
/**
* <p>Gets the package name from a {@code String}.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
* <p>If the class is unpackaged, return an empty string.</p>
*
* @param className the className to get the package name for, may be {@code null}
* @return the package name or an empty string
*/
public static String getPackageName(String className) {
if (className == null || className.length() == 0) {
return StringUtils.EMPTY;
}
// Strip array encoding
while (className.charAt(0) == '[') {
className = className.substring(1);
}
// Strip Object type encoding
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
className = className.substring(1);
}
int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
if (i == -1) {
return StringUtils.EMPTY;
}
return className.substring(0, i);
}
// Superclasses/Superinterfaces
// ----------------------------------------------------------------------
/**
* <p>Gets a {@code List} of superclasses for the given class.</p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@code List} of superclasses in order going up from this one
* {@code null} if null input
*/
public static List<Class<?>> getAllSuperclasses(Class<?> cls) {
if (cls == null) {
return null;
}
List<Class<?>> classes = new ArrayList<Class<?>>();
Class<?> superclass = cls.getSuperclass();
while (superclass != null) {
classes.add(superclass);
superclass = superclass.getSuperclass();
}
return classes;
}
/**
* <p>Gets a {@code List} of all interfaces implemented by the given
* class and its superclasses.</p>
*
* <p>The order is determined by looking through each interface in turn as
* declared in the source file and following its hierarchy up. Then each
* superclass is considered in the same way. Later duplicates are ignored,
* so the order is maintained.</p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@code List} of interfaces in order,
* {@code null} if null input
*/
public static List<Class<?>> getAllInterfaces(Class<?> cls) {
if (cls == null) {
return null;
}
LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<Class<?>>();
getAllInterfaces(cls, interfacesFound);
return new ArrayList<Class<?>>(interfacesFound);
}
/**
* Get the interfaces for the specified class.
*
* @param cls the class to look up, may be {@code null}
* @param interfacesFound the {@code Set} of interfaces for the class
*/
private static void getAllInterfaces(Class<?> cls, HashSet<Class<?>> interfacesFound) {
while (cls != null) {
Class<?>[] interfaces = cls.getInterfaces();
for (Class<?> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}
cls = cls.getSuperclass();
}
}
// Convert list
// ----------------------------------------------------------------------
/**
* <p>Given a {@code List} of class names, this method converts them into classes.</p>
*
* <p>A new {@code List} is returned. If the class name cannot be found, {@code null}
* is stored in the {@code List}. If the class name in the {@code List} is
* {@code null}, {@code null} is stored in the output {@code List}.</p>
*
* @param classNames the classNames to change
* @return a {@code List} of Class objects corresponding to the class names,
* {@code null} if null input
* @throws ClassCastException if classNames contains a non String entry
*/
public static List<Class<?>> convertClassNamesToClasses(List<String> classNames) {
if (classNames == null) {
return null;
}
List<Class<?>> classes = new ArrayList<Class<?>>(classNames.size());
for (String className : classNames) {
try {
classes.add(Class.forName(className));
} catch (Exception ex) {
classes.add(null);
}
}
return classes;
}
/**
* <p>Given a {@code List} of {@code Class} objects, this method converts
* them into class names.</p>
*
* <p>A new {@code List} is returned. {@code null} objects will be copied into
* the returned list as {@code null}.</p>
*
* @param classes the classes to change
* @return a {@code List} of class names corresponding to the Class objects,
* {@code null} if null input
* @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
*/
public static List<String> convertClassesToClassNames(List<Class<?>> classes) {
if (classes == null) {
return null;
}
List<String> classNames = new ArrayList<String>(classes.size());
for (Class<?> cls : classes) {
if (cls == null) {
classNames.add(null);
} else {
classNames.add(cls.getName());
}
}
return classNames;
}
// Is assignable
// ----------------------------------------------------------------------
/**
* <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
*
* <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
* Class pair in the input arrays. It can be used to check if a set of arguments
* (the first parameter) are suitably compatible with a set of method parameter types
* (the second parameter).</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(Class)} method, this
* method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a {@code long},
* {@code float} or {@code double}. This method returns the correct
* result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method will
* return {@code true} if {@code null} is passed in and the toClass is
* non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* <p><strong>Since Lang 3.0,</strong> this method will default behavior for
* calculating assignability between primitive and wrapper types <em>corresponding
* to the running Java version</em>; i.e. autoboxing will be the default
* behavior in VMs running Java versions >= 1.5.</p>
*
* @param classArray the array of Classes to check, may be {@code null}
* @param toClassArray the array of Classes to try to assign into, may be {@code null}
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?>[] classArray, Class<?>... toClassArray) {
return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
}
/**
* <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
*
* <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
* Class pair in the input arrays. It can be used to check if a set of arguments
* (the first parameter) are suitably compatible with a set of method parameter types
* (the second parameter).</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(Class)} method, this
* method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a {@code long},
* {@code float} or {@code double}. This method returns the correct
* result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method will
* return {@code true} if {@code null} is passed in and the toClass is
* non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* @param classArray the array of Classes to check, may be {@code null}
* @param toClassArray the array of Classes to try to assign into, may be {@code null}
* @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, boolean autoboxing) {
if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
return false;
}
if (classArray == null) {
classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (toClassArray == null) {
toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
}
for (int i = 0; i < classArray.length; i++) {
if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) {
return false;
}
}
return true;
}
/**
* Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
* @param type
* The class to query or null.
* @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
* @since 3.1
*/
public static boolean isPrimitiveOrWrapper(Class<?> type) {
if (type == null) {
return false;
}
return type.isPrimitive() || isPrimitiveWrapper(type);
}
/**
* Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
* {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
* @param type
* The class to query or null.
* @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
* {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
* @since 3.1
*/
public static boolean isPrimitiveWrapper(Class<?> type) {
return wrapperPrimitiveMap.containsKey(type);
}
/**
* <p>Checks if one {@code Class} can be assigned to a variable of
* another {@code Class}.</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(Class)} method,
* this method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a long, float or
* double. This method returns the correct result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method
* will return {@code true} if {@code null} is passed in and the
* toClass is non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* <p><strong>Since Lang 3.0,</strong> this method will default behavior for
* calculating assignability between primitive and wrapper types <em>corresponding
* to the running Java version</em>; i.e. autoboxing will be the default
* behavior in VMs running Java versions >= 1.5.</p>
*
* @param cls the Class to check, may be null
* @param toClass the Class to try to assign into, returns false if null
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?> cls, Class<?> toClass) {
return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
}
/**
* <p>Checks if one {@code Class} can be assigned to a variable of
* another {@code Class}.</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(Class)} method,
* this method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a long, float or
* double. This method returns the correct result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method
* will return {@code true} if {@code null} is passed in and the
* toClass is non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* @param cls the Class to check, may be null
* @param toClass the Class to try to assign into, returns false if null
* @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?> cls, Class<?> toClass, boolean autoboxing) {
if (toClass == null) {
return false;
}
// have to check for null, as isAssignableFrom doesn't
if (cls == null) {
return !toClass.isPrimitive();
}
//autoboxing:
if (autoboxing) {
if (cls.isPrimitive() && !toClass.isPrimitive()) {
cls = primitiveToWrapper(cls);
if (cls == null) {
return false;
}
}
if (toClass.isPrimitive() && !cls.isPrimitive()) {
cls = wrapperToPrimitive(cls);
if (cls == null) {
return false;
}
}
}
if (cls.equals(toClass)) {
return true;
}
if (cls.isPrimitive()) {
if (toClass.isPrimitive() == false) {
return false;
}
if (Integer.TYPE.equals(cls)) {
return Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Long.TYPE.equals(cls)) {
return Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Boolean.TYPE.equals(cls)) {
return false;
}
if (Double.TYPE.equals(cls)) {
return false;
}
if (Float.TYPE.equals(cls)) {
return Double.TYPE.equals(toClass);
}
if (Character.TYPE.equals(cls)) {
return Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Short.TYPE.equals(cls)) {
return Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Byte.TYPE.equals(cls)) {
return Short.TYPE.equals(toClass)
|| Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
// should never get here
return false;
}
return toClass.isAssignableFrom(cls);
}
/**
* <p>Converts the specified primitive Class object to its corresponding
* wrapper Class object.</p>
*
* <p>NOTE: From v2.2, this method handles {@code Void.TYPE},
* returning {@code Void.TYPE}.</p>
*
* @param cls the class to convert, may be null
* @return the wrapper class for {@code cls} or {@code cls} if
* {@code cls} is not a primitive. {@code null} if null input.
* @since 2.1
*/
public static Class<?> primitiveToWrapper(Class<?> cls) {
Class<?> convertedClass = cls;
if (cls != null && cls.isPrimitive()) {
convertedClass = primitiveWrapperMap.get(cls);
}
return convertedClass;
}
/**
* <p>Converts the specified array of primitive Class objects to an array of
* its corresponding wrapper Class objects.</p>
*
* @param classes the class array to convert, may be null or empty
* @return an array which contains for each given class, the wrapper class or
* the original class if class is not a primitive. {@code null} if null input.
* Empty array if an empty array passed in.
* @since 2.1
*/
public static Class<?>[] primitivesToWrappers(Class<?>... classes) {
if (classes == null) {
return null;
}
if (classes.length == 0) {
return classes;
}
Class<?>[] convertedClasses = new Class[classes.length];
for (int i = 0; i < classes.length; i++) {
convertedClasses[i] = primitiveToWrapper(classes[i]);
}
return convertedClasses;
}
/**
* <p>Converts the specified wrapper class to its corresponding primitive
* class.</p>
*
* <p>This method is the counter part of {@code primitiveToWrapper()}.
* If the passed in class is a wrapper class for a primitive type, this
* primitive type will be returned (e.g. {@code Integer.TYPE} for
* {@code Integer.class}). For other classes, or if the parameter is
* <b>null</b>, the return value is <b>null</b>.</p>
*
* @param cls the class to convert, may be <b>null</b>
* @return the corresponding primitive type if {@code cls} is a
* wrapper class, <b>null</b> otherwise
* @see #primitiveToWrapper(Class)
* @since 2.4
*/
public static Class<?> wrapperToPrimitive(Class<?> cls) {
return wrapperPrimitiveMap.get(cls);
}
/**
* <p>Converts the specified array of wrapper Class objects to an array of
* its corresponding primitive Class objects.</p>
*
* <p>This method invokes {@code wrapperToPrimitive()} for each element
* of the passed in array.</p>
*
* @param classes the class array to convert, may be null or empty
* @return an array which contains for each given class, the primitive class or
* <b>null</b> if the original class is not a wrapper class. {@code null} if null input.
* Empty array if an empty array passed in.
* @see #wrapperToPrimitive(Class)
* @since 2.4
*/
public static Class<?>[] wrappersToPrimitives(Class<?>... classes) {
if (classes == null) {
return null;
}
if (classes.length == 0) {
return classes;
}
Class<?>[] convertedClasses = new Class[classes.length];
for (int i = 0; i < classes.length; i++) {
convertedClasses[i] = wrapperToPrimitive(classes[i]);
}
return convertedClasses;
}
// Inner class
// ----------------------------------------------------------------------
/**
* <p>Is the specified class an inner class or static nested class.</p>
*
* @param cls the class to check, may be null
* @return {@code true} if the class is an inner or static nested class,
* false if not or {@code null}
*/
public static boolean isInnerClass(Class<?> cls) {
return cls != null && cls.getEnclosingClass() != null;
}
// Class loading
// ----------------------------------------------------------------------
/**
* Returns the class represented by {@code className} using the
* {@code classLoader}. This implementation supports the syntaxes
* "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
*
* @param classLoader the class loader to use to load the class
* @param className the class name
* @param initialize whether the class must be initialized
* @return the class represented by {@code className} using the {@code classLoader}
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(
ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException {
try {
Class<?> clazz;
if (abbreviationMap.containsKey(className)) {
String clsName = "[" + abbreviationMap.get(className);
clazz = Class.forName(clsName, initialize, classLoader).getComponentType();
} else {
clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
}
return clazz;
} catch (ClassNotFoundException ex) {
// allow path separators (.) as inner class name separators
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
if (lastDotIndex != -1) {
try {
return getClass(classLoader, className.substring(0, lastDotIndex) +
INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
initialize);
} catch (ClassNotFoundException ex2) { // NOPMD
// ignore exception
}
}
throw ex;
}
}
/**
* Returns the (initialized) class represented by {@code className}
* using the {@code classLoader}. This implementation supports
* the syntaxes "{@code java.util.Map.Entry[]}",
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
* and "{@code [Ljava.util.Map$Entry;}".
*
* @param classLoader the class loader to use to load the class
* @param className the class name
* @return the class represented by {@code className} using the {@code classLoader}
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
return getClass(classLoader, className, true);
}
/**
* Returns the (initialized) class represented by {@code className}
* using the current thread's context class loader. This implementation
* supports the syntaxes "{@code java.util.Map.Entry[]}",
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
* and "{@code [Ljava.util.Map$Entry;}".
*
* @param className the class name
* @return the class represented by {@code className} using the current thread's context class loader
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(String className) throws ClassNotFoundException {
return getClass(className, true);
}
/**
* Returns the class represented by {@code className} using the
* current thread's context class loader. This implementation supports the
* syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
*
* @param className the class name
* @param initialize whether the class must be initialized
* @return the class represented by {@code className} using the current thread's context class loader
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(String className, boolean initialize) throws ClassNotFoundException {
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
return getClass(loader, className, initialize);
}
// Public method
// ----------------------------------------------------------------------
/**
* <p>Returns the desired Method much like {@code Class.getMethod}, however
* it ensures that the returned Method is from a public class or interface and not
* from an anonymous inner class. This means that the Method is invokable and
* doesn't fall foul of Java bug
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).
*
* <code><pre>Set set = Collections.unmodifiableSet(...);
* Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
* Object result = method.invoke(set, new Object[]);</pre></code>
* </p>
*
* @param cls the class to check, not null
* @param methodName the name of the method
* @param parameterTypes the list of parameters
* @return the method
* @throws NullPointerException if the class is null
* @throws SecurityException if a a security violation occured
* @throws NoSuchMethodException if the method is not found in the given class
* or if the metothod doen't conform with the requirements
*/
public static Method getPublicMethod(Class<?> cls, String methodName, Class<?>... parameterTypes)
throws SecurityException, NoSuchMethodException {
Method declaredMethod = cls.getMethod(methodName, parameterTypes);
if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
return declaredMethod;
}
List<Class<?>> candidateClasses = new ArrayList<Class<?>>();
candidateClasses.addAll(getAllInterfaces(cls));
candidateClasses.addAll(getAllSuperclasses(cls));
for (Class<?> candidateClass : candidateClasses) {
if (!Modifier.isPublic(candidateClass.getModifiers())) {
continue;
}
Method candidateMethod;
try {
candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
continue;
}
if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
return candidateMethod;
}
}
throw new NoSuchMethodException("Can't find a public method for " +
methodName + " " + ArrayUtils.toString(parameterTypes));
}
// ----------------------------------------------------------------------
/**
* Converts a class name to a JLS style class name.
*
* @param className the class name
* @return the converted name
*/
private static String toCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
if (className == null) {
throw new NullPointerException("className must not be null.");
} else if (className.endsWith("[]")) {
StringBuilder classNameBuffer = new StringBuilder();
while (className.endsWith("[]")) {
className = className.substring(0, className.length() - 2);
classNameBuffer.append("[");
}
String abbreviation = abbreviationMap.get(className);
if (abbreviation != null) {
classNameBuffer.append(abbreviation);
} else {
classNameBuffer.append("L").append(className).append(";");
}
className = classNameBuffer.toString();
}
return className;
}
/**
* <p>Converts an array of {@code Object} in to an array of {@code Class} objects.
* If any of these objects is null, a null element will be inserted into the array.</p>
*
* <p>This method returns {@code null} for a {@code null} input array.</p>
*
* @param array an {@code Object} array
* @return a {@code Class} array, {@code null} if null array input
* @since 2.4
*/
public static Class<?>[] toClass(Object... array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return ArrayUtils.EMPTY_CLASS_ARRAY;
}
Class<?>[] classes = new Class[array.length];
for (int i = 0; i < array.length; i++) {
classes[i] = array[i] == null ? null : array[i].getClass();
}
return classes;
}
// Short canonical name
// ----------------------------------------------------------------------
/**
* <p>Gets the canonical name minus the package name for an {@code Object}.</p>
*
* @param object the class to get the short name for, may be null
* @param valueIfNull the value to return if null
* @return the canonical name of the object without the package name, or the null value
* @since 2.4
*/
public static String getShortCanonicalName(Object object, String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getShortCanonicalName(object.getClass().getName());
}
/**
* <p>Gets the canonical name minus the package name from a {@code Class}.</p>
*
* @param cls the class to get the short name for.
* @return the canonical name without the package name or an empty string
* @since 2.4
*/
public static String getShortCanonicalName(Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getShortCanonicalName(cls.getName());
}
/**
* <p>Gets the canonical name minus the package name from a String.</p>
*
* <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
*
* @param canonicalName the class name to get the short name for
* @return the canonical name of the class without the package name or an empty string
* @since 2.4
*/
public static String getShortCanonicalName(String canonicalName) {
return ClassUtils.getShortClassName(getCanonicalName(canonicalName));
}
// Package name
// ----------------------------------------------------------------------
/**
* <p>Gets the package name from the canonical name of an {@code Object}.</p>
*
* @param object the class to get the package name for, may be null
* @param valueIfNull the value to return if null
* @return the package name of the object, or the null value
* @since 2.4
*/
public static String getPackageCanonicalName(Object object, String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getPackageCanonicalName(object.getClass().getName());
}
/**
* <p>Gets the package name from the canonical name of a {@code Class}.</p>
*
* @param cls the class to get the package name for, may be {@code null}.
* @return the package name or an empty string
* @since 2.4
*/
public static String getPackageCanonicalName(Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getPackageCanonicalName(cls.getName());
}
/**
* <p>Gets the package name from the canonical name. </p>
*
* <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
* <p>If the class is unpackaged, return an empty string.</p>
*
* @param canonicalName the canonical name to get the package name for, may be {@code null}
* @return the package name or an empty string
* @since 2.4
*/
public static String getPackageCanonicalName(String canonicalName) {
return ClassUtils.getPackageName(getCanonicalName(canonicalName));
}
/**
* <p>Converts a given name of class into canonical format.
* If name of class is not a name of array class it returns
* unchanged name.</p>
* <p>Example:
* <ul>
* <li>{@code getCanonicalName("[I") = "int[]"}</li>
* <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li>
* <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li>
* </ul>
* </p>
*
* @param className the name of class
* @return canonical form of class name
* @since 2.4
*/
private static String getCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
if (className == null) {
return null;
} else {
int dim = 0;
while (className.startsWith("[")) {
dim++;
className = className.substring(1);
}
if (dim < 1) {
return className;
} else {
if (className.startsWith("L")) {
className = className.substring(
1,
className.endsWith(";")
? className.length() - 1
: className.length());
} else {
if (className.length() > 0) {
className = reverseAbbreviationMap.get(className.substring(0, 1));
}
}
StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
for (int i = 0; i < dim; i++) {
canonicalClassNameBuffer.append("[]");
}
return canonicalClassNameBuffer.toString();
}
}
}
}
/*
* 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 external.org.apache.commons.lang3;
/**
* <p>An enum representing all the versions of the Java specification.
* This is intended to mirror available values from the
* <em>java.specification.version</em> System property. </p>
*
* @since 3.0
* @version $Id: $
*/
public enum JavaVersion {
/**
* The Java version reported by Android. This is not an official Java version number.
*/
JAVA_0_9(1.5f, "0.9"),
/**
* Java 1.1.
*/
JAVA_1_1(1.1f, "1.1"),
/**
* Java 1.2.
*/
JAVA_1_2(1.2f, "1.2"),
/**
* Java 1.3.
*/
JAVA_1_3(1.3f, "1.3"),
/**
* Java 1.4.
*/
JAVA_1_4(1.4f, "1.4"),
/**
* Java 1.5.
*/
JAVA_1_5(1.5f, "1.5"),
/**
* Java 1.6.
*/
JAVA_1_6(1.6f, "1.6"),
/**
* Java 1.7.
*/
JAVA_1_7(1.7f, "1.7"),
/**
* Java 1.8.
*/
JAVA_1_8(1.8f, "1.8");
/**
* The float value.
*/
private float value;
/**
* The standard name.
*/
private String name;
/**
* Constructor.
*
* @param value the float value
* @param name the standard name, not null
*/
JavaVersion(final float value, final String name) {
this.value = value;
this.name = name;
}
//-----------------------------------------------------------------------
/**
* <p>Whether this version of Java is at least the version of Java passed in.</p>
*
* <p>For example:<br />
* {@code myVersion.atLeast(JavaVersion.JAVA_1_4)}<p>
*
* @param requiredVersion the version to check against, not null
* @return true if this version is equal to or greater than the specified version
*/
public boolean atLeast(JavaVersion requiredVersion) {
return this.value >= requiredVersion.value;
}
/**
* Transforms the given string with a Java version number to the
* corresponding constant of this enumeration class. This method is used
* internally.
*
* @param nom the Java version as string
* @return the corresponding enumeration constant or <b>null</b> if the
* version is unknown
*/
// helper for static importing
static JavaVersion getJavaVersion(final String nom) {
return get(nom);
}
/**
* Transforms the given string with a Java version number to the
* corresponding constant of this enumeration class. This method is used
* internally.
*
* @param nom the Java version as string
* @return the corresponding enumeration constant or <b>null</b> if the
* version is unknown
*/
static JavaVersion get(final String nom) {
if ("0.9".equals(nom)) {
return JAVA_0_9;
} else if ("1.1".equals(nom)) {
return JAVA_1_1;
} else if ("1.2".equals(nom)) {
return JAVA_1_2;
} else if ("1.3".equals(nom)) {
return JAVA_1_3;
} else if ("1.4".equals(nom)) {
return JAVA_1_4;
} else if ("1.5".equals(nom)) {
return JAVA_1_5;
} else if ("1.6".equals(nom)) {
return JAVA_1_6;
} else if ("1.7".equals(nom)) {
return JAVA_1_7;
} else if ("1.8".equals(nom)) {
return JAVA_1_8;
} else {
return null;
}
}
//-----------------------------------------------------------------------
/**
* <p>The string value is overridden to return the standard name.</p>
*
* <p>For example, <code>"1.5"</code>.</p>
*
* @return the name, not null
*/
@Override
public String toString() {
return name;
}
}
/*
* 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 external.org.apache.commons.lang3;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeSet;
import external.org.apache.commons.lang3.exception.CloneFailedException;
import external.org.apache.commons.lang3.mutable.MutableInt;
/**
* <p>Operations on {@code Object}.</p>
*
* <p>This class tries to handle {@code null} input gracefully.
* An exception will generally not be thrown for a {@code null} input.
* Each method documents its behaviour in more detail.</p>
*
* <p>#ThreadSafe#</p>
* @since 1.0
* @version $Id: ObjectUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
*/
//@Immutable
public class ObjectUtils {
/**
* <p>Singleton used as a {@code null} placeholder where
* {@code null} has another meaning.</p>
*
* <p>For example, in a {@code HashMap} the
* {@link HashMap#get(Object)} method returns
* {@code null} if the {@code Map} contains {@code null} or if there
* is no matching key. The {@code Null} placeholder can be used to
* distinguish between these two cases.</p>
*
* <p>Another example is {@code Hashtable}, where {@code null}
* cannot be stored.</p>
*
* <p>This instance is Serializable.</p>
*/
public static final Null NULL = new Null();
/**
* <p>{@code ObjectUtils} instances should NOT be constructed in
* standard programming. Instead, the static methods on the class should
* be used, such as {@code ObjectUtils.defaultIfNull("a","b");}.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public ObjectUtils() {
super();
}
// Defaulting
//-----------------------------------------------------------------------
/**
* <p>Returns a default value if the object passed is {@code null}.</p>
*
* <pre>
* ObjectUtils.defaultIfNull(null, null) = null
* ObjectUtils.defaultIfNull(null, "") = ""
* ObjectUtils.defaultIfNull(null, "zz") = "zz"
* ObjectUtils.defaultIfNull("abc", *) = "abc"
* ObjectUtils.defaultIfNull(Boolean.TRUE, *) = Boolean.TRUE
* </pre>
*
* @param <T> the type of the object
* @param object the {@code Object} to test, may be {@code null}
* @param defaultValue the default value to return, may be {@code null}
* @return {@code object} if it is not {@code null}, defaultValue otherwise
*/
public static <T> T defaultIfNull(T object, T defaultValue) {
return object != null ? object : defaultValue;
}
/**
* <p>Returns the first value in the array which is not {@code null}.
* If all the values are {@code null} or the array is {@code null}
* or empty then {@code null} is returned.</p>
*
* <pre>
* ObjectUtils.firstNonNull(null, null) = null
* ObjectUtils.firstNonNull(null, "") = ""
* ObjectUtils.firstNonNull(null, null, "") = ""
* ObjectUtils.firstNonNull(null, "zz") = "zz"
* ObjectUtils.firstNonNull("abc", *) = "abc"
* ObjectUtils.firstNonNull(null, "xyz", *) = "xyz"
* ObjectUtils.firstNonNull(Boolean.TRUE, *) = Boolean.TRUE
* ObjectUtils.firstNonNull() = null
* </pre>
*
* @param <T> the component type of the array
* @param values the values to test, may be {@code null} or empty
* @return the first value from {@code values} which is not {@code null},
* or {@code null} if there are no non-null values
* @since 3.0
*/
public static <T> T firstNonNull(T... values) {
if (values != null) {
for (T val : values) {
if (val != null) {
return val;
}
}
}
return null;
}
// Null-safe equals/hashCode
//-----------------------------------------------------------------------
/**
* <p>Compares two objects for equality, where either one or both
* objects may be {@code null}.</p>
*
* <pre>
* ObjectUtils.equals(null, null) = true
* ObjectUtils.equals(null, "") = false
* ObjectUtils.equals("", null) = false
* ObjectUtils.equals("", "") = true
* ObjectUtils.equals(Boolean.TRUE, null) = false
* ObjectUtils.equals(Boolean.TRUE, "true") = false
* ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE) = true
* ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
* </pre>
*
* @param object1 the first object, may be {@code null}
* @param object2 the second object, may be {@code null}
* @return {@code true} if the values of both objects are the same
*/
public static boolean equals(Object object1, Object object2) {
if (object1 == object2) {
return true;
}
if (object1 == null || object2 == null) {
return false;
}
return object1.equals(object2);
}
/**
* <p>Compares two objects for inequality, where either one or both
* objects may be {@code null}.</p>
*
* <pre>
* ObjectUtils.notEqual(null, null) = false
* ObjectUtils.notEqual(null, "") = true
* ObjectUtils.notEqual("", null) = true
* ObjectUtils.notEqual("", "") = false
* ObjectUtils.notEqual(Boolean.TRUE, null) = true
* ObjectUtils.notEqual(Boolean.TRUE, "true") = true
* ObjectUtils.notEqual(Boolean.TRUE, Boolean.TRUE) = false
* ObjectUtils.notEqual(Boolean.TRUE, Boolean.FALSE) = true
* </pre>
*
* @param object1 the first object, may be {@code null}
* @param object2 the second object, may be {@code null}
* @return {@code false} if the values of both objects are the same
*/
public static boolean notEqual(Object object1, Object object2) {
return ObjectUtils.equals(object1, object2) == false;
}
/**
* <p>Gets the hash code of an object returning zero when the
* object is {@code null}.</p>
*
* <pre>
* ObjectUtils.hashCode(null) = 0
* ObjectUtils.hashCode(obj) = obj.hashCode()
* </pre>
*
* @param obj the object to obtain the hash code of, may be {@code null}
* @return the hash code of the object, or zero if null
* @since 2.1
*/
public static int hashCode(Object obj) {
// hashCode(Object) retained for performance, as hash code is often critical
return obj == null ? 0 : obj.hashCode();
}
/**
* <p>Gets the hash code for multiple objects.</p>
*
* <p>This allows a hash code to be rapidly calculated for a number of objects.
* The hash code for a single object is the <em>not</em> same as {@link #hashCode(Object)}.
* The hash code for multiple objects is the same as that calculated by an
* {@code ArrayList} containing the specified objects.</p>
*
* <pre>
* ObjectUtils.hashCodeMulti() = 1
* ObjectUtils.hashCodeMulti((Object[]) null) = 1
* ObjectUtils.hashCodeMulti(a) = 31 + a.hashCode()
* ObjectUtils.hashCodeMulti(a,b) = (31 + a.hashCode()) * 31 + b.hashCode()
* ObjectUtils.hashCodeMulti(a,b,c) = ((31 + a.hashCode()) * 31 + b.hashCode()) * 31 + c.hashCode()
* </pre>
*
* @param objects the objects to obtain the hash code of, may be {@code null}
* @return the hash code of the objects, or zero if null
* @since 3.0
*/
public static int hashCodeMulti(Object... objects) {
int hash = 1;
if (objects != null) {
for (Object object : objects) {
hash = hash * 31 + ObjectUtils.hashCode(object);
}
}
return hash;
}
// Identity ToString
//-----------------------------------------------------------------------
/**
* <p>Gets the toString that would be produced by {@code Object}
* if a class did not override toString itself. {@code null}
* will return {@code null}.</p>
*
* <pre>
* ObjectUtils.identityToString(null) = null
* ObjectUtils.identityToString("") = "java.lang.String@1e23"
* ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
* </pre>
*
* @param object the object to create a toString for, may be
* {@code null}
* @return the default toString text, or {@code null} if
* {@code null} passed in
*/
public static String identityToString(Object object) {
if (object == null) {
return null;
}
StringBuffer buffer = new StringBuffer();
identityToString(buffer, object);
return buffer.toString();
}
/**
* <p>Appends the toString that would be produced by {@code Object}
* if a class did not override toString itself. {@code null}
* will throw a NullPointerException for either of the two parameters. </p>
*
* <pre>
* ObjectUtils.identityToString(buf, "") = buf.append("java.lang.String@1e23"
* ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa"
* ObjectUtils.identityToString(buf, Boolean.TRUE) = buf.append("java.lang.Boolean@7fa")
* </pre>
*
* @param buffer the buffer to append to
* @param object the object to create a toString for
* @since 2.4
*/
public static void identityToString(StringBuffer buffer, Object object) {
if (object == null) {
throw new NullPointerException("Cannot get the toString of a null identity");
}
buffer.append(object.getClass().getName())
.append('@')
.append(Integer.toHexString(System.identityHashCode(object)));
}
// ToString
//-----------------------------------------------------------------------
/**
* <p>Gets the {@code toString} of an {@code Object} returning
* an empty string ("") if {@code null} input.</p>
*
* <pre>
* ObjectUtils.toString(null) = ""
* ObjectUtils.toString("") = ""
* ObjectUtils.toString("bat") = "bat"
* ObjectUtils.toString(Boolean.TRUE) = "true"
* </pre>
*
* @see StringUtils#defaultString(String)
* @see String#valueOf(Object)
* @param obj the Object to {@code toString}, may be null
* @return the passed in Object's toString, or nullStr if {@code null} input
* @since 2.0
*/
public static String toString(Object obj) {
return obj == null ? "" : obj.toString();
}
/**
* <p>Gets the {@code toString} of an {@code Object} returning
* a specified text if {@code null} input.</p>
*
* <pre>
* ObjectUtils.toString(null, null) = null
* ObjectUtils.toString(null, "null") = "null"
* ObjectUtils.toString("", "null") = ""
* ObjectUtils.toString("bat", "null") = "bat"
* ObjectUtils.toString(Boolean.TRUE, "null") = "true"
* </pre>
*
* @see StringUtils#defaultString(String,String)
* @see String#valueOf(Object)
* @param obj the Object to {@code toString}, may be null
* @param nullStr the String to return if {@code null} input, may be null
* @return the passed in Object's toString, or nullStr if {@code null} input
* @since 2.0
*/
public static String toString(Object obj, String nullStr) {
return obj == null ? nullStr : obj.toString();
}
// Comparable
//-----------------------------------------------------------------------
/**
* <p>Null safe comparison of Comparables.</p>
*
* @param <T> type of the values processed by this method
* @param values the set of comparable values, may be null
* @return
* <ul>
* <li>If any objects are non-null and unequal, the lesser object.
* <li>If all objects are non-null and equal, the first.
* <li>If any of the comparables are null, the lesser of the non-null objects.
* <li>If all the comparables are null, null is returned.
* </ul>
*/
public static <T extends Comparable<? super T>> T min(T... values) {
T result = null;
if (values != null) {
for (T value : values) {
if (compare(value, result, true) < 0) {
result = value;
}
}
}
return result;
}
/**
* <p>Null safe comparison of Comparables.</p>
*
* @param <T> type of the values processed by this method
* @param values the set of comparable values, may be null
* @return
* <ul>
* <li>If any objects are non-null and unequal, the greater object.
* <li>If all objects are non-null and equal, the first.
* <li>If any of the comparables are null, the greater of the non-null objects.
* <li>If all the comparables are null, null is returned.
* </ul>
*/
public static <T extends Comparable<? super T>> T max(T... values) {
T result = null;
if (values != null) {
for (T value : values) {
if (compare(value, result, false) > 0) {
result = value;
}
}
}
return result;
}
/**
* <p>Null safe comparison of Comparables.
* {@code null} is assumed to be less than a non-{@code null} value.</p>
*
* @param <T> type of the values processed by this method
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @return a negative value if c1 < c2, zero if c1 = c2
* and a positive value if c1 > c2
*/
public static <T extends Comparable<? super T>> int compare(T c1, T c2) {
return compare(c1, c2, false);
}
/**
* <p>Null safe comparison of Comparables.</p>
*
* @param <T> type of the values processed by this method
* @param c1 the first comparable, may be null
* @param c2 the second comparable, may be null
* @param nullGreater if true {@code null} is considered greater
* than a non-{@code null} value or if false {@code null} is
* considered less than a Non-{@code null} value
* @return a negative value if c1 < c2, zero if c1 = c2
* and a positive value if c1 > c2
* @see Comparator#compare(Object, Object)
*/
public static <T extends Comparable<? super T>> int compare(T c1, T c2, boolean nullGreater) {
if (c1 == c2) {
return 0;
} else if (c1 == null) {
return nullGreater ? 1 : -1;
} else if (c2 == null) {
return nullGreater ? -1 : 1;
}
return c1.compareTo(c2);
}
/**
* Find the "best guess" middle value among comparables. If there is an even
* number of total values, the lower of the two middle values will be returned.
* @param <T> type of values processed by this method
* @param items to compare
* @return T at middle position
* @throws NullPointerException if items is {@code null}
* @throws IllegalArgumentException if items is empty or contains {@code null} values
* @since 3.0.1
*/
public static <T extends Comparable<? super T>> T median(T... items) {
Validate.notEmpty(items);
Validate.noNullElements(items);
TreeSet<T> sort = new TreeSet<T>();
Collections.addAll(sort, items);
@SuppressWarnings("unchecked") //we know all items added were T instances
T result = (T) sort.toArray()[(sort.size() - 1) / 2];
return result;
}
/**
* Find the "best guess" middle value among comparables. If there is an even
* number of total values, the lower of the two middle values will be returned.
* @param <T> type of values processed by this method
* @param comparator to use for comparisons
* @param items to compare
* @return T at middle position
* @throws NullPointerException if items or comparator is {@code null}
* @throws IllegalArgumentException if items is empty or contains {@code null} values
* @since 3.0.1
*/
public static <T> T median(Comparator<T> comparator, T... items) {
Validate.notEmpty(items, "null/empty items");
Validate.noNullElements(items);
Validate.notNull(comparator, "null comparator");
TreeSet<T> sort = new TreeSet<T>(comparator);
Collections.addAll(sort, items);
@SuppressWarnings("unchecked") //we know all items added were T instances
T result = (T) sort.toArray()[(sort.size() - 1) / 2];
return result;
}
// Mode
//-----------------------------------------------------------------------
/**
* Find the most frequently occurring item.
*
* @param <T> type of values processed by this method
* @param items to check
* @return most populous T, {@code null} if non-unique or no items supplied
* @since 3.0.1
*/
public static <T> T mode(T... items) {
if (ArrayUtils.isNotEmpty(items)) {
HashMap<T, MutableInt> occurrences = new HashMap<T, MutableInt>(items.length);
for (T t : items) {
MutableInt count = occurrences.get(t);
if (count == null) {
occurrences.put(t, new MutableInt(1));
} else {
count.increment();
}
}
T result = null;
int max = 0;
for (Map.Entry<T, MutableInt> e : occurrences.entrySet()) {
int cmp = e.getValue().intValue();
if (cmp == max) {
result = null;
} else if (cmp > max) {
max = cmp;
result = e.getKey();
}
}
return result;
}
return null;
}
// cloning
//-----------------------------------------------------------------------
/**
* <p>Clone an object.</p>
*
* @param <T> the type of the object
* @param obj the object to clone, null returns null
* @return the clone if the object implements {@link Cloneable} otherwise {@code null}
* @throws CloneFailedException if the object is cloneable and the clone operation fails
* @since 3.0
*/
public static <T> T clone(final T obj) {
if (obj instanceof Cloneable) {
final Object result;
if (obj.getClass().isArray()) {
final Class<?> componentType = obj.getClass().getComponentType();
if (!componentType.isPrimitive()) {
result = ((Object[]) obj).clone();
} else {
int length = Array.getLength(obj);
result = Array.newInstance(componentType, length);
while (length-- > 0) {
Array.set(result, length, Array.get(obj, length));
}
}
} else {
try {
final Method clone = obj.getClass().getMethod("clone");
result = clone.invoke(obj);
} catch (final NoSuchMethodException e) {
throw new CloneFailedException("Cloneable type "
+ obj.getClass().getName()
+ " has no clone method", e);
} catch (final IllegalAccessException e) {
throw new CloneFailedException("Cannot clone Cloneable type "
+ obj.getClass().getName(), e);
} catch (final InvocationTargetException e) {
throw new CloneFailedException("Exception cloning Cloneable type "
+ obj.getClass().getName(), e.getCause());
}
}
@SuppressWarnings("unchecked")
final T checked = (T) result;
return checked;
}
return null;
}
/**
* <p>Clone an object if possible.</p>
*
* <p>This method is similar to {@link #clone(Object)}, but will return the provided
* instance as the return value instead of {@code null} if the instance
* is not cloneable. This is more convenient if the caller uses different
* implementations (e.g. of a service) and some of the implementations do not allow concurrent
* processing or have state. In such cases the implementation can simply provide a proper
* clone implementation and the caller's code does not have to change.</p>
*
* @param <T> the type of the object
* @param obj the object to clone, null returns null
* @return the clone if the object implements {@link Cloneable} otherwise the object itself
* @throws CloneFailedException if the object is cloneable and the clone operation fails
* @since 3.0
*/
public static <T> T cloneIfPossible(final T obj) {
final T clone = clone(obj);
return clone == null ? obj : clone;
}
// Null
//-----------------------------------------------------------------------
/**
* <p>Class used as a null placeholder where {@code null}
* has another meaning.</p>
*
* <p>For example, in a {@code HashMap} the
* {@link HashMap#get(Object)} method returns
* {@code null} if the {@code Map} contains {@code null} or if there is
* no matching key. The {@code Null} placeholder can be used to distinguish
* between these two cases.</p>
*
* <p>Another example is {@code Hashtable}, where {@code null}
* cannot be stored.</p>
*/
public static class Null implements Serializable {
/**
* Required for serialization support. Declare serialization compatibility with Commons Lang 1.0
*
* @see Serializable
*/
private static final long serialVersionUID = 7092611880189329093L;
/**
* Restricted constructor - singleton.
*/
Null() {
super();
}
/**
* <p>Ensure singleton.</p>
*
* @return the singleton value
*/
private Object readResolve() {
return ObjectUtils.NULL;
}
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* 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 external.org.apache.commons.lang3;
import java.io.File;
/**
* <p>
* Helpers for {@code java.lang.System}.
* </p>
* <p>
* If a system property cannot be read due to security restrictions, the corresponding field in this class will be set
* to {@code null} and a message will be written to {@code System.err}.
* </p>
* <p>
* #ThreadSafe#
* </p>
*
* @since 1.0
* @version $Id: SystemUtils.java 1199816 2011-11-09 16:11:34Z bayard $
*/
public class SystemUtils {
/**
* The prefix String for all Windows OS.
*/
private static final String OS_NAME_WINDOWS_PREFIX = "Windows";
// System property constants
// -----------------------------------------------------------------------
// These MUST be declared first. Other constants depend on this.
/**
* The System property key for the user home directory.
*/
private static final String USER_HOME_KEY = "user.home";
/**
* The System property key for the user directory.
*/
private static final String USER_DIR_KEY = "user.dir";
/**
* The System property key for the Java IO temporary directory.
*/
private static final String JAVA_IO_TMPDIR_KEY = "java.io.tmpdir";
/**
* The System property key for the Java home directory.
*/
private static final String JAVA_HOME_KEY = "java.home";
/**
* <p>
* The {@code awt.toolkit} System Property.
* </p>
* <p>
* Holds a class name, on Windows XP this is {@code sun.awt.windows.WToolkit}.
* </p>
* <p>
* <b>On platforms without a GUI, this value is {@code null}.</b>
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
*/
public static final String AWT_TOOLKIT = getSystemProperty("awt.toolkit");
/**
* <p>
* The {@code file.encoding} System Property.
* </p>
* <p>
* File encoding, such as {@code Cp1252}.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.2
*/
public static final String FILE_ENCODING = getSystemProperty("file.encoding");
/**
* <p>
* The {@code file.separator} System Property. File separator (<code>&quot;/&quot;</code> on UNIX).
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String FILE_SEPARATOR = getSystemProperty("file.separator");
/**
* <p>
* The {@code java.awt.fonts} System Property.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
*/
public static final String JAVA_AWT_FONTS = getSystemProperty("java.awt.fonts");
/**
* <p>
* The {@code java.awt.graphicsenv} System Property.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
*/
public static final String JAVA_AWT_GRAPHICSENV = getSystemProperty("java.awt.graphicsenv");
/**
* <p>
* The {@code java.awt.headless} System Property. The value of this property is the String {@code "true"} or
* {@code "false"}.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @see #isJavaAwtHeadless()
* @since 2.1
* @since Java 1.4
*/
public static final String JAVA_AWT_HEADLESS = getSystemProperty("java.awt.headless");
/**
* <p>
* The {@code java.awt.printerjob} System Property.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
*/
public static final String JAVA_AWT_PRINTERJOB = getSystemProperty("java.awt.printerjob");
/**
* <p>
* The {@code java.class.path} System Property. Java class path.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_CLASS_PATH = getSystemProperty("java.class.path");
/**
* <p>
* The {@code java.class.version} System Property. Java class format version number.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_CLASS_VERSION = getSystemProperty("java.class.version");
/**
* <p>
* The {@code java.compiler} System Property. Name of JIT compiler to use. First in JDK version 1.2. Not used in Sun
* JDKs after 1.2.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2. Not used in Sun versions after 1.2.
*/
public static final String JAVA_COMPILER = getSystemProperty("java.compiler");
/**
* <p>
* The {@code java.endorsed.dirs} System Property. Path of endorsed directory or directories.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.4
*/
public static final String JAVA_ENDORSED_DIRS = getSystemProperty("java.endorsed.dirs");
/**
* <p>
* The {@code java.ext.dirs} System Property. Path of extension directory or directories.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.3
*/
public static final String JAVA_EXT_DIRS = getSystemProperty("java.ext.dirs");
/**
* <p>
* The {@code java.home} System Property. Java installation directory.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_HOME = getSystemProperty(JAVA_HOME_KEY);
/**
* <p>
* The {@code java.io.tmpdir} System Property. Default temp file path.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_IO_TMPDIR = getSystemProperty(JAVA_IO_TMPDIR_KEY);
/**
* <p>
* The {@code java.library.path} System Property. List of paths to search when loading libraries.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_LIBRARY_PATH = getSystemProperty("java.library.path");
/**
* <p>
* The {@code java.runtime.name} System Property. Java Runtime Environment name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.3
*/
public static final String JAVA_RUNTIME_NAME = getSystemProperty("java.runtime.name");
/**
* <p>
* The {@code java.runtime.version} System Property. Java Runtime Environment version.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.3
*/
public static final String JAVA_RUNTIME_VERSION = getSystemProperty("java.runtime.version");
/**
* <p>
* The {@code java.specification.name} System Property. Java Runtime Environment specification name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_SPECIFICATION_NAME = getSystemProperty("java.specification.name");
/**
* <p>
* The {@code java.specification.vendor} System Property. Java Runtime Environment specification vendor.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_SPECIFICATION_VENDOR = getSystemProperty("java.specification.vendor");
/**
* <p>
* The {@code java.specification.version} System Property. Java Runtime Environment specification version.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.3
*/
public static final String JAVA_SPECIFICATION_VERSION = getSystemProperty("java.specification.version");
private static final JavaVersion JAVA_SPECIFICATION_VERSION_AS_ENUM = JavaVersion.get(JAVA_SPECIFICATION_VERSION);
/**
* <p>
* The {@code java.util.prefs.PreferencesFactory} System Property. A class name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
* @since Java 1.4
*/
public static final String JAVA_UTIL_PREFS_PREFERENCES_FACTORY =
getSystemProperty("java.util.prefs.PreferencesFactory");
/**
* <p>
* The {@code java.vendor} System Property. Java vendor-specific string.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_VENDOR = getSystemProperty("java.vendor");
/**
* <p>
* The {@code java.vendor.url} System Property. Java vendor URL.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_VENDOR_URL = getSystemProperty("java.vendor.url");
/**
* <p>
* The {@code java.version} System Property. Java version number.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String JAVA_VERSION = getSystemProperty("java.version");
/**
* <p>
* The {@code java.vm.info} System Property. Java Virtual Machine implementation info.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.2
*/
public static final String JAVA_VM_INFO = getSystemProperty("java.vm.info");
/**
* <p>
* The {@code java.vm.name} System Property. Java Virtual Machine implementation name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_NAME = getSystemProperty("java.vm.name");
/**
* <p>
* The {@code java.vm.specification.name} System Property. Java Virtual Machine specification name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_SPECIFICATION_NAME = getSystemProperty("java.vm.specification.name");
/**
* <p>
* The {@code java.vm.specification.vendor} System Property. Java Virtual Machine specification vendor.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_SPECIFICATION_VENDOR = getSystemProperty("java.vm.specification.vendor");
/**
* <p>
* The {@code java.vm.specification.version} System Property. Java Virtual Machine specification version.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_SPECIFICATION_VERSION = getSystemProperty("java.vm.specification.version");
/**
* <p>
* The {@code java.vm.vendor} System Property. Java Virtual Machine implementation vendor.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_VENDOR = getSystemProperty("java.vm.vendor");
/**
* <p>
* The {@code java.vm.version} System Property. Java Virtual Machine implementation version.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.2
*/
public static final String JAVA_VM_VERSION = getSystemProperty("java.vm.version");
/**
* <p>
* The {@code line.separator} System Property. Line separator (<code>&quot;\n&quot;</code> on UNIX).
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String LINE_SEPARATOR = getSystemProperty("line.separator");
/**
* <p>
* The {@code os.arch} System Property. Operating system architecture.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String OS_ARCH = getSystemProperty("os.arch");
/**
* <p>
* The {@code os.name} System Property. Operating system name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String OS_NAME = getSystemProperty("os.name");
/**
* <p>
* The {@code os.version} System Property. Operating system version.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String OS_VERSION = getSystemProperty("os.version");
/**
* <p>
* The {@code path.separator} System Property. Path separator (<code>&quot;:&quot;</code> on UNIX).
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String PATH_SEPARATOR = getSystemProperty("path.separator");
/**
* <p>
* The {@code user.country} or {@code user.region} System Property. User's country code, such as {@code GB}. First
* in Java version 1.2 as {@code user.region}. Renamed to {@code user.country} in 1.4
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.2
*/
public static final String USER_COUNTRY = getSystemProperty("user.country") == null ?
getSystemProperty("user.region") : getSystemProperty("user.country");
/**
* <p>
* The {@code user.dir} System Property. User's current working directory.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String USER_DIR = getSystemProperty(USER_DIR_KEY);
/**
* <p>
* The {@code user.home} System Property. User's home directory.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String USER_HOME = getSystemProperty(USER_HOME_KEY);
/**
* <p>
* The {@code user.language} System Property. User's language code, such as {@code "en"}.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.0
* @since Java 1.2
*/
public static final String USER_LANGUAGE = getSystemProperty("user.language");
/**
* <p>
* The {@code user.name} System Property. User's account name.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since Java 1.1
*/
public static final String USER_NAME = getSystemProperty("user.name");
/**
* <p>
* The {@code user.timezone} System Property. For example: {@code "America/Los_Angeles"}.
* </p>
* <p>
* Defaults to {@code null} if the runtime does not have security access to read this property or the property does
* not exist.
* </p>
* <p>
* This value is initialized when the class is loaded. If {@link System#setProperty(String,String)} or
* {@link System#setProperties(java.util.Properties)} is called after this class is loaded, the value will be out of
* sync with that System property.
* </p>
*
* @since 2.1
*/
public static final String USER_TIMEZONE = getSystemProperty("user.timezone");
// Java version checks
// -----------------------------------------------------------------------
// These MUST be declared after those above as they depend on the
// values being set up
/**
* <p>
* Is {@code true} if this is Java version 1.1 (also 1.1.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_1 = getJavaVersionMatches("1.1");
/**
* <p>
* Is {@code true} if this is Java version 1.2 (also 1.2.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_2 = getJavaVersionMatches("1.2");
/**
* <p>
* Is {@code true} if this is Java version 1.3 (also 1.3.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_3 = getJavaVersionMatches("1.3");
/**
* <p>
* Is {@code true} if this is Java version 1.4 (also 1.4.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_4 = getJavaVersionMatches("1.4");
/**
* <p>
* Is {@code true} if this is Java version 1.5 (also 1.5.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_5 = getJavaVersionMatches("1.5");
/**
* <p>
* Is {@code true} if this is Java version 1.6 (also 1.6.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*/
public static final boolean IS_JAVA_1_6 = getJavaVersionMatches("1.6");
/**
* <p>
* Is {@code true} if this is Java version 1.7 (also 1.7.x versions).
* </p>
* <p>
* The field will return {@code false} if {@link #JAVA_VERSION} is {@code null}.
* </p>
*
* @since 3.0
*/
public static final boolean IS_JAVA_1_7 = getJavaVersionMatches("1.7");
// Operating system checks
// -----------------------------------------------------------------------
// These MUST be declared after those above as they depend on the
// values being set up
// OS names from http://www.vamphq.com/os.html
// Selected ones included - please advise dev@commons.apache.org
// if you want another added or a mistake corrected
/**
* <p>
* Is {@code true} if this is AIX.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_AIX = getOSMatchesName("AIX");
/**
* <p>
* Is {@code true} if this is HP-UX.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_HP_UX = getOSMatchesName("HP-UX");
/**
* <p>
* Is {@code true} if this is Irix.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_IRIX = getOSMatchesName("Irix");
/**
* <p>
* Is {@code true} if this is Linux.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_LINUX = getOSMatchesName("Linux") || getOSMatchesName("LINUX");
/**
* <p>
* Is {@code true} if this is Mac.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_MAC = getOSMatchesName("Mac");
/**
* <p>
* Is {@code true} if this is Mac.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_MAC_OSX = getOSMatchesName("Mac OS X");
/**
* <p>
* Is {@code true} if this is FreeBSD.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.1
*/
public static final boolean IS_OS_FREE_BSD = getOSMatchesName("FreeBSD");
/**
* <p>
* Is {@code true} if this is OpenBSD.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.1
*/
public static final boolean IS_OS_OPEN_BSD = getOSMatchesName("OpenBSD");
/**
* <p>
* Is {@code true} if this is NetBSD.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.1
*/
public static final boolean IS_OS_NET_BSD = getOSMatchesName("NetBSD");
/**
* <p>
* Is {@code true} if this is OS/2.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_OS2 = getOSMatchesName("OS/2");
/**
* <p>
* Is {@code true} if this is Solaris.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_SOLARIS = getOSMatchesName("Solaris");
/**
* <p>
* Is {@code true} if this is SunOS.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_SUN_OS = getOSMatchesName("SunOS");
/**
* <p>
* Is {@code true} if this is a UNIX like system, as in any of AIX, HP-UX, Irix, Linux, MacOSX, Solaris or SUN OS.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.1
*/
public static final boolean IS_OS_UNIX = IS_OS_AIX || IS_OS_HP_UX || IS_OS_IRIX || IS_OS_LINUX || IS_OS_MAC_OSX
|| IS_OS_SOLARIS || IS_OS_SUN_OS || IS_OS_FREE_BSD || IS_OS_OPEN_BSD || IS_OS_NET_BSD;
/**
* <p>
* Is {@code true} if this is Windows.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS = getOSMatchesName(OS_NAME_WINDOWS_PREFIX);
/**
* <p>
* Is {@code true} if this is Windows 2000.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_2000 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.0");
/**
* <p>
* Is {@code true} if this is Windows 2003.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.1
*/
public static final boolean IS_OS_WINDOWS_2003 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.2");
/**
* <p>
* Is {@code true} if this is Windows 2008.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.1
*/
public static final boolean IS_OS_WINDOWS_2008 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " Server 2008", "6.1");
/**
* <p>
* Is {@code true} if this is Windows 95.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_95 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.0");
// Java 1.2 running on Windows98 returns 'Windows 95', hence the above
/**
* <p>
* Is {@code true} if this is Windows 98.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_98 = getOSMatches(OS_NAME_WINDOWS_PREFIX + " 9", "4.1");
// Java 1.2 running on Windows98 returns 'Windows 95', hence the above
/**
* <p>
* Is {@code true} if this is Windows ME.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_ME = getOSMatches(OS_NAME_WINDOWS_PREFIX, "4.9");
// Java 1.2 running on WindowsME may return 'Windows 95', hence the above
/**
* <p>
* Is {@code true} if this is Windows NT.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_NT = getOSMatchesName(OS_NAME_WINDOWS_PREFIX + " NT");
// Windows 2000 returns 'Windows 2000' but may suffer from same Java1.2 problem
/**
* <p>
* Is {@code true} if this is Windows XP.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.0
*/
public static final boolean IS_OS_WINDOWS_XP = getOSMatches(OS_NAME_WINDOWS_PREFIX, "5.1");
// -----------------------------------------------------------------------
/**
* <p>
* Is {@code true} if this is Windows Vista.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 2.4
*/
public static final boolean IS_OS_WINDOWS_VISTA = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.0");
/**
* <p>
* Is {@code true} if this is Windows 7.
* </p>
* <p>
* The field will return {@code false} if {@code OS_NAME} is {@code null}.
* </p>
*
* @since 3.0
*/
public static final boolean IS_OS_WINDOWS_7 = getOSMatches(OS_NAME_WINDOWS_PREFIX, "6.1");
/**
* <p>
* Gets the Java home directory as a {@code File}.
* </p>
*
* @return a directory
* @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
* access to the specified system property.
* @see System#getProperty(String)
* @since 2.1
*/
public static File getJavaHome() {
return new File(System.getProperty(JAVA_HOME_KEY));
}
/**
* <p>
* Gets the Java IO temporary directory as a {@code File}.
* </p>
*
* @return a directory
* @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
* access to the specified system property.
* @see System#getProperty(String)
* @since 2.1
*/
public static File getJavaIoTmpDir() {
return new File(System.getProperty(JAVA_IO_TMPDIR_KEY));
}
/**
* <p>
* Decides if the Java version matches.
* </p>
*
* @param versionPrefix the prefix for the java version
* @return true if matches, or false if not or can't determine
*/
private static boolean getJavaVersionMatches(String versionPrefix) {
return isJavaVersionMatch(JAVA_SPECIFICATION_VERSION, versionPrefix);
}
/**
* Decides if the operating system matches.
*
* @param osNamePrefix the prefix for the os name
* @param osVersionPrefix the prefix for the version
* @return true if matches, or false if not or can't determine
*/
private static boolean getOSMatches(String osNamePrefix, String osVersionPrefix) {
return isOSMatch(OS_NAME, OS_VERSION, osNamePrefix, osVersionPrefix);
}
/**
* Decides if the operating system matches.
*
* @param osNamePrefix the prefix for the os name
* @return true if matches, or false if not or can't determine
*/
private static boolean getOSMatchesName(String osNamePrefix) {
return isOSNameMatch(OS_NAME, osNamePrefix);
}
// -----------------------------------------------------------------------
/**
* <p>
* Gets a System property, defaulting to {@code null} if the property cannot be read.
* </p>
* <p>
* If a {@code SecurityException} is caught, the return value is {@code null} and a message is written to
* {@code System.err}.
* </p>
*
* @param property the system property name
* @return the system property value or {@code null} if a security problem occurs
*/
private static String getSystemProperty(String property) {
try {
return System.getProperty(property);
} catch (SecurityException ex) {
// we are not allowed to look at this property
System.err.println("Caught a SecurityException reading the system property '" + property
+ "'; the SystemUtils property value will default to null.");
return null;
}
}
/**
* <p>
* Gets the user directory as a {@code File}.
* </p>
*
* @return a directory
* @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
* access to the specified system property.
* @see System#getProperty(String)
* @since 2.1
*/
public static File getUserDir() {
return new File(System.getProperty(USER_DIR_KEY));
}
/**
* <p>
* Gets the user home directory as a {@code File}.
* </p>
*
* @return a directory
* @throws SecurityException if a security manager exists and its {@code checkPropertyAccess} method doesn't allow
* access to the specified system property.
* @see System#getProperty(String)
* @since 2.1
*/
public static File getUserHome() {
return new File(System.getProperty(USER_HOME_KEY));
}
/**
* Returns whether the {@link #JAVA_AWT_HEADLESS} value is {@code true}.
*
* @return {@code true} if {@code JAVA_AWT_HEADLESS} is {@code "true"}, {@code false} otherwise.
* @see #JAVA_AWT_HEADLESS
* @since 2.1
* @since Java 1.4
*/
public static boolean isJavaAwtHeadless() {
return JAVA_AWT_HEADLESS != null ? JAVA_AWT_HEADLESS.equals(Boolean.TRUE.toString()) : false;
}
/**
* <p>
* Is the Java version at least the requested version.
* </p>
* <p>
* Example input:
* </p>
* <ul>
* <li>{@code 1.2f} to test for Java 1.2</li>
* <li>{@code 1.31f} to test for Java 1.3.1</li>
* </ul>
*
* @param requiredVersion the required version, for example 1.31f
* @return {@code true} if the actual version is equal or greater than the required version
*/
public static boolean isJavaVersionAtLeast(JavaVersion requiredVersion) {
return JAVA_SPECIFICATION_VERSION_AS_ENUM.atLeast(requiredVersion);
}
/**
* <p>
* Decides if the Java version matches.
* </p>
* <p>
* This method is package private instead of private to support unit test invocation.
* </p>
*
* @param version the actual Java version
* @param versionPrefix the prefix for the expected Java version
* @return true if matches, or false if not or can't determine
*/
static boolean isJavaVersionMatch(String version, String versionPrefix) {
if (version == null) {
return false;
}
return version.startsWith(versionPrefix);
}
/**
* Decides if the operating system matches.
* <p>
* This method is package private instead of private to support unit test invocation.
* </p>
*
* @param osName the actual OS name
* @param osVersion the actual OS version
* @param osNamePrefix the prefix for the expected OS name
* @param osVersionPrefix the prefix for the expected OS version
* @return true if matches, or false if not or can't determine
*/
static boolean isOSMatch(String osName, String osVersion, String osNamePrefix, String osVersionPrefix) {
if (osName == null || osVersion == null) {
return false;
}
return osName.startsWith(osNamePrefix) && osVersion.startsWith(osVersionPrefix);
}
/**
* Decides if the operating system matches.
* <p>
* This method is package private instead of private to support unit test invocation.
* </p>
*
* @param osName the actual OS name
* @param osNamePrefix the prefix for the expected OS name
* @return true if matches, or false if not or can't determine
*/
static boolean isOSNameMatch(String osName, String osNamePrefix) {
if (osName == null) {
return false;
}
return osName.startsWith(osNamePrefix);
}
// -----------------------------------------------------------------------
/**
* <p>
* SystemUtils instances should NOT be constructed in standard programming. Instead, the class should be used as
* {@code SystemUtils.FILE_SEPARATOR}.
* </p>
* <p>
* This constructor is public to permit tools that require a JavaBean instance to operate.
* </p>
*/
public SystemUtils() {
super();
}
}
/*
* 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 external.org.apache.commons.lang3;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;
/**
* <p>This class assists in validating arguments. The validation methods are
* based along the following principles:
* <ul>
* <li>An invalid {@code null} argument causes a {@link NullPointerException}.</li>
* <li>A non-{@code null} argument causes an {@link IllegalArgumentException}.</li>
* <li>An invalid index into an array/collection/map/string causes an {@link IndexOutOfBoundsException}.</li>
* </ul>
*
* <p>All exceptions messages are
* <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html#syntax">format strings</a>
* as defined by the Java platform. For example:</p>
*
* <pre>
* Validate.isTrue(i > 0, "The value must be greater than zero: %d", i);
* Validate.notNull(surname, "The surname must not be %s", null);
* </pre>
*
* <p>#ThreadSafe#</p>
* @version $Id: Validate.java 1199983 2011-11-09 21:41:24Z ggregory $
* @see String#format(String, Object...)
* @since 2.0
*/
public class Validate {
private static final String DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE =
"The value %s is not in the specified exclusive range of %s to %s";
private static final String DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE =
"The value %s is not in the specified inclusive range of %s to %s";
private static final String DEFAULT_MATCHES_PATTERN_EX = "The string %s does not match the pattern %s";
private static final String DEFAULT_IS_NULL_EX_MESSAGE = "The validated object is null";
private static final String DEFAULT_IS_TRUE_EX_MESSAGE = "The validated expression is false";
private static final String DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE =
"The validated array contains null element at index: %d";
private static final String DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE =
"The validated collection contains null element at index: %d";
private static final String DEFAULT_NOT_BLANK_EX_MESSAGE = "The validated character sequence is blank";
private static final String DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE = "The validated array is empty";
private static final String DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE =
"The validated character sequence is empty";
private static final String DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE = "The validated collection is empty";
private static final String DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE = "The validated map is empty";
private static final String DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE = "The validated array index is invalid: %d";
private static final String DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE =
"The validated character sequence index is invalid: %d";
private static final String DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE =
"The validated collection index is invalid: %d";
private static final String DEFAULT_VALID_STATE_EX_MESSAGE = "The validated state is false";
private static final String DEFAULT_IS_ASSIGNABLE_EX_MESSAGE = "Cannot assign a %s to a %s";
private static final String DEFAULT_IS_INSTANCE_OF_EX_MESSAGE = "Expected type: %s, actual: %s";
/**
* Constructor. This class should not normally be instantiated.
*/
public Validate() {
super();
}
// isTrue
//---------------------------------------------------------------------------------
/**
* <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>
*
* <pre>Validate.isTrue(i > 0.0, "The value must be greater than zero: %d", i);</pre>
*
* <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 the {@link String#format(String, Object...)} exception message if invalid, not null
* @param value the value to append to the message when invalid
* @throws IllegalArgumentException if expression is {@code false}
* @see #isTrue(boolean)
* @see #isTrue(boolean, String, double)
* @see #isTrue(boolean, String, Object...)
*/
public static void isTrue(boolean expression, String message, long value) {
if (expression == false) {
throw new IllegalArgumentException(String.format(message, Long.valueOf(value)));
}
}
/**
* <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>
*
* <pre>Validate.isTrue(d > 0.0, "The value must be greater than zero: %s", d);</pre>
*
* <p>For performance reasons, the double 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 the {@link String#format(String, Object...)} exception message if invalid, not null
* @param value the value to append to the message when invalid
* @throws IllegalArgumentException if expression is {@code false}
* @see #isTrue(boolean)
* @see #isTrue(boolean, String, long)
* @see #isTrue(boolean, String, Object...)
*/
public static void isTrue(boolean expression, String message, double value) {
if (expression == false) {
throw new IllegalArgumentException(String.format(message, Double.valueOf(value)));
}
}
/**
* <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>
*
* <pre>
* Validate.isTrue(i >= min && i <= max, "The value must be between %d and %d", min, max);
* Validate.isTrue(myObject.isOk(), "The object is not okay");</pre>
*
* @param expression the boolean expression 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, null array not recommended
* @throws IllegalArgumentException if expression is {@code false}
* @see #isTrue(boolean)
* @see #isTrue(boolean, String, long)
* @see #isTrue(boolean, String, double)
*/
public static void isTrue(boolean expression, String message, Object... values) {
if (expression == false) {
throw new IllegalArgumentException(String.format(message, values));
}
}
/**
* <p>Validate that the argument condition is {@code true}; otherwise
* throwing an exception. 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>
*
* <pre>
* Validate.isTrue(i > 0);
* Validate.isTrue(myObject.isOk());</pre>
*
* <p>The message of the exception is &quot;The validated expression is
* false&quot;.</p>
*
* @param expression the boolean expression to check
* @throws IllegalArgumentException if expression is {@code false}
* @see #isTrue(boolean, String, long)
* @see #isTrue(boolean, String, double)
* @see #isTrue(boolean, String, Object...)
*/
public static void isTrue(boolean expression) {
if (expression == false) {
throw new IllegalArgumentException(DEFAULT_IS_TRUE_EX_MESSAGE);
}
}
// notNull
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument is not {@code null};
* otherwise throwing an exception.
*
* <pre>Validate.notNull(myObject, "The object must not be null");</pre>
*
* <p>The message of the exception is &quot;The validated object is
* null&quot;.</p>
*
* @param <T> the object type
* @param object the object to check
* @return the validated object (never {@code null} for method chaining)
* @throws NullPointerException if the object is {@code null}
* @see #notNull(Object, String, Object...)
*/
public static <T> T notNull(T object) {
return notNull(object, DEFAULT_IS_NULL_EX_MESSAGE);
}
/**
* <p>Validate that the specified argument is not {@code null};
* otherwise throwing an exception with the specified message.
*
* <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}
* @see #notNull(Object)
*/
public static <T> T notNull(T object, String message, Object... values) {
if (object == null) {
throw new NullPointerException(String.format(message, values));
}
return object;
}
// notEmpty array
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument array is neither {@code null}
* nor a length of zero (no elements); otherwise throwing an exception
* with the specified message.
*
* <pre>Validate.notEmpty(myArray, "The array must not be empty");</pre>
*
* @param <T> the array type
* @param array the array 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 array (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if the array is empty
* @see #notEmpty(Object[])
*/
public static <T> T[] notEmpty(T[] array, String message, Object... values) {
if (array == null) {
throw new NullPointerException(String.format(message, values));
}
if (array.length == 0) {
throw new IllegalArgumentException(String.format(message, values));
}
return array;
}
/**
* <p>Validate that the specified argument array is neither {@code null}
* nor a length of zero (no elements); otherwise throwing an exception.
*
* <pre>Validate.notEmpty(myArray);</pre>
*
* <p>The message in the exception is &quot;The validated array is
* empty&quot;.
*
* @param <T> the array type
* @param array the array to check, validated not null by this method
* @return the validated array (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if the array is empty
* @see #notEmpty(Object[], String, Object...)
*/
public static <T> T[] notEmpty(T[] array) {
return notEmpty(array, DEFAULT_NOT_EMPTY_ARRAY_EX_MESSAGE);
}
// notEmpty collection
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument collection is neither {@code null}
* nor a size of zero (no elements); otherwise throwing an exception
* with the specified message.
*
* <pre>Validate.notEmpty(myCollection, "The collection must not be empty");</pre>
*
* @param <T> the collection type
* @param collection the collection 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 collection (never {@code null} method for chaining)
* @throws NullPointerException if the collection is {@code null}
* @throws IllegalArgumentException if the collection is empty
* @see #notEmpty(Object[])
*/
public static <T extends Collection<?>> T notEmpty(T collection, String message, Object... values) {
if (collection == null) {
throw new NullPointerException(String.format(message, values));
}
if (collection.isEmpty()) {
throw new IllegalArgumentException(String.format(message, values));
}
return collection;
}
/**
* <p>Validate that the specified argument collection is neither {@code null}
* nor a size of zero (no elements); otherwise throwing an exception.
*
* <pre>Validate.notEmpty(myCollection);</pre>
*
* <p>The message in the exception is &quot;The validated collection is
* empty&quot;.</p>
*
* @param <T> the collection type
* @param collection the collection to check, validated not null by this method
* @return the validated collection (never {@code null} method for chaining)
* @throws NullPointerException if the collection is {@code null}
* @throws IllegalArgumentException if the collection is empty
* @see #notEmpty(Collection, String, Object...)
*/
public static <T extends Collection<?>> T notEmpty(T collection) {
return notEmpty(collection, DEFAULT_NOT_EMPTY_COLLECTION_EX_MESSAGE);
}
// notEmpty map
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument map is neither {@code null}
* nor a size of zero (no elements); otherwise throwing an exception
* with the specified message.
*
* <pre>Validate.notEmpty(myMap, "The map must not be empty");</pre>
*
* @param <T> the map type
* @param map the map 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 map (never {@code null} method for chaining)
* @throws NullPointerException if the map is {@code null}
* @throws IllegalArgumentException if the map is empty
* @see #notEmpty(Object[])
*/
public static <T extends Map<?, ?>> T notEmpty(T map, String message, Object... values) {
if (map == null) {
throw new NullPointerException(String.format(message, values));
}
if (map.isEmpty()) {
throw new IllegalArgumentException(String.format(message, values));
}
return map;
}
/**
* <p>Validate that the specified argument map is neither {@code null}
* nor a size of zero (no elements); otherwise throwing an exception.
*
* <pre>Validate.notEmpty(myMap);</pre>
*
* <p>The message in the exception is &quot;The validated map is
* empty&quot;.</p>
*
* @param <T> the map type
* @param map the map to check, validated not null by this method
* @return the validated map (never {@code null} method for chaining)
* @throws NullPointerException if the map is {@code null}
* @throws IllegalArgumentException if the map is empty
* @see #notEmpty(Map, String, Object...)
*/
public static <T extends Map<?, ?>> T notEmpty(T map) {
return notEmpty(map, DEFAULT_NOT_EMPTY_MAP_EX_MESSAGE);
}
// notEmpty string
//---------------------------------------------------------------------------------
/**
* <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.
*
* <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
* @see #notEmpty(CharSequence)
*/
public static <T extends CharSequence> T notEmpty(T chars, String message, Object... values) {
if (chars == null) {
throw new NullPointerException(String.format(message, values));
}
if (chars.length() == 0) {
throw new IllegalArgumentException(String.format(message, values));
}
return chars;
}
/**
* <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.
*
* <pre>Validate.notEmpty(myString);</pre>
*
* <p>The message in the exception is &quot;The validated
* character sequence is empty&quot;.</p>
*
* @param <T> the character sequence type
* @param chars the character sequence to check, validated not null by this method
* @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
* @see #notEmpty(CharSequence, String, Object...)
*/
public static <T extends CharSequence> T notEmpty(T chars) {
return notEmpty(chars, DEFAULT_NOT_EMPTY_CHAR_SEQUENCE_EX_MESSAGE);
}
// notBlank string
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument character sequence is
* neither {@code null}, a length of zero (no characters), empty
* nor whitespace; otherwise throwing an exception with the specified
* message.
*
* <pre>Validate.notBlank(myString, "The string must not be blank");</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 blank
* @see #notBlank(CharSequence)
*
* @since 3.0
*/
public static <T extends CharSequence> T notBlank(T chars, String message, Object... values) {
if (chars == null) {
throw new NullPointerException(String.format(message, values));
}
if (StringUtils.isBlank(chars)) {
throw new IllegalArgumentException(String.format(message, values));
}
return chars;
}
/**
* <p>Validate that the specified argument character sequence is
* neither {@code null}, a length of zero (no characters), empty
* nor whitespace; otherwise throwing an exception.
*
* <pre>Validate.notBlank(myString);</pre>
*
* <p>The message in the exception is &quot;The validated character
* sequence is blank&quot;.</p>
*
* @param <T> the character sequence type
* @param chars the character sequence to check, validated not null by this method
* @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 blank
* @see #notBlank(CharSequence, String, Object...)
*
* @since 3.0
*/
public static <T extends CharSequence> T notBlank(T chars) {
return notBlank(chars, DEFAULT_NOT_BLANK_EX_MESSAGE);
}
// noNullElements array
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument array is neither
* {@code null} nor contains any elements that are {@code null};
* otherwise throwing an exception with the specified message.
*
* <pre>Validate.noNullElements(myArray, "The array contain null at position %d");</pre>
*
* <p>If the array is {@code null}, then the message in the exception
* is &quot;The validated object is null&quot;.</p>
*
* <p>If the array has a {@code null} element, then the iteration
* index of the invalid element is appended to the {@code values}
* argument.</p>
*
* @param <T> the array type
* @param array the array 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 array (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if an element is {@code null}
* @see #noNullElements(Object[])
*/
public static <T> T[] noNullElements(T[] array, String message, Object... values) {
Validate.notNull(array);
for (int i = 0; i < array.length; i++) {
if (array[i] == null) {
Object[] values2 = ArrayUtils.add(values, Integer.valueOf(i));
throw new IllegalArgumentException(String.format(message, values2));
}
}
return array;
}
/**
* <p>Validate that the specified argument array is neither
* {@code null} nor contains any elements that are {@code null};
* otherwise throwing an exception.
*
* <pre>Validate.noNullElements(myArray);</pre>
*
* <p>If the array is {@code null}, then the message in the exception
* is &quot;The validated object is null&quot;.</p>
*
* <p>If the array has a {@code null} element, then the message in the
* exception is &quot;The validated array contains null element at index:
* &quot followed by the index.</p>
*
* @param <T> the array type
* @param array the array to check, validated not null by this method
* @return the validated array (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if an element is {@code null}
* @see #noNullElements(Object[], String, Object...)
*/
public static <T> T[] noNullElements(T[] array) {
return noNullElements(array, DEFAULT_NO_NULL_ELEMENTS_ARRAY_EX_MESSAGE);
}
// noNullElements iterable
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument iterable is neither
* {@code null} nor contains any elements that are {@code null};
* otherwise throwing an exception with the specified message.
*
* <pre>Validate.noNullElements(myCollection, "The collection contains null at position %d");</pre>
*
* <p>If the iterable is {@code null}, then the message in the exception
* is &quot;The validated object is null&quot;.</p>
*
* <p>If the iterable has a {@code null} element, then the iteration
* index of the invalid element is appended to the {@code values}
* argument.</p>
*
* @param <T> the iterable type
* @param iterable the iterable 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 iterable (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if an element is {@code null}
* @see #noNullElements(Iterable)
*/
public static <T extends Iterable<?>> T noNullElements(T iterable, String message, Object... values) {
Validate.notNull(iterable);
int i = 0;
for (Iterator<?> it = iterable.iterator(); it.hasNext(); i++) {
if (it.next() == null) {
Object[] values2 = ArrayUtils.addAll(values, Integer.valueOf(i));
throw new IllegalArgumentException(String.format(message, values2));
}
}
return iterable;
}
/**
* <p>Validate that the specified argument iterable is neither
* {@code null} nor contains any elements that are {@code null};
* otherwise throwing an exception.
*
* <pre>Validate.noNullElements(myCollection);</pre>
*
* <p>If the iterable is {@code null}, then the message in the exception
* is &quot;The validated object is null&quot;.</p>
*
* <p>If the array has a {@code null} element, then the message in the
* exception is &quot;The validated iterable contains null element at index:
* &quot followed by the index.</p>
*
* @param <T> the iterable type
* @param iterable the iterable to check, validated not null by this method
* @return the validated iterable (never {@code null} method for chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IllegalArgumentException if an element is {@code null}
* @see #noNullElements(Iterable, String, Object...)
*/
public static <T extends Iterable<?>> T noNullElements(T iterable) {
return noNullElements(iterable, DEFAULT_NO_NULL_ELEMENTS_COLLECTION_EX_MESSAGE);
}
// validIndex array
//---------------------------------------------------------------------------------
/**
* <p>Validates that the index is within the bounds of the argument
* array; otherwise throwing an exception with the specified message.</p>
*
* <pre>Validate.validIndex(myArray, 2, "The array index is invalid: ");</pre>
*
* <p>If the array is {@code null}, then the message of the exception
* is &quot;The validated object is null&quot;.</p>
*
* @param <T> the array type
* @param array the array to check, validated not null by this method
* @param index the index 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, null array not recommended
* @return the validated array (never {@code null} for method chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(Object[], int)
*
* @since 3.0
*/
public static <T> T[] validIndex(T[] array, int index, String message, Object... values) {
Validate.notNull(array);
if (index < 0 || index >= array.length) {
throw new IndexOutOfBoundsException(String.format(message, values));
}
return array;
}
/**
* <p>Validates that the index is within the bounds of the argument
* array; otherwise throwing an exception.</p>
*
* <pre>Validate.validIndex(myArray, 2);</pre>
*
* <p>If the array is {@code null}, then the message of the exception
* is &quot;The validated object is null&quot;.</p>
*
* <p>If the index is invalid, then the message of the exception is
* &quot;The validated array index is invalid: &quot; followed by the
* index.</p>
*
* @param <T> the array type
* @param array the array to check, validated not null by this method
* @param index the index to check
* @return the validated array (never {@code null} for method chaining)
* @throws NullPointerException if the array is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(Object[], int, String, Object...)
*
* @since 3.0
*/
public static <T> T[] validIndex(T[] array, int index) {
return validIndex(array, index, DEFAULT_VALID_INDEX_ARRAY_EX_MESSAGE, Integer.valueOf(index));
}
// validIndex collection
//---------------------------------------------------------------------------------
/**
* <p>Validates that the index is within the bounds of the argument
* collection; otherwise throwing an exception with the specified message.</p>
*
* <pre>Validate.validIndex(myCollection, 2, "The collection index is invalid: ");</pre>
*
* <p>If the collection is {@code null}, then the message of the
* exception is &quot;The validated object is null&quot;.</p>
*
* @param <T> the collection type
* @param collection the collection to check, validated not null by this method
* @param index the index 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, null array not recommended
* @return the validated collection (never {@code null} for chaining)
* @throws NullPointerException if the collection is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(Collection, int)
*
* @since 3.0
*/
public static <T extends Collection<?>> T validIndex(T collection, int index, String message, Object... values) {
Validate.notNull(collection);
if (index < 0 || index >= collection.size()) {
throw new IndexOutOfBoundsException(String.format(message, values));
}
return collection;
}
/**
* <p>Validates that the index is within the bounds of the argument
* collection; otherwise throwing an exception.</p>
*
* <pre>Validate.validIndex(myCollection, 2);</pre>
*
* <p>If the index is invalid, then the message of the exception
* is &quot;The validated collection index is invalid: &quot;
* followed by the index.</p>
*
* @param <T> the collection type
* @param collection the collection to check, validated not null by this method
* @param index the index to check
* @return the validated collection (never {@code null} for method chaining)
* @throws NullPointerException if the collection is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(Collection, int, String, Object...)
*
* @since 3.0
*/
public static <T extends Collection<?>> T validIndex(T collection, int index) {
return validIndex(collection, index, DEFAULT_VALID_INDEX_COLLECTION_EX_MESSAGE, Integer.valueOf(index));
}
// validIndex string
//---------------------------------------------------------------------------------
/**
* <p>Validates that the index is within the bounds of the argument
* character sequence; otherwise throwing an exception with the
* specified message.</p>
*
* <pre>Validate.validIndex(myStr, 2, "The string index is invalid: ");</pre>
*
* <p>If the character sequence is {@code null}, then the message
* of the exception is &quot;The validated object is null&quot;.</p>
*
* @param <T> the character sequence type
* @param chars the character sequence to check, validated not null by this method
* @param index the index 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, null array not recommended
* @return the validated character sequence (never {@code null} for method chaining)
* @throws NullPointerException if the character sequence is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(CharSequence, int)
*
* @since 3.0
*/
public static <T extends CharSequence> T validIndex(T chars, int index, String message, Object... values) {
Validate.notNull(chars);
if (index < 0 || index >= chars.length()) {
throw new IndexOutOfBoundsException(String.format(message, values));
}
return chars;
}
/**
* <p>Validates that the index is within the bounds of the argument
* character sequence; otherwise throwing an exception.</p>
*
* <pre>Validate.validIndex(myStr, 2);</pre>
*
* <p>If the character sequence is {@code null}, then the message
* of the exception is &quot;The validated object is
* null&quot;.</p>
*
* <p>If the index is invalid, then the message of the exception
* is &quot;The validated character sequence index is invalid: &quot;
* followed by the index.</p>
*
* @param <T> the character sequence type
* @param chars the character sequence to check, validated not null by this method
* @param index the index to check
* @return the validated character sequence (never {@code null} for method chaining)
* @throws NullPointerException if the character sequence is {@code null}
* @throws IndexOutOfBoundsException if the index is invalid
* @see #validIndex(CharSequence, int, String, Object...)
*
* @since 3.0
*/
public static <T extends CharSequence> T validIndex(T chars, int index) {
return validIndex(chars, index, DEFAULT_VALID_INDEX_CHAR_SEQUENCE_EX_MESSAGE, Integer.valueOf(index));
}
// validState
//---------------------------------------------------------------------------------
/**
* <p>Validate that the stateful condition is {@code true}; otherwise
* throwing an exception. 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>
*
* <pre>
* Validate.validState(field > 0);
* Validate.validState(this.isOk());</pre>
*
* <p>The message of the exception is &quot;The validated state is
* false&quot;.</p>
*
* @param expression the boolean expression to check
* @throws IllegalStateException if expression is {@code false}
* @see #validState(boolean, String, Object...)
*
* @since 3.0
*/
public static void validState(boolean expression) {
if (expression == false) {
throw new IllegalStateException(DEFAULT_VALID_STATE_EX_MESSAGE);
}
}
/**
* <p>Validate that the stateful 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>
*
* <pre>Validate.validState(this.isOk(), "The state is not OK: %s", myObject);</pre>
*
* @param expression the boolean expression 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, null array not recommended
* @throws IllegalStateException if expression is {@code false}
* @see #validState(boolean)
*
* @since 3.0
*/
public static void validState(boolean expression, String message, Object... values) {
if (expression == false) {
throw new IllegalStateException(String.format(message, values));
}
}
// matchesPattern
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument character sequence matches the specified regular
* expression pattern; otherwise throwing an exception.</p>
*
* <pre>Validate.matchesPattern("hi", "[a-z]*");</pre>
*
* <p>The syntax of the pattern is the one used in the {@link Pattern} class.</p>
*
* @param input the character sequence to validate, not null
* @param pattern the regular expression pattern, not null
* @throws IllegalArgumentException if the character sequence does not match the pattern
* @see #matchesPattern(CharSequence, String, String, Object...)
*
* @since 3.0
*/
public static void matchesPattern(CharSequence input, String pattern) {
if (Pattern.matches(pattern, input) == false) {
throw new IllegalArgumentException(String.format(DEFAULT_MATCHES_PATTERN_EX, input, pattern));
}
}
/**
* <p>Validate that the specified argument character sequence matches the specified regular
* expression pattern; otherwise throwing an exception with the specified message.</p>
*
* <pre>Validate.matchesPattern("hi", "[a-z]*", "%s does not match %s", "hi" "[a-z]*");</pre>
*
* <p>The syntax of the pattern is the one used in the {@link Pattern} class.</p>
*
* @param input the character sequence to validate, not null
* @param pattern the regular expression pattern, not null
* @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
* @throws IllegalArgumentException if the character sequence does not match the pattern
* @see #matchesPattern(CharSequence, String)
*
* @since 3.0
*/
public static void matchesPattern(CharSequence input, String pattern, String message, Object... values) {
if (Pattern.matches(pattern, input) == false) {
throw new IllegalArgumentException(String.format(message, values));
}
}
// inclusiveBetween
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument object fall between the two
* inclusive values specified; otherwise, throws an exception.</p>
*
* <pre>Validate.inclusiveBetween(0, 2, 1);</pre>
*
* @param <T> the type of the argument object
* @param start the inclusive start value, not null
* @param end the inclusive end value, not null
* @param value the object to validate, not null
* @throws IllegalArgumentException if the value falls out of the boundaries
* @see #inclusiveBetween(Object, Object, Comparable, String, Object...)
*
* @since 3.0
*/
public static <T> void inclusiveBetween(T start, T end, Comparable<T> value) {
if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
throw new IllegalArgumentException(String.format(DEFAULT_INCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end));
}
}
/**
* <p>Validate that the specified argument object fall between the two
* inclusive values specified; otherwise, throws an exception with the
* specified message.</p>
*
* <pre>Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");</pre>
*
* @param <T> the type of the argument object
* @param start the inclusive start value, not null
* @param end the inclusive end value, not null
* @param value the object to validate, not null
* @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
* @throws IllegalArgumentException if the value falls out of the boundaries
* @see #inclusiveBetween(Object, Object, Comparable)
*
* @since 3.0
*/
public static <T> void inclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
if (value.compareTo(start) < 0 || value.compareTo(end) > 0) {
throw new IllegalArgumentException(String.format(message, values));
}
}
// exclusiveBetween
//---------------------------------------------------------------------------------
/**
* <p>Validate that the specified argument object fall between the two
* exclusive values specified; otherwise, throws an exception.</p>
*
* <pre>Validate.inclusiveBetween(0, 2, 1);</pre>
*
* @param <T> the type of the argument object
* @param start the exclusive start value, not null
* @param end the exclusive end value, not null
* @param value the object to validate, not null
* @throws IllegalArgumentException if the value falls out of the boundaries
* @see #exclusiveBetween(Object, Object, Comparable, String, Object...)
*
* @since 3.0
*/
public static <T> void exclusiveBetween(T start, T end, Comparable<T> value) {
if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
throw new IllegalArgumentException(String.format(DEFAULT_EXCLUSIVE_BETWEEN_EX_MESSAGE, value, start, end));
}
}
/**
* <p>Validate that the specified argument object fall between the two
* exclusive values specified; otherwise, throws an exception with the
* specified message.</p>
*
* <pre>Validate.inclusiveBetween(0, 2, 1, "Not in boundaries");</pre>
*
* @param <T> the type of the argument object
* @param start the exclusive start value, not null
* @param end the exclusive end value, not null
* @param value the object to validate, not null
* @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
* @throws IllegalArgumentException if the value falls out of the boundaries
* @see #exclusiveBetween(Object, Object, Comparable)
*
* @since 3.0
*/
public static <T> void exclusiveBetween(T start, T end, Comparable<T> value, String message, Object... values) {
if (value.compareTo(start) <= 0 || value.compareTo(end) >= 0) {
throw new IllegalArgumentException(String.format(message, values));
}
}
// isInstanceOf
//---------------------------------------------------------------------------------
/**
* Validates that the argument is an instance of the specified class, if not throws an exception.
*
* <p>This method is useful when validating according to an arbitrary class</p>
*
* <pre>Validate.isInstanceOf(OkClass.class, object);</pre>
*
* <p>The message of the exception is &quot;Expected type: {type}, actual: {obj_type}&quot;</p>
*
* @param type the class the object must be validated against, not null
* @param obj the object to check, null throws an exception
* @throws IllegalArgumentException if argument is not of specified class
* @see #isInstanceOf(Class, Object, String, Object...)
*
* @since 3.0
*/
public static void isInstanceOf(Class<?> type, Object obj) {
if (type.isInstance(obj) == false) {
throw new IllegalArgumentException(String.format(DEFAULT_IS_INSTANCE_OF_EX_MESSAGE, type.getName(),
obj == null ? "null" : obj.getClass().getName()));
}
}
/**
* <p>Validate that the argument is an instance of the specified class; otherwise
* throwing an exception with the specified message. This method is useful when
* validating according to an arbitrary class</p>
*
* <pre>Validate.isInstanceOf(OkClass.classs, object, "Wrong class, object is of class %s",
* object.getClass().getName());</pre>
*
* @param type the class the object must be validated against, not null
* @param obj the object to check, null throws an exception
* @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
* @throws IllegalArgumentException if argument is not of specified class
* @see #isInstanceOf(Class, Object)
*
* @since 3.0
*/
public static void isInstanceOf(Class<?> type, Object obj, String message, Object... values) {
if (type.isInstance(obj) == false) {
throw new IllegalArgumentException(String.format(message, values));
}
}
// isAssignableFrom
//---------------------------------------------------------------------------------
/**
* Validates that the argument can be converted to the specified class, if not, throws an exception.
*
* <p>This method is useful when validating that there will be no casting errors.</p>
*
* <pre>Validate.isAssignableFrom(SuperClass.class, object.getClass());</pre>
*
* <p>The message format of the exception is &quot;Cannot assign {type} to {superType}&quot;</p>
*
* @param superType the class the class must be validated against, not null
* @param type the class to check, not null
* @throws IllegalArgumentException if type argument is not assignable to the specified superType
* @see #isAssignableFrom(Class, Class, String, Object...)
*
* @since 3.0
*/
public static void isAssignableFrom(Class<?> superType, Class<?> type) {
if (superType.isAssignableFrom(type) == false) {
throw new IllegalArgumentException(String.format(DEFAULT_IS_ASSIGNABLE_EX_MESSAGE, type == null ? "null" : type.getName(),
superType.getName()));
}
}
/**
* Validates that the argument can be converted to the specified class, if not throws an exception.
*
* <p>This method is useful when validating if there will be no casting errors.</p>
*
* <pre>Validate.isAssignableFrom(SuperClass.class, object.getClass());</pre>
*
* <p>The message of the exception is &quot;The validated object can not be converted to the&quot;
* followed by the name of the class and &quot;class&quot;</p>
*
* @param superType the class the class must be validated against, not null
* @param type the class to check, not null
* @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
* @throws IllegalArgumentException if argument can not be converted to the specified class
* @see #isAssignableFrom(Class, Class)
*/
public static void isAssignableFrom(Class<?> superType, Class<?> type, String message, Object... values) {
if (superType.isAssignableFrom(type) == false) {
throw new IllegalArgumentException(String.format(message, values));
}
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
/**
* <p>
* The Builder interface is designed to designate a class as a <em>builder</em>
* object in the Builder design pattern. Builders are capable of creating and
* configuring objects or results that normally take multiple steps to construct
* or are very complex to derive.
* </p>
*
* <p>
* The builder interface defines a single method, {@link #build()}, that
* classes must implement. The result of this method should be the final
* configured object or result after all building operations are performed.
* </p>
*
* <p>
* It is a recommended practice that the methods supplied to configure the
* object or result being built return a reference to {@code this} so that
* method calls can be chained together.
* </p>
*
* <p>
* Example Builder:
* <code><pre>
* class FontBuilder implements Builder&lt;Font&gt; {
* private Font font;
*
* public FontBuilder(String fontName) {
* this.font = new Font(fontName, Font.PLAIN, 12);
* }
*
* public FontBuilder bold() {
* this.font = this.font.deriveFont(Font.BOLD);
* return this; // Reference returned so calls can be chained
* }
*
* public FontBuilder size(float pointSize) {
* this.font = this.font.deriveFont(pointSize);
* return this; // Reference returned so calls can be chained
* }
*
* // Other Font construction methods
*
* public Font build() {
* return this.font;
* }
* }
* </pre></code>
*
* Example Builder Usage:
* <code><pre>
* Font bold14ptSansSerifFont = new FontBuilder(Font.SANS_SERIF).bold()
* .size(14.0f)
* .build();
* </pre></code>
* </p>
*
* @param <T> the type of object that the builder will construct or compute.
*
* @since 3.0
* @version $Id: Builder.java 1088899 2011-04-05 05:31:27Z bayard $
*/
public interface Builder<T> {
/**
* Returns a reference to the object being constructed or result being
* calculated by the builder.
*
* @return the object constructed or result calculated by the builder.
*/
public T build();
}
/*
* 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 external.org.apache.commons.lang3.builder;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Comparator;
import external.org.apache.commons.lang3.ArrayUtils;
/**
* Assists in implementing {@link Comparable#compareTo(Object)} methods.
*
* It is consistent with <code>equals(Object)</code> and
* <code>hashcode()</code> built with {@link EqualsBuilder} and
* {@link HashCodeBuilder}.</p>
*
* <p>Two Objects that compare equal using <code>equals(Object)</code> should normally
* also compare equal using <code>compareTo(Object)</code>.</p>
*
* <p>All relevant fields should be included in the calculation of the
* comparison. Derived fields may be ignored. The same fields, in the same
* order, should be used in both <code>compareTo(Object)</code> and
* <code>equals(Object)</code>.</p>
*
* <p>To use this class write code as follows:</p>
*
* <pre>
* public class MyClass {
* String field1;
* int field2;
* boolean field3;
*
* ...
*
* public int compareTo(Object o) {
* MyClass myClass = (MyClass) o;
* return new CompareToBuilder()
* .appendSuper(super.compareTo(o)
* .append(this.field1, myClass.field1)
* .append(this.field2, myClass.field2)
* .append(this.field3, myClass.field3)
* .toComparison();
* }
* }
* </pre>
*
* <p>Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use
* reflection to determine the fields to append. Because fields can be private,
* <code>reflectionCompare</code> uses {@link AccessibleObject#setAccessible(boolean)} to
* bypass normal access control checks. This will fail under a security manager,
* unless the appropriate permissions are set up correctly. It is also
* slower than appending explicitly.</p>
*
* <p>A typical implementation of <code>compareTo(Object)</code> using
* <code>reflectionCompare</code> looks like:</p>
* <pre>
* public int compareTo(Object o) {
* return CompareToBuilder.reflectionCompare(this, o);
* }
* </pre>
*
* @see Comparable
* @see Object#equals(Object)
* @see Object#hashCode()
* @see EqualsBuilder
* @see HashCodeBuilder
* @since 1.0
* @version $Id: CompareToBuilder.java 1199735 2011-11-09 13:11:07Z sebb $
*/
public class CompareToBuilder implements Builder<Integer> {
/**
* Current state of the comparison as appended fields are checked.
*/
private int comparison;
/**
* <p>Constructor for CompareToBuilder.</p>
*
* <p>Starts off assuming that the objects are equal. Multiple calls are
* then made to the various append methods, followed by a call to
* {@link #toComparison} to get the result.</p>
*/
public CompareToBuilder() {
super();
comparison = 0;
}
//-----------------------------------------------------------------------
/**
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
* <li>Static fields will not be compared</li>
* <li>Transient members will be not be compared, as they are likely derived
* fields</li>
* <li>Superclass fields will be compared</li>
* </ul>
*
* <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
* they are considered equal.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
* @throws NullPointerException if either (but not both) parameters are
* <code>null</code>
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
*/
public static int reflectionCompare(Object lhs, Object rhs) {
return reflectionCompare(lhs, rhs, false, null);
}
/**
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
* <li>Static fields will not be compared</li>
* <li>If <code>compareTransients</code> is <code>true</code>,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.</li>
* <li>Superclass fields will be compared</li>
* </ul>
*
* <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
* they are considered equal.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param compareTransients whether to compare transient fields
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
* @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
* (but not both) is <code>null</code>
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
*/
public static int reflectionCompare(Object lhs, Object rhs, boolean compareTransients) {
return reflectionCompare(lhs, rhs, compareTransients, null);
}
/**
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
* <li>Static fields will not be compared</li>
* <li>If <code>compareTransients</code> is <code>true</code>,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.</li>
* <li>Superclass fields will be compared</li>
* </ul>
*
* <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
* they are considered equal.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param excludeFields Collection of String fields to exclude
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
* @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
* (but not both) is <code>null</code>
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
* @since 2.2
*/
public static int reflectionCompare(Object lhs, Object rhs, Collection<String> excludeFields) {
return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
/**
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
* <li>Static fields will not be compared</li>
* <li>If <code>compareTransients</code> is <code>true</code>,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.</li>
* <li>Superclass fields will be compared</li>
* </ul>
*
* <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
* they are considered equal.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param excludeFields array of fields to exclude
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
* @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
* (but not both) is <code>null</code>
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
* @since 2.2
*/
public static int reflectionCompare(Object lhs, Object rhs, String... excludeFields) {
return reflectionCompare(lhs, rhs, false, null, excludeFields);
}
/**
* <p>Compares two <code>Object</code>s via reflection.</p>
*
* <p>Fields can be private, thus <code>AccessibleObject.setAccessible</code>
* is used to bypass normal access control checks. This will fail under a
* security manager unless the appropriate permissions are set.</p>
*
* <ul>
* <li>Static fields will not be compared</li>
* <li>If the <code>compareTransients</code> is <code>true</code>,
* compares transient members. Otherwise ignores them, as they
* are likely derived fields.</li>
* <li>Compares superclass fields up to and including <code>reflectUpToClass</code>.
* If <code>reflectUpToClass</code> is <code>null</code>, compares all superclass fields.</li>
* </ul>
*
* <p>If both <code>lhs</code> and <code>rhs</code> are <code>null</code>,
* they are considered equal.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param compareTransients whether to compare transient fields
* @param reflectUpToClass last superclass for which fields are compared
* @param excludeFields fields to exclude
* @return a negative integer, zero, or a positive integer as <code>lhs</code>
* is less than, equal to, or greater than <code>rhs</code>
* @throws NullPointerException if either <code>lhs</code> or <code>rhs</code>
* (but not both) is <code>null</code>
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
* @since 2.2 (2.0 as <code>reflectionCompare(Object, Object, boolean, Class)</code>)
*/
public static int reflectionCompare(
Object lhs,
Object rhs,
boolean compareTransients,
Class<?> reflectUpToClass,
String... excludeFields) {
if (lhs == rhs) {
return 0;
}
if (lhs == null || rhs == null) {
throw new NullPointerException();
}
Class<?> lhsClazz = lhs.getClass();
if (!lhsClazz.isInstance(rhs)) {
throw new ClassCastException();
}
CompareToBuilder compareToBuilder = new CompareToBuilder();
reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) {
lhsClazz = lhsClazz.getSuperclass();
reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields);
}
return compareToBuilder.toComparison();
}
/**
* <p>Appends to <code>builder</code> the comparison of <code>lhs</code>
* to <code>rhs</code> using the fields defined in <code>clazz</code>.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param clazz <code>Class</code> that defines fields to be compared
* @param builder <code>CompareToBuilder</code> to append to
* @param useTransients whether to compare transient fields
* @param excludeFields fields to exclude
*/
private static void reflectionAppend(
Object lhs,
Object rhs,
Class<?> clazz,
CompareToBuilder builder,
boolean useTransients,
String[] excludeFields) {
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length && builder.comparison == 0; i++) {
Field f = fields[i];
if (!ArrayUtils.contains(excludeFields, f.getName())
&& (f.getName().indexOf('$') == -1)
&& (useTransients || !Modifier.isTransient(f.getModifiers()))
&& (!Modifier.isStatic(f.getModifiers()))) {
try {
builder.append(f.get(lhs), f.get(rhs));
} catch (IllegalAccessException e) {
// This can't happen. Would get a Security exception instead.
// Throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
}
}
}
//-----------------------------------------------------------------------
/**
* <p>Appends to the <code>builder</code> the <code>compareTo(Object)</code>
* result of the superclass.</p>
*
* @param superCompareTo result of calling <code>super.compareTo(Object)</code>
* @return this - used to chain append calls
* @since 2.0
*/
public CompareToBuilder appendSuper(int superCompareTo) {
if (comparison != 0) {
return this;
}
comparison = superCompareTo;
return this;
}
//-----------------------------------------------------------------------
/**
* <p>Appends to the <code>builder</code> the comparison of
* two <code>Object</code>s.</p>
*
* <ol>
* <li>Check if <code>lhs == rhs</code></li>
* <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
* a <code>null</code> object is less than a non-<code>null</code> object</li>
* <li>Check the object contents</li>
* </ol>
*
* <p><code>lhs</code> must either be an array or implement {@link Comparable}.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @return this - used to chain append calls
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
*/
public CompareToBuilder append(Object lhs, Object rhs) {
return append(lhs, rhs, null);
}
/**
* <p>Appends to the <code>builder</code> the comparison of
* two <code>Object</code>s.</p>
*
* <ol>
* <li>Check if <code>lhs == rhs</code></li>
* <li>Check if either <code>lhs</code> or <code>rhs</code> is <code>null</code>,
* a <code>null</code> object is less than a non-<code>null</code> object</li>
* <li>Check the object contents</li>
* </ol>
*
* <p>If <code>lhs</code> is an array, array comparison methods will be used.
* Otherwise <code>comparator</code> will be used to compare the objects.
* If <code>comparator</code> is <code>null</code>, <code>lhs</code> must
* implement {@link Comparable} instead.</p>
*
* @param lhs left-hand object
* @param rhs right-hand object
* @param comparator <code>Comparator</code> used to compare the objects,
* <code>null</code> means treat lhs as <code>Comparable</code>
* @return this - used to chain append calls
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
* @since 2.0
*/
public CompareToBuilder append(Object lhs, Object rhs, Comparator<?> comparator) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.getClass().isArray()) {
// switch on type of array, to dispatch to the correct handler
// handles multi dimensional arrays
// throws a ClassCastException if rhs is not the correct array type
if (lhs instanceof long[]) {
append((long[]) lhs, (long[]) rhs);
} else if (lhs instanceof int[]) {
append((int[]) lhs, (int[]) rhs);
} else if (lhs instanceof short[]) {
append((short[]) lhs, (short[]) rhs);
} else if (lhs instanceof char[]) {
append((char[]) lhs, (char[]) rhs);
} else if (lhs instanceof byte[]) {
append((byte[]) lhs, (byte[]) rhs);
} else if (lhs instanceof double[]) {
append((double[]) lhs, (double[]) rhs);
} else if (lhs instanceof float[]) {
append((float[]) lhs, (float[]) rhs);
} else if (lhs instanceof boolean[]) {
append((boolean[]) lhs, (boolean[]) rhs);
} else {
// not an array of primitives
// throws a ClassCastException if rhs is not an array
append((Object[]) lhs, (Object[]) rhs, comparator);
}
} else {
// the simple case, not an array, just test the element
if (comparator == null) {
@SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
final Comparable<Object> comparable = (Comparable<Object>) lhs;
comparison = comparable.compareTo(rhs);
} else {
@SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc
final Comparator<Object> comparator2 = (Comparator<Object>) comparator;
comparison = comparator2.compare(lhs, rhs);
}
}
return this;
}
//-------------------------------------------------------------------------
/**
* Appends to the <code>builder</code> the comparison of
* two <code>long</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(long lhs, long rhs) {
if (comparison != 0) {
return this;
}
comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
return this;
}
/**
* Appends to the <code>builder</code> the comparison of
* two <code>int</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(int lhs, int rhs) {
if (comparison != 0) {
return this;
}
comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
return this;
}
/**
* Appends to the <code>builder</code> the comparison of
* two <code>short</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(short lhs, short rhs) {
if (comparison != 0) {
return this;
}
comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
return this;
}
/**
* Appends to the <code>builder</code> the comparison of
* two <code>char</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(char lhs, char rhs) {
if (comparison != 0) {
return this;
}
comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
return this;
}
/**
* Appends to the <code>builder</code> the comparison of
* two <code>byte</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(byte lhs, byte rhs) {
if (comparison != 0) {
return this;
}
comparison = ((lhs < rhs) ? -1 : ((lhs > rhs) ? 1 : 0));
return this;
}
/**
* <p>Appends to the <code>builder</code> the comparison of
* two <code>double</code>s.</p>
*
* <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
*
* <p>It is compatible with the hash code generated by
* <code>HashCodeBuilder</code>.</p>
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(double lhs, double rhs) {
if (comparison != 0) {
return this;
}
comparison = Double.compare(lhs, rhs);
return this;
}
/**
* <p>Appends to the <code>builder</code> the comparison of
* two <code>float</code>s.</p>
*
* <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
*
* <p>It is compatible with the hash code generated by
* <code>HashCodeBuilder</code>.</p>
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(float lhs, float rhs) {
if (comparison != 0) {
return this;
}
comparison = Float.compare(lhs, rhs);
return this;
}
/**
* Appends to the <code>builder</code> the comparison of
* two <code>booleans</code>s.
*
* @param lhs left-hand value
* @param rhs right-hand value
* @return this - used to chain append calls
*/
public CompareToBuilder append(boolean lhs, boolean rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == false) {
comparison = -1;
} else {
comparison = +1;
}
return this;
}
//-----------------------------------------------------------------------
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>Object</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a short length array is less than a long length array</li>
* <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
* </ol>
*
* <p>This method will also will be called for the top level of multi-dimensional,
* ragged, and multi-typed arrays.</p>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
*/
public CompareToBuilder append(Object[] lhs, Object[] rhs) {
return append(lhs, rhs, null);
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>Object</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a short length array is less than a long length array</li>
* <li>Check array contents element by element using {@link #append(Object, Object, Comparator)}</li>
* </ol>
*
* <p>This method will also will be called for the top level of multi-dimensional,
* ragged, and multi-typed arrays.</p>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @param comparator <code>Comparator</code> to use to compare the array elements,
* <code>null</code> means to treat <code>lhs</code> elements as <code>Comparable</code>.
* @return this - used to chain append calls
* @throws ClassCastException if <code>rhs</code> is not assignment-compatible
* with <code>lhs</code>
* @since 2.0
*/
public CompareToBuilder append(Object[] lhs, Object[] rhs, Comparator<?> comparator) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i], comparator);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>long</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(long, long)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(long[] lhs, long[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>int</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(int, int)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(int[] lhs, int[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>short</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(short, short)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(short[] lhs, short[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>char</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(char, char)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(char[] lhs, char[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>byte</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(byte, byte)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(byte[] lhs, byte[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>double</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(double, double)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(double[] lhs, double[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>float</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(float, float)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(float[] lhs, float[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Appends to the <code>builder</code> the deep comparison of
* two <code>boolean</code> arrays.</p>
*
* <ol>
* <li>Check if arrays are the same using <code>==</code></li>
* <li>Check if for <code>null</code>, <code>null</code> is less than non-<code>null</code></li>
* <li>Check array length, a shorter length array is less than a longer length array</li>
* <li>Check array contents element by element using {@link #append(boolean, boolean)}</li>
* </ol>
*
* @param lhs left-hand array
* @param rhs right-hand array
* @return this - used to chain append calls
*/
public CompareToBuilder append(boolean[] lhs, boolean[] rhs) {
if (comparison != 0) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null) {
comparison = -1;
return this;
}
if (rhs == null) {
comparison = +1;
return this;
}
if (lhs.length != rhs.length) {
comparison = (lhs.length < rhs.length) ? -1 : +1;
return this;
}
for (int i = 0; i < lhs.length && comparison == 0; i++) {
append(lhs[i], rhs[i]);
}
return this;
}
//-----------------------------------------------------------------------
/**
* Returns a negative integer, a positive integer, or zero as
* the <code>builder</code> has judged the "left-hand" side
* as less than, greater than, or equal to the "right-hand"
* side.
*
* @return final comparison result
* @see #build()
*/
public int toComparison() {
return comparison;
}
/**
* Returns a negative Integer, a positive Integer, or zero as
* the <code>builder</code> has judged the "left-hand" side
* as less than, greater than, or equal to the "right-hand"
* side.
*
* @return final comparison result as an Integer
* @see #toComparison()
* @since 3.0
*/
public Integer build() {
return Integer.valueOf(toComparison());
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import external.org.apache.commons.lang3.ArrayUtils;
import external.org.apache.commons.lang3.tuple.Pair;
/**
* <p>Assists in implementing {@link Object#equals(Object)} methods.</p>
*
* <p> This class provides methods to build a good equals method for any
* class. It follows rules laid out in
* <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a>
* , by Joshua Bloch. In particular the rule for comparing <code>doubles</code>,
* <code>floats</code>, and arrays can be tricky. Also, making sure that
* <code>equals()</code> and <code>hashCode()</code> are consistent can be
* difficult.</p>
*
* <p>Two Objects that compare as equals must generate the same hash code,
* but two Objects with the same hash code do not have to be equal.</p>
*
* <p>All relevant fields should be included in the calculation of equals.
* Derived fields may be ignored. In particular, any field used in
* generating a hash code must be used in the equals method, and vice
* versa.</p>
*
* <p>Typical use for the code is as follows:</p>
* <pre>
* public boolean equals(Object obj) {
* if (obj == null) { return false; }
* if (obj == this) { return true; }
* if (obj.getClass() != getClass()) {
* return false;
* }
* MyClass rhs = (MyClass) obj;
* return new EqualsBuilder()
* .appendSuper(super.equals(obj))
* .append(field1, rhs.field1)
* .append(field2, rhs.field2)
* .append(field3, rhs.field3)
* .isEquals();
* }
* </pre>
*
* <p> Alternatively, there is a method that uses reflection to determine
* the fields to test. Because these fields are usually private, the method,
* <code>reflectionEquals</code>, uses <code>AccessibleObject.setAccessible</code> to
* change the visibility of the fields. This will fail under a security
* manager, unless the appropriate permissions are set up correctly. It is
* also slower than testing explicitly.</p>
*
* <p> A typical invocation for this method would look like:</p>
* <pre>
* public boolean equals(Object obj) {
* return EqualsBuilder.reflectionEquals(this, obj);
* }
* </pre>
*
* @since 1.0
* @version $Id: EqualsBuilder.java 1091531 2011-04-12 18:29:49Z ggregory $
*/
public class EqualsBuilder implements Builder<Boolean> {
/**
* <p>
* A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
* </p>
*
* @since 3.0
*/
private static final ThreadLocal<Set<Pair<IDKey, IDKey>>> REGISTRY = new ThreadLocal<Set<Pair<IDKey, IDKey>>>();
/*
* NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
* we are in the process of calculating.
*
* So we generate a one-to-one mapping from the original object to a new object.
*
* Now HashSet uses equals() to determine if two elements with the same hashcode really
* are equal, so we also need to ensure that the replacement objects are only equal
* if the original objects are identical.
*
* The original implementation (2.4 and before) used the System.indentityHashCode()
* method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
*
* We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
* to disambiguate the duplicate ids.
*/
/**
* <p>
* Returns the registry of object pairs being traversed by the reflection
* methods in the current thread.
* </p>
*
* @return Set the registry of objects being traversed
* @since 3.0
*/
static Set<Pair<IDKey, IDKey>> getRegistry() {
return REGISTRY.get();
}
/**
* <p>
* Converters value pair into a register pair.
* </p>
*
* @param lhs <code>this</code> object
* @param rhs the other object
*
* @return the pair
*/
static Pair<IDKey, IDKey> getRegisterPair(Object lhs, Object rhs) {
IDKey left = new IDKey(lhs);
IDKey right = new IDKey(rhs);
return Pair.of(left, right);
}
/**
* <p>
* Returns <code>true</code> if the registry contains the given object pair.
* Used by the reflection methods to avoid infinite loops.
* Objects might be swapped therefore a check is needed if the object pair
* is registered in given or swapped order.
* </p>
*
* @param lhs <code>this</code> object to lookup in registry
* @param rhs the other object to lookup on registry
* @return boolean <code>true</code> if the registry contains the given object.
* @since 3.0
*/
static boolean isRegistered(Object lhs, Object rhs) {
Set<Pair<IDKey, IDKey>> registry = getRegistry();
Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
Pair<IDKey, IDKey> swappedPair = Pair.of(pair.getLeft(), pair.getRight());
return registry != null
&& (registry.contains(pair) || registry.contains(swappedPair));
}
/**
* <p>
* Registers the given object pair.
* Used by the reflection methods to avoid infinite loops.
* </p>
*
* @param lhs <code>this</code> object to register
* @param rhs the other object to register
*/
static void register(Object lhs, Object rhs) {
synchronized (EqualsBuilder.class) {
if (getRegistry() == null) {
REGISTRY.set(new HashSet<Pair<IDKey, IDKey>>());
}
}
Set<Pair<IDKey, IDKey>> registry = getRegistry();
Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
registry.add(pair);
}
/**
* <p>
* Unregisters the given object pair.
* </p>
*
* <p>
* Used by the reflection methods to avoid infinite loops.
*
* @param lhs <code>this</code> object to unregister
* @param rhs the other object to unregister
* @since 3.0
*/
static void unregister(Object lhs, Object rhs) {
Set<Pair<IDKey, IDKey>> registry = getRegistry();
if (registry != null) {
Pair<IDKey, IDKey> pair = getRegisterPair(lhs, rhs);
registry.remove(pair);
synchronized (EqualsBuilder.class) {
//read again
registry = getRegistry();
if (registry != null && registry.isEmpty()) {
REGISTRY.remove();
}
}
}
}
/**
* If the fields tested are equals.
* The default value is <code>true</code>.
*/
private boolean isEquals = true;
/**
* <p>Constructor for EqualsBuilder.</p>
*
* <p>Starts off assuming that equals is <code>true</code>.</p>
* @see Object#equals(Object)
*/
public EqualsBuilder() {
// do nothing for now.
}
//-------------------------------------------------------------------------
/**
* <p>This method uses reflection to determine if the two <code>Object</code>s
* are equal.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run under
* a security manager, if the permissions are not set up correctly. It is also
* not as efficient as testing explicitly.</p>
*
* <p>Transient members will be not be tested, as they are likely derived
* fields, and not part of the value of the Object.</p>
*
* <p>Static fields will not be tested. Superclass fields will be included.</p>
*
* @param lhs <code>this</code> object
* @param rhs the other object
* @param excludeFields Collection of String field names to exclude from testing
* @return <code>true</code> if the two Objects have tested equals.
*/
public static boolean reflectionEquals(Object lhs, Object rhs, Collection<String> excludeFields) {
return reflectionEquals(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
/**
* <p>This method uses reflection to determine if the two <code>Object</code>s
* are equal.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run under
* a security manager, if the permissions are not set up correctly. It is also
* not as efficient as testing explicitly.</p>
*
* <p>Transient members will be not be tested, as they are likely derived
* fields, and not part of the value of the Object.</p>
*
* <p>Static fields will not be tested. Superclass fields will be included.</p>
*
* @param lhs <code>this</code> object
* @param rhs the other object
* @param excludeFields array of field names to exclude from testing
* @return <code>true</code> if the two Objects have tested equals.
*/
public static boolean reflectionEquals(Object lhs, Object rhs, String... excludeFields) {
return reflectionEquals(lhs, rhs, false, null, excludeFields);
}
/**
* <p>This method uses reflection to determine if the two <code>Object</code>s
* are equal.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run under
* a security manager, if the permissions are not set up correctly. It is also
* not as efficient as testing explicitly.</p>
*
* <p>If the TestTransients parameter is set to <code>true</code>, transient
* members will be tested, otherwise they are ignored, as they are likely
* derived fields, and not part of the value of the <code>Object</code>.</p>
*
* <p>Static fields will not be tested. Superclass fields will be included.</p>
*
* @param lhs <code>this</code> object
* @param rhs the other object
* @param testTransients whether to include transient fields
* @return <code>true</code> if the two Objects have tested equals.
*/
public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients) {
return reflectionEquals(lhs, rhs, testTransients, null);
}
/**
* <p>This method uses reflection to determine if the two <code>Object</code>s
* are equal.</p>
*
* <p>It uses <code>AccessibleObject.setAccessible</code> to gain access to private
* fields. This means that it will throw a security exception if run under
* a security manager, if the permissions are not set up correctly. It is also
* not as efficient as testing explicitly.</p>
*
* <p>If the testTransients parameter is set to <code>true</code>, transient
* members will be tested, otherwise they are ignored, as they are likely
* derived fields, and not part of the value of the <code>Object</code>.</p>
*
* <p>Static fields will not be included. Superclass fields will be appended
* up to and including the specified superclass. A null superclass is treated
* as java.lang.Object.</p>
*
* @param lhs <code>this</code> object
* @param rhs the other object
* @param testTransients whether to include transient fields
* @param reflectUpToClass the superclass to reflect up to (inclusive),
* may be <code>null</code>
* @param excludeFields array of field names to exclude from testing
* @return <code>true</code> if the two Objects have tested equals.
* @since 2.0
*/
public static boolean reflectionEquals(Object lhs, Object rhs, boolean testTransients, Class<?> reflectUpToClass,
String... excludeFields) {
if (lhs == rhs) {
return true;
}
if (lhs == null || rhs == null) {
return false;
}
// Find the leaf class since there may be transients in the leaf
// class or in classes between the leaf and root.
// If we are not testing transients or a subclass has no ivars,
// then a subclass can test equals to a superclass.
Class<?> lhsClass = lhs.getClass();
Class<?> rhsClass = rhs.getClass();
Class<?> testClass;
if (lhsClass.isInstance(rhs)) {
testClass = lhsClass;
if (!rhsClass.isInstance(lhs)) {
// rhsClass is a subclass of lhsClass
testClass = rhsClass;
}
} else if (rhsClass.isInstance(lhs)) {
testClass = rhsClass;
if (!lhsClass.isInstance(rhs)) {
// lhsClass is a subclass of rhsClass
testClass = lhsClass;
}
} else {
// The two classes are not related.
return false;
}
EqualsBuilder equalsBuilder = new EqualsBuilder();
try {
reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
while (testClass.getSuperclass() != null && testClass != reflectUpToClass) {
testClass = testClass.getSuperclass();
reflectionAppend(lhs, rhs, testClass, equalsBuilder, testTransients, excludeFields);
}
} catch (IllegalArgumentException e) {
// In this case, we tried to test a subclass vs. a superclass and
// the subclass has ivars or the ivars are transient and
// we are testing transients.
// If a subclass has ivars that we are trying to test them, we get an
// exception and we know that the objects are not equal.
return false;
}
return equalsBuilder.isEquals();
}
/**
* <p>Appends the fields and values defined by the given object of the
* given Class.</p>
*
* @param lhs the left hand object
* @param rhs the right hand object
* @param clazz the class to append details of
* @param builder the builder to append to
* @param useTransients whether to test transient fields
* @param excludeFields array of field names to exclude from testing
*/
private static void reflectionAppend(
Object lhs,
Object rhs,
Class<?> clazz,
EqualsBuilder builder,
boolean useTransients,
String[] excludeFields) {
if (isRegistered(lhs, rhs)) {
return;
}
try {
register(lhs, rhs);
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (int i = 0; i < fields.length && builder.isEquals; i++) {
Field f = fields[i];
if (!ArrayUtils.contains(excludeFields, f.getName())
&& (f.getName().indexOf('$') == -1)
&& (useTransients || !Modifier.isTransient(f.getModifiers()))
&& (!Modifier.isStatic(f.getModifiers()))) {
try {
builder.append(f.get(lhs), f.get(rhs));
} catch (IllegalAccessException e) {
//this can't happen. Would get a Security exception instead
//throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
}
}
} finally {
unregister(lhs, rhs);
}
}
//-------------------------------------------------------------------------
/**
* <p>Adds the result of <code>super.equals()</code> to this builder.</p>
*
* @param superEquals the result of calling <code>super.equals()</code>
* @return EqualsBuilder - used to chain calls.
* @since 2.0
*/
public EqualsBuilder appendSuper(boolean superEquals) {
if (isEquals == false) {
return this;
}
isEquals = superEquals;
return this;
}
//-------------------------------------------------------------------------
/**
* <p>Test if two <code>Object</code>s are equal using their
* <code>equals</code> method.</p>
*
* @param lhs the left hand object
* @param rhs the right hand object
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(Object lhs, Object rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
Class<?> lhsClass = lhs.getClass();
if (!lhsClass.isArray()) {
// The simple case, not an array, just test the element
isEquals = lhs.equals(rhs);
} else if (lhs.getClass() != rhs.getClass()) {
// Here when we compare different dimensions, for example: a boolean[][] to a boolean[]
this.setEquals(false);
}
// 'Switch' on type of array, to dispatch to the correct handler
// This handles multi dimensional arrays of the same depth
else if (lhs instanceof long[]) {
append((long[]) lhs, (long[]) rhs);
} else if (lhs instanceof int[]) {
append((int[]) lhs, (int[]) rhs);
} else if (lhs instanceof short[]) {
append((short[]) lhs, (short[]) rhs);
} else if (lhs instanceof char[]) {
append((char[]) lhs, (char[]) rhs);
} else if (lhs instanceof byte[]) {
append((byte[]) lhs, (byte[]) rhs);
} else if (lhs instanceof double[]) {
append((double[]) lhs, (double[]) rhs);
} else if (lhs instanceof float[]) {
append((float[]) lhs, (float[]) rhs);
} else if (lhs instanceof boolean[]) {
append((boolean[]) lhs, (boolean[]) rhs);
} else {
// Not an array of primitives
append((Object[]) lhs, (Object[]) rhs);
}
return this;
}
/**
* <p>
* Test if two <code>long</code> s are equal.
* </p>
*
* @param lhs
* the left hand <code>long</code>
* @param rhs
* the right hand <code>long</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(long lhs, long rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Test if two <code>int</code>s are equal.</p>
*
* @param lhs the left hand <code>int</code>
* @param rhs the right hand <code>int</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(int lhs, int rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Test if two <code>short</code>s are equal.</p>
*
* @param lhs the left hand <code>short</code>
* @param rhs the right hand <code>short</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(short lhs, short rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Test if two <code>char</code>s are equal.</p>
*
* @param lhs the left hand <code>char</code>
* @param rhs the right hand <code>char</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(char lhs, char rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Test if two <code>byte</code>s are equal.</p>
*
* @param lhs the left hand <code>byte</code>
* @param rhs the right hand <code>byte</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(byte lhs, byte rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Test if two <code>double</code>s are equal by testing that the
* pattern of bits returned by <code>doubleToLong</code> are equal.</p>
*
* <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
*
* <p>It is compatible with the hash code generated by
* <code>HashCodeBuilder</code>.</p>
*
* @param lhs the left hand <code>double</code>
* @param rhs the right hand <code>double</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(double lhs, double rhs) {
if (isEquals == false) {
return this;
}
return append(Double.doubleToLongBits(lhs), Double.doubleToLongBits(rhs));
}
/**
* <p>Test if two <code>float</code>s are equal byt testing that the
* pattern of bits returned by doubleToLong are equal.</p>
*
* <p>This handles NaNs, Infinities, and <code>-0.0</code>.</p>
*
* <p>It is compatible with the hash code generated by
* <code>HashCodeBuilder</code>.</p>
*
* @param lhs the left hand <code>float</code>
* @param rhs the right hand <code>float</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(float lhs, float rhs) {
if (isEquals == false) {
return this;
}
return append(Float.floatToIntBits(lhs), Float.floatToIntBits(rhs));
}
/**
* <p>Test if two <code>booleans</code>s are equal.</p>
*
* @param lhs the left hand <code>boolean</code>
* @param rhs the right hand <code>boolean</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(boolean lhs, boolean rhs) {
if (isEquals == false) {
return this;
}
isEquals = (lhs == rhs);
return this;
}
/**
* <p>Performs a deep comparison of two <code>Object</code> arrays.</p>
*
* <p>This also will be called for the top level of
* multi-dimensional, ragged, and multi-typed arrays.</p>
*
* @param lhs the left hand <code>Object[]</code>
* @param rhs the right hand <code>Object[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(Object[] lhs, Object[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>long</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(long, long)} is used.</p>
*
* @param lhs the left hand <code>long[]</code>
* @param rhs the right hand <code>long[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(long[] lhs, long[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>int</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(int, int)} is used.</p>
*
* @param lhs the left hand <code>int[]</code>
* @param rhs the right hand <code>int[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(int[] lhs, int[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>short</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(short, short)} is used.</p>
*
* @param lhs the left hand <code>short[]</code>
* @param rhs the right hand <code>short[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(short[] lhs, short[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>char</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(char, char)} is used.</p>
*
* @param lhs the left hand <code>char[]</code>
* @param rhs the right hand <code>char[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(char[] lhs, char[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>byte</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(byte, byte)} is used.</p>
*
* @param lhs the left hand <code>byte[]</code>
* @param rhs the right hand <code>byte[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(byte[] lhs, byte[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>double</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(double, double)} is used.</p>
*
* @param lhs the left hand <code>double[]</code>
* @param rhs the right hand <code>double[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(double[] lhs, double[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>float</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(float, float)} is used.</p>
*
* @param lhs the left hand <code>float[]</code>
* @param rhs the right hand <code>float[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(float[] lhs, float[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Deep comparison of array of <code>boolean</code>. Length and all
* values are compared.</p>
*
* <p>The method {@link #append(boolean, boolean)} is used.</p>
*
* @param lhs the left hand <code>boolean[]</code>
* @param rhs the right hand <code>boolean[]</code>
* @return EqualsBuilder - used to chain calls.
*/
public EqualsBuilder append(boolean[] lhs, boolean[] rhs) {
if (isEquals == false) {
return this;
}
if (lhs == rhs) {
return this;
}
if (lhs == null || rhs == null) {
this.setEquals(false);
return this;
}
if (lhs.length != rhs.length) {
this.setEquals(false);
return this;
}
for (int i = 0; i < lhs.length && isEquals; ++i) {
append(lhs[i], rhs[i]);
}
return this;
}
/**
* <p>Returns <code>true</code> if the fields that have been checked
* are all equal.</p>
*
* @return boolean
*/
public boolean isEquals() {
return this.isEquals;
}
/**
* <p>Returns <code>true</code> if the fields that have been checked
* are all equal.</p>
*
* @return <code>true</code> if all of the fields that have been checked
* are equal, <code>false</code> otherwise.
*
* @since 3.0
*/
public Boolean build() {
return Boolean.valueOf(isEquals());
}
/**
* Sets the <code>isEquals</code> value.
*
* @param isEquals The value to set.
* @since 2.1
*/
protected void setEquals(boolean isEquals) {
this.isEquals = isEquals;
}
/**
* Reset the EqualsBuilder so you can use the same object again
* @since 2.5
*/
public void reset() {
this.isEquals = true;
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import external.org.apache.commons.lang3.ArrayUtils;
/**
* <p>
* Assists in implementing {@link Object#hashCode()} methods.
* </p>
*
* <p>
* This class enables a good <code>hashCode</code> method to be built for any class. It follows the rules laid out in
* the book <a href="http://java.sun.com/docs/books/effective/index.html">Effective Java</a> by Joshua Bloch. Writing a
* good <code>hashCode</code> method is actually quite difficult. This class aims to simplify the process.
* </p>
*
* <p>
* The following is the approach taken. When appending a data field, the current total is multiplied by the
* multiplier then a relevant value
* for that data type is added. For example, if the current hashCode is 17, and the multiplier is 37, then
* appending the integer 45 will create a hashcode of 674, namely 17 * 37 + 45.
* </p>
*
* <p>
* All relevant fields from the object should be included in the <code>hashCode</code> method. Derived fields may be
* excluded. In general, any field used in the <code>equals</code> method must be used in the <code>hashCode</code>
* method.
* </p>
*
* <p>
* To use this class write code as follows:
* </p>
*
* <pre>
* public class Person {
* String name;
* int age;
* boolean smoker;
* ...
*
* public int hashCode() {
* // you pick a hard-coded, randomly chosen, non-zero, odd number
* // ideally different for each class
* return new HashCodeBuilder(17, 37).
* append(name).
* append(age).
* append(smoker).
* toHashCode();
* }
* }
* </pre>
*
* <p>
* If required, the superclass <code>hashCode()</code> can be added using {@link #appendSuper}.
* </p>
*
* <p>
* Alternatively, there is a method that uses reflection to determine the fields to test. Because these fields are
* usually private, the method, <code>reflectionHashCode</code>, uses <code>AccessibleObject.setAccessible</code>
* to change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions
* are set up correctly. It is also slower than testing explicitly.
* </p>
*
* <p>
* A typical invocation for this method would look like:
* </p>
*
* <pre>
* public int hashCode() {
* return HashCodeBuilder.reflectionHashCode(this);
* }
* </pre>
*
* @since 1.0
* @version $Id: HashCodeBuilder.java 1144929 2011-07-10 18:26:16Z ggregory $
*/
public class HashCodeBuilder implements Builder<Integer> {
/**
* <p>
* A registry of objects used by reflection methods to detect cyclical object references and avoid infinite loops.
* </p>
*
* @since 2.3
*/
private static final ThreadLocal<Set<IDKey>> REGISTRY = new ThreadLocal<Set<IDKey>>();
/*
* NOTE: we cannot store the actual objects in a HashSet, as that would use the very hashCode()
* we are in the process of calculating.
*
* So we generate a one-to-one mapping from the original object to a new object.
*
* Now HashSet uses equals() to determine if two elements with the same hashcode really
* are equal, so we also need to ensure that the replacement objects are only equal
* if the original objects are identical.
*
* The original implementation (2.4 and before) used the System.indentityHashCode()
* method - however this is not guaranteed to generate unique ids (e.g. LANG-459)
*
* We now use the IDKey helper class (adapted from org.apache.axis.utils.IDKey)
* to disambiguate the duplicate ids.
*/
/**
* <p>
* Returns the registry of objects being traversed by the reflection methods in the current thread.
* </p>
*
* @return Set the registry of objects being traversed
* @since 2.3
*/
static Set<IDKey> getRegistry() {
return REGISTRY.get();
}
/**
* <p>
* Returns <code>true</code> if the registry contains the given object. Used by the reflection methods to avoid
* infinite loops.
* </p>
*
* @param value
* The object to lookup in the registry.
* @return boolean <code>true</code> if the registry contains the given object.
* @since 2.3
*/
static boolean isRegistered(Object value) {
Set<IDKey> registry = getRegistry();
return registry != null && registry.contains(new IDKey(value));
}
/**
* <p>
* Appends the fields and values defined by the given object of the given <code>Class</code>.
* </p>
*
* @param object
* the object to append details of
* @param clazz
* the class to append details of
* @param builder
* the builder to append to
* @param useTransients
* whether to use transient fields
* @param excludeFields
* Collection of String field names to exclude from use in calculation of hash code
*/
private static void reflectionAppend(Object object, Class<?> clazz, HashCodeBuilder builder, boolean useTransients,
String[] excludeFields) {
if (isRegistered(object)) {
return;
}
try {
register(object);
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
if (!ArrayUtils.contains(excludeFields, field.getName())
&& (field.getName().indexOf('$') == -1)
&& (useTransients || !Modifier.isTransient(field.getModifiers()))
&& (!Modifier.isStatic(field.getModifiers()))) {
try {
Object fieldValue = field.get(object);
builder.append(fieldValue);
} catch (IllegalAccessException e) {
// this can't happen. Would get a Security exception instead
// throw a runtime exception in case the impossible happens.
throw new InternalError("Unexpected IllegalAccessException");
}
}
}
} finally {
unregister(object);
}
}
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* Transient members will be not be used, as they are likely derived fields, and not part of the value of the
* <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be tested. Superclass fields will be included.
* </p>
*
* <p>
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
* however this is not vital. Prime numbers are preferred, especially for the multiplier.
* </p>
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a <code>hashCode</code> for
* @return int hash code
* @throws IllegalArgumentException
* if the Object is <code>null</code>
* @throws IllegalArgumentException
* if the number is zero or even
*/
public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object) {
return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, false, null);
}
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be tested. Superclass fields will be included.
* </p>
*
* <p>
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
* however this is not vital. Prime numbers are preferred, especially for the multiplier.
* </p>
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a <code>hashCode</code> for
* @param testTransients
* whether to include transient fields
* @return int hash code
* @throws IllegalArgumentException
* if the Object is <code>null</code>
* @throws IllegalArgumentException
* if the number is zero or even
*/
public static int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, Object object,
boolean testTransients) {
return reflectionHashCode(initialNonZeroOddNumber, multiplierNonZeroOddNumber, object, testTransients, null);
}
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be included. Superclass fields will be included up to and including the specified
* superclass. A null superclass is treated as java.lang.Object.
* </p>
*
* <p>
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
* however this is not vital. Prime numbers are preferred, especially for the multiplier.
* </p>
*
* @param <T>
* the type of the object involved
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @param object
* the Object to create a <code>hashCode</code> for
* @param testTransients
* whether to include transient fields
* @param reflectUpToClass
* the superclass to reflect up to (inclusive), may be <code>null</code>
* @param excludeFields
* array of field names to exclude from use in calculation of hash code
* @return int hash code
* @throws IllegalArgumentException
* if the Object is <code>null</code>
* @throws IllegalArgumentException
* if the number is zero or even
* @since 2.0
*/
public static <T> int reflectionHashCode(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber, T object,
boolean testTransients, Class<? super T> reflectUpToClass, String... excludeFields) {
if (object == null) {
throw new IllegalArgumentException("The object to build a hash code for must not be null");
}
HashCodeBuilder builder = new HashCodeBuilder(initialNonZeroOddNumber, multiplierNonZeroOddNumber);
Class<?> clazz = object.getClass();
reflectionAppend(object, clazz, builder, testTransients, excludeFields);
while (clazz.getSuperclass() != null && clazz != reflectUpToClass) {
clazz = clazz.getSuperclass();
reflectionAppend(object, clazz, builder, testTransients, excludeFields);
}
return builder.toHashCode();
}
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* This constructor uses two hard coded choices for the constants needed to build a hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <P>
* If the TestTransients parameter is set to <code>true</code>, transient members will be tested, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be tested. Superclass fields will be included.
* </p>
*
* @param object
* the Object to create a <code>hashCode</code> for
* @param testTransients
* whether to include transient fields
* @return int hash code
* @throws IllegalArgumentException
* if the object is <code>null</code>
*/
public static int reflectionHashCode(Object object, boolean testTransients) {
return reflectionHashCode(17, 37, object, testTransients, null);
}
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* This constructor uses two hard coded choices for the constants needed to build a hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* Transient members will be not be used, as they are likely derived fields, and not part of the value of the
* <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be tested. Superclass fields will be included.
* </p>
*
* @param object
* the Object to create a <code>hashCode</code> for
* @param excludeFields
* Collection of String field names to exclude from use in calculation of hash code
* @return int hash code
* @throws IllegalArgumentException
* if the object is <code>null</code>
*/
public static int reflectionHashCode(Object object, Collection<String> excludeFields) {
return reflectionHashCode(object, ReflectionToStringBuilder.toNoNullStringArray(excludeFields));
}
// -------------------------------------------------------------------------
/**
* <p>
* This method uses reflection to build a valid hash code.
* </p>
*
* <p>
* This constructor uses two hard coded choices for the constants needed to build a hash code.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* Transient members will be not be used, as they are likely derived fields, and not part of the value of the
* <code>Object</code>.
* </p>
*
* <p>
* Static fields will not be tested. Superclass fields will be included.
* </p>
*
* @param object
* the Object to create a <code>hashCode</code> for
* @param excludeFields
* array of field names to exclude from use in calculation of hash code
* @return int hash code
* @throws IllegalArgumentException
* if the object is <code>null</code>
*/
public static int reflectionHashCode(Object object, String... excludeFields) {
return reflectionHashCode(17, 37, object, false, null, excludeFields);
}
/**
* <p>
* Registers the given object. Used by the reflection methods to avoid infinite loops.
* </p>
*
* @param value
* The object to register.
*/
static void register(Object value) {
synchronized (HashCodeBuilder.class) {
if (getRegistry() == null) {
REGISTRY.set(new HashSet<IDKey>());
}
}
getRegistry().add(new IDKey(value));
}
/**
* <p>
* Unregisters the given object.
* </p>
*
* <p>
* Used by the reflection methods to avoid infinite loops.
*
* @param value
* The object to unregister.
* @since 2.3
*/
static void unregister(Object value) {
Set<IDKey> registry = getRegistry();
if (registry != null) {
registry.remove(new IDKey(value));
synchronized (HashCodeBuilder.class) {
//read again
registry = getRegistry();
if (registry != null && registry.isEmpty()) {
REGISTRY.remove();
}
}
}
}
/**
* Constant to use in building the hashCode.
*/
private final int iConstant;
/**
* Running total of the hashCode.
*/
private int iTotal = 0;
/**
* <p>
* Uses two hard coded choices for the constants needed to build a <code>hashCode</code>.
* </p>
*/
public HashCodeBuilder() {
iConstant = 37;
iTotal = 17;
}
/**
* <p>
* Two randomly chosen, non-zero, odd numbers must be passed in. Ideally these should be different for each class,
* however this is not vital.
* </p>
*
* <p>
* Prime numbers are preferred, especially for the multiplier.
* </p>
*
* @param initialNonZeroOddNumber
* a non-zero, odd number used as the initial value
* @param multiplierNonZeroOddNumber
* a non-zero, odd number used as the multiplier
* @throws IllegalArgumentException
* if the number is zero or even
*/
public HashCodeBuilder(int initialNonZeroOddNumber, int multiplierNonZeroOddNumber) {
if (initialNonZeroOddNumber == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires a non zero initial value");
}
if (initialNonZeroOddNumber % 2 == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires an odd initial value");
}
if (multiplierNonZeroOddNumber == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires a non zero multiplier");
}
if (multiplierNonZeroOddNumber % 2 == 0) {
throw new IllegalArgumentException("HashCodeBuilder requires an odd multiplier");
}
iConstant = multiplierNonZeroOddNumber;
iTotal = initialNonZeroOddNumber;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>boolean</code>.
* </p>
* <p>
* This adds <code>1</code> when true, and <code>0</code> when false to the <code>hashCode</code>.
* </p>
* <p>
* This is in contrast to the standard <code>java.lang.Boolean.hashCode</code> handling, which computes
* a <code>hashCode</code> value of <code>1231</code> for <code>java.lang.Boolean</code> instances
* that represent <code>true</code> or <code>1237</code> for <code>java.lang.Boolean</code> instances
* that represent <code>false</code>.
* </p>
* <p>
* This is in accordance with the <quote>Effective Java</quote> design.
* </p>
*
* @param value
* the boolean to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(boolean value) {
iTotal = iTotal * iConstant + (value ? 0 : 1);
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>boolean</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(boolean[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (boolean element : array) {
append(element);
}
}
return this;
}
// -------------------------------------------------------------------------
/**
* <p>
* Append a <code>hashCode</code> for a <code>byte</code>.
* </p>
*
* @param value
* the byte to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(byte value) {
iTotal = iTotal * iConstant + value;
return this;
}
// -------------------------------------------------------------------------
/**
* <p>
* Append a <code>hashCode</code> for a <code>byte</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(byte[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (byte element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>char</code>.
* </p>
*
* @param value
* the char to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(char value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>char</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(char[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (char element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>double</code>.
* </p>
*
* @param value
* the double to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(double value) {
return append(Double.doubleToLongBits(value));
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>double</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(double[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (double element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>float</code>.
* </p>
*
* @param value
* the float to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(float value) {
iTotal = iTotal * iConstant + Float.floatToIntBits(value);
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>float</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(float[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (float element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for an <code>int</code>.
* </p>
*
* @param value
* the int to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(int value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for an <code>int</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(int[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (int element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>long</code>.
* </p>
*
* @param value
* the long to add to the <code>hashCode</code>
* @return this
*/
// NOTE: This method uses >> and not >>> as Effective Java and
// Long.hashCode do. Ideally we should switch to >>> at
// some stage. There are backwards compat issues, so
// that will have to wait for the time being. cf LANG-342.
public HashCodeBuilder append(long value) {
iTotal = iTotal * iConstant + ((int) (value ^ (value >> 32)));
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>long</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(long[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (long element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for an <code>Object</code>.
* </p>
*
* @param object
* the Object to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(Object object) {
if (object == null) {
iTotal = iTotal * iConstant;
} else {
if(object.getClass().isArray()) {
// 'Switch' on type of array, to dispatch to the correct handler
// This handles multi dimensional arrays
if (object instanceof long[]) {
append((long[]) object);
} else if (object instanceof int[]) {
append((int[]) object);
} else if (object instanceof short[]) {
append((short[]) object);
} else if (object instanceof char[]) {
append((char[]) object);
} else if (object instanceof byte[]) {
append((byte[]) object);
} else if (object instanceof double[]) {
append((double[]) object);
} else if (object instanceof float[]) {
append((float[]) object);
} else if (object instanceof boolean[]) {
append((boolean[]) object);
} else {
// Not an array of primitives
append((Object[]) object);
}
} else {
iTotal = iTotal * iConstant + object.hashCode();
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for an <code>Object</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(Object[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (Object element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>short</code>.
* </p>
*
* @param value
* the short to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(short value) {
iTotal = iTotal * iConstant + value;
return this;
}
/**
* <p>
* Append a <code>hashCode</code> for a <code>short</code> array.
* </p>
*
* @param array
* the array to add to the <code>hashCode</code>
* @return this
*/
public HashCodeBuilder append(short[] array) {
if (array == null) {
iTotal = iTotal * iConstant;
} else {
for (short element : array) {
append(element);
}
}
return this;
}
/**
* <p>
* Adds the result of super.hashCode() to this builder.
* </p>
*
* @param superHashCode
* the result of calling <code>super.hashCode()</code>
* @return this HashCodeBuilder, used to chain calls.
* @since 2.0
*/
public HashCodeBuilder appendSuper(int superHashCode) {
iTotal = iTotal * iConstant + superHashCode;
return this;
}
/**
* <p>
* Return the computed <code>hashCode</code>.
* </p>
*
* @return <code>hashCode</code> based on the fields appended
*/
public int toHashCode() {
return iTotal;
}
/**
* Returns the computed <code>hashCode</code>.
*
* @return <code>hashCode</code> based on the fields appended
*
* @since 3.0
*/
public Integer build() {
return Integer.valueOf(toHashCode());
}
/**
* <p>
* The computed <code>hashCode</code> from toHashCode() is returned due to the likelihood
* of bugs in mis-calling toHashCode() and the unlikeliness of it mattering what the hashCode for
* HashCodeBuilder itself is.</p>
*
* @return <code>hashCode</code> based on the fields appended
* @since 2.5
*/
@Override
public int hashCode() {
return toHashCode();
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
// adapted from org.apache.axis.utils.IDKey
/**
* Wrap an identity key (System.identityHashCode())
* so that an object can only be equal() to itself.
*
* This is necessary to disambiguate the occasional duplicate
* identityHashCodes that can occur.
*
*/
final class IDKey {
private final Object value;
private final int id;
/**
* Constructor for IDKey
* @param _value The value
*/
public IDKey(Object _value) {
// This is the Object hashcode
id = System.identityHashCode(_value);
// There have been some cases (LANG-459) that return the
// same identity hash code for different objects. So
// the value is also added to disambiguate these cases.
value = _value;
}
/**
* returns hashcode - i.e. the system identity hashcode.
* @return the hashcode
*/
@Override
public int hashCode() {
return id;
}
/**
* checks if instances are equal
* @param other The other object to compare to
* @return if the instances are for the same object
*/
@Override
public boolean equals(Object other) {
if (!(other instanceof IDKey)) {
return false;
}
IDKey idKey = (IDKey) other;
if (id != idKey.id) {
return false;
}
// Note that identity equals is used.
return value == idKey.value;
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import external.org.apache.commons.lang3.ArrayUtils;
import external.org.apache.commons.lang3.ClassUtils;
/**
* <p>
* Assists in implementing {@link Object#toString()} methods using reflection.
* </p>
* <p>
* This class uses reflection to determine the fields to append. Because these fields are usually private, the class
* uses {@link AccessibleObject#setAccessible(AccessibleObject[], boolean)} to
* change the visibility of the fields. This will fail under a security manager, unless the appropriate permissions are
* set up correctly.
* </p>
* <p>
* Using reflection to access (private) fields circumvents any synchronization protection guarding access to these
* fields. If a toString method cannot safely read a field, you should exclude it from the toString method, or use
* synchronization consistent with the class' lock management around the invocation of the method. Take special care to
* exclude non-thread-safe collection classes, because these classes may throw ConcurrentModificationException if
* modified while the toString method is executing.
* </p>
* <p>
* A typical invocation for this method would look like:
* </p>
* <pre>
* public String toString() {
* return ReflectionToStringBuilder.toString(this);
* }
* </pre>
* <p>
* You can also use the builder to debug 3rd party objects:
* </p>
* <pre>
* System.out.println(&quot;An object: &quot; + ReflectionToStringBuilder.toString(anObject));
* </pre>
* <p>
* A subclass can control field output by overriding the methods:
* <ul>
* <li>{@link #accept(Field)}</li>
* <li>{@link #getValue(Field)}</li>
* </ul>
* </p>
* <p>
* For example, this method does <i>not</i> include the <code>password</code> field in the returned <code>String</code>:
* </p>
* <pre>
* public String toString() {
* return (new ReflectionToStringBuilder(this) {
* protected boolean accept(Field f) {
* return super.accept(f) &amp;&amp; !f.getName().equals(&quot;password&quot;);
* }
* }).toString();
* }
* </pre>
* <p>
* The exact format of the <code>toString</code> is determined by the {@link ToStringStyle} passed into the constructor.
* </p>
*
* @since 2.0
* @version $Id: ReflectionToStringBuilder.java 1200177 2011-11-10 06:14:33Z ggregory $
*/
public class ReflectionToStringBuilder extends ToStringBuilder {
/**
* <p>
* Builds a <code>toString</code> value using the default <code>ToStringStyle</code> through reflection.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* Transient members will be not be included, as they are likely derived. Static fields will not be included.
* Superclass fields will be appended.
* </p>
*
* @param object
* the Object to be output
* @return the String result
* @throws IllegalArgumentException
* if the Object is <code>null</code>
*/
public static String toString(Object object) {
return toString(object, null, false, false, null);
}
/**
* <p>
* Builds a <code>toString</code> value through reflection.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* Transient members will be not be included, as they are likely derived. Static fields will not be included.
* Superclass fields will be appended.
* </p>
*
* <p>
* If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
* </p>
*
* @param object
* the Object to be output
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException
* if the Object or <code>ToStringStyle</code> is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style) {
return toString(object, style, false, false, null);
}
/**
* <p>
* Builds a <code>toString</code> value through reflection.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* If the <code>outputTransients</code> is <code>true</code>, transient members will be output, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the Object.
* </p>
*
* <p>
* Static fields will not be included. Superclass fields will be appended.
* </p>
*
* <p>
* If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
* </p>
*
* @param object
* the Object to be output
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @param outputTransients
* whether to include transient fields
* @return the String result
* @throws IllegalArgumentException
* if the Object is <code>null</code>
*/
public static String toString(Object object, ToStringStyle style, boolean outputTransients) {
return toString(object, style, outputTransients, false, null);
}
/**
* <p>
* Builds a <code>toString</code> value through reflection.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* If the <code>outputTransients</code> is <code>true</code>, transient fields will be output, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the Object.
* </p>
*
* <p>
* If the <code>outputStatics</code> is <code>true</code>, static fields will be output, otherwise they are
* ignored.
* </p>
*
* <p>
* Static fields will not be included. Superclass fields will be appended.
* </p>
*
* <p>
* If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
* </p>
*
* @param object
* the Object to be output
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @param outputTransients
* whether to include transient fields
* @param outputStatics
* whether to include transient fields
* @return the String result
* @throws IllegalArgumentException
* if the Object is <code>null</code>
* @since 2.1
*/
public static String toString(Object object, ToStringStyle style, boolean outputTransients, boolean outputStatics) {
return toString(object, style, outputTransients, outputStatics, null);
}
/**
* <p>
* Builds a <code>toString</code> value through reflection.
* </p>
*
* <p>
* It uses <code>AccessibleObject.setAccessible</code> to gain access to private fields. This means that it will
* throw a security exception if run under a security manager, if the permissions are not set up correctly. It is
* also not as efficient as testing explicitly.
* </p>
*
* <p>
* If the <code>outputTransients</code> is <code>true</code>, transient fields will be output, otherwise they
* are ignored, as they are likely derived fields, and not part of the value of the Object.
* </p>
*
* <p>
* If the <code>outputStatics</code> is <code>true</code>, static fields will be output, otherwise they are
* ignored.
* </p>
*
* <p>
* Superclass fields will be appended up to and including the specified superclass. A null superclass is treated as
* <code>java.lang.Object</code>.
* </p>
*
* <p>
* If the style is <code>null</code>, the default <code>ToStringStyle</code> is used.
* </p>
*
* @param <T>
* the type of the object
* @param object
* the Object to be output
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @param outputTransients
* whether to include transient fields
* @param outputStatics
* whether to include static fields
* @param reflectUpToClass
* the superclass to reflect up to (inclusive), may be <code>null</code>
* @return the String result
* @throws IllegalArgumentException
* if the Object is <code>null</code>
* @since 2.1
*/
public static <T> String toString(
T object, ToStringStyle style, boolean outputTransients,
boolean outputStatics, Class<? super T> reflectUpToClass) {
return new ReflectionToStringBuilder(object, style, null, reflectUpToClass, outputTransients, outputStatics)
.toString();
}
/**
* Builds a String for a toString method excluding the given field names.
*
* @param object
* The object to "toString".
* @param excludeFieldNames
* The field names to exclude. Null excludes nothing.
* @return The toString value.
*/
public static String toStringExclude(Object object, Collection<String> excludeFieldNames) {
return toStringExclude(object, toNoNullStringArray(excludeFieldNames));
}
/**
* Converts the given Collection into an array of Strings. The returned array does not contain <code>null</code>
* entries. Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException} if an array element
* is <code>null</code>.
*
* @param collection
* The collection to convert
* @return A new array of Strings.
*/
static String[] toNoNullStringArray(Collection<String> collection) {
if (collection == null) {
return ArrayUtils.EMPTY_STRING_ARRAY;
}
return toNoNullStringArray(collection.toArray());
}
/**
* Returns a new array of Strings without null elements. Internal method used to normalize exclude lists
* (arrays and collections). Note that {@link Arrays#sort(Object[])} will throw an {@link NullPointerException}
* if an array element is <code>null</code>.
*
* @param array
* The array to check
* @return The given array or a new array without null.
*/
static String[] toNoNullStringArray(Object[] array) {
List<String> list = new ArrayList<String>(array.length);
for (Object e : array) {
if (e != null) {
list.add(e.toString());
}
}
return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
}
/**
* Builds a String for a toString method excluding the given field names.
*
* @param object
* The object to "toString".
* @param excludeFieldNames
* The field names to exclude
* @return The toString value.
*/
public static String toStringExclude(Object object, String... excludeFieldNames) {
return new ReflectionToStringBuilder(object).setExcludeFieldNames(excludeFieldNames).toString();
}
/**
* Whether or not to append static fields.
*/
private boolean appendStatics = false;
/**
* Whether or not to append transient fields.
*/
private boolean appendTransients = false;
/**
* Which field names to exclude from output. Intended for fields like <code>"password"</code>.
*
* @since 3.0 this is protected instead of private
*/
protected String[] excludeFieldNames;
/**
* The last super class to stop appending fields for.
*/
private Class<?> upToClass = null;
/**
* <p>
* Constructor.
* </p>
*
* <p>
* This constructor outputs using the default style set with <code>setDefaultStyle</code>.
* </p>
*
* @param object
* the Object to build a <code>toString</code> for, must not be <code>null</code>
* @throws IllegalArgumentException
* if the Object passed in is <code>null</code>
*/
public ReflectionToStringBuilder(Object object) {
super(object);
}
/**
* <p>
* Constructor.
* </p>
*
* <p>
* If the style is <code>null</code>, the default style is used.
* </p>
*
* @param object
* the Object to build a <code>toString</code> for, must not be <code>null</code>
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @throws IllegalArgumentException
* if the Object passed in is <code>null</code>
*/
public ReflectionToStringBuilder(Object object, ToStringStyle style) {
super(object, style);
}
/**
* <p>
* Constructor.
* </p>
*
* <p>
* If the style is <code>null</code>, the default style is used.
* </p>
*
* <p>
* If the buffer is <code>null</code>, a new one is created.
* </p>
*
* @param object
* the Object to build a <code>toString</code> for
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @param buffer
* the <code>StringBuffer</code> to populate, may be <code>null</code>
* @throws IllegalArgumentException
* if the Object passed in is <code>null</code>
*/
public ReflectionToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
super(object, style, buffer);
}
/**
* Constructor.
*
* @param <T>
* the type of the object
* @param object
* the Object to build a <code>toString</code> for
* @param style
* the style of the <code>toString</code> to create, may be <code>null</code>
* @param buffer
* the <code>StringBuffer</code> to populate, may be <code>null</code>
* @param reflectUpToClass
* the superclass to reflect up to (inclusive), may be <code>null</code>
* @param outputTransients
* whether to include transient fields
* @param outputStatics
* whether to include static fields
* @since 2.1
*/
public <T> ReflectionToStringBuilder(
T object, ToStringStyle style, StringBuffer buffer,
Class<? super T> reflectUpToClass, boolean outputTransients, boolean outputStatics) {
super(object, style, buffer);
this.setUpToClass(reflectUpToClass);
this.setAppendTransients(outputTransients);
this.setAppendStatics(outputStatics);
}
/**
* Returns whether or not to append the given <code>Field</code>.
* <ul>
* <li>Transient fields are appended only if {@link #isAppendTransients()} returns <code>true</code>.
* <li>Static fields are appended only if {@link #isAppendStatics()} returns <code>true</code>.
* <li>Inner class fields are not appened.</li>
* </ul>
*
* @param field
* The Field to test.
* @return Whether or not to append the given <code>Field</code>.
*/
protected boolean accept(Field field) {
if (field.getName().indexOf(ClassUtils.INNER_CLASS_SEPARATOR_CHAR) != -1) {
// Reject field from inner class.
return false;
}
if (Modifier.isTransient(field.getModifiers()) && !this.isAppendTransients()) {
// Reject transient fields.
return false;
}
if (Modifier.isStatic(field.getModifiers()) && !this.isAppendStatics()) {
// Reject static fields.
return false;
}
if (this.excludeFieldNames != null
&& Arrays.binarySearch(this.excludeFieldNames, field.getName()) >= 0) {
// Reject fields from the getExcludeFieldNames list.
return false;
}
return true;
}
/**
* <p>
* Appends the fields and values defined by the given object of the given Class.
* </p>
*
* <p>
* If a cycle is detected as an object is &quot;toString()'ed&quot;, such an object is rendered as if
* <code>Object.toString()</code> had been called and not implemented by the object.
* </p>
*
* @param clazz
* The class of object parameter
*/
protected void appendFieldsIn(Class<?> clazz) {
if (clazz.isArray()) {
this.reflectionAppendArray(this.getObject());
return;
}
Field[] fields = clazz.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
for (Field field : fields) {
String fieldName = field.getName();
if (this.accept(field)) {
try {
// Warning: Field.get(Object) creates wrappers objects
// for primitive types.
Object fieldValue = this.getValue(field);
this.append(fieldName, fieldValue);
} catch (IllegalAccessException ex) {
//this can't happen. Would get a Security exception
// instead
//throw a runtime exception in case the impossible
// happens.
throw new InternalError("Unexpected IllegalAccessException: " + ex.getMessage());
}
}
}
}
/**
* @return Returns the excludeFieldNames.
*/
public String[] getExcludeFieldNames() {
return this.excludeFieldNames.clone();
}
/**
* <p>
* Gets the last super class to stop appending fields for.
* </p>
*
* @return The last super class to stop appending fields for.
*/
public Class<?> getUpToClass() {
return this.upToClass;
}
/**
* <p>
* Calls <code>java.lang.reflect.Field.get(Object)</code>.
* </p>
*
* @param field
* The Field to query.
* @return The Object from the given Field.
*
* @throws IllegalArgumentException
* see {@link Field#get(Object)}
* @throws IllegalAccessException
* see {@link Field#get(Object)}
*
* @see Field#get(Object)
*/
protected Object getValue(Field field) throws IllegalArgumentException, IllegalAccessException {
return field.get(this.getObject());
}
/**
* <p>
* Gets whether or not to append static fields.
* </p>
*
* @return Whether or not to append static fields.
* @since 2.1
*/
public boolean isAppendStatics() {
return this.appendStatics;
}
/**
* <p>
* Gets whether or not to append transient fields.
* </p>
*
* @return Whether or not to append transient fields.
*/
public boolean isAppendTransients() {
return this.appendTransients;
}
/**
* <p>
* Append to the <code>toString</code> an <code>Object</code> array.
* </p>
*
* @param array
* the array to add to the <code>toString</code>
* @return this
*/
public ReflectionToStringBuilder reflectionAppendArray(Object array) {
this.getStyle().reflectionAppendArrayDetail(this.getStringBuffer(), null, array);
return this;
}
/**
* <p>
* Sets whether or not to append static fields.
* </p>
*
* @param appendStatics
* Whether or not to append static fields.
* @since 2.1
*/
public void setAppendStatics(boolean appendStatics) {
this.appendStatics = appendStatics;
}
/**
* <p>
* Sets whether or not to append transient fields.
* </p>
*
* @param appendTransients
* Whether or not to append transient fields.
*/
public void setAppendTransients(boolean appendTransients) {
this.appendTransients = appendTransients;
}
/**
* Sets the field names to exclude.
*
* @param excludeFieldNamesParam
* The excludeFieldNames to excluding from toString or <code>null</code>.
* @return <code>this</code>
*/
public ReflectionToStringBuilder setExcludeFieldNames(String... excludeFieldNamesParam) {
if (excludeFieldNamesParam == null) {
this.excludeFieldNames = null;
} else {
//clone and remove nulls
this.excludeFieldNames = toNoNullStringArray(excludeFieldNamesParam);
Arrays.sort(this.excludeFieldNames);
}
return this;
}
/**
* <p>
* Sets the last super class to stop appending fields for.
* </p>
*
* @param clazz
* The last super class to stop appending fields for.
*/
public void setUpToClass(Class<?> clazz) {
if (clazz != null) {
Object object = getObject();
if (object != null && clazz.isInstance(object) == false) {
throw new IllegalArgumentException("Specified class is not a superclass of the object");
}
}
this.upToClass = clazz;
}
/**
* <p>
* Gets the String built by this builder.
* </p>
*
* @return the built string
*/
@Override
public String toString() {
if (this.getObject() == null) {
return this.getStyle().getNullText();
}
Class<?> clazz = this.getObject().getClass();
this.appendFieldsIn(clazz);
while (clazz.getSuperclass() != null && clazz != this.getUpToClass()) {
clazz = clazz.getSuperclass();
this.appendFieldsIn(clazz);
}
return super.toString();
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
import external.org.apache.commons.lang3.ObjectUtils;
/**
* <p>Assists in implementing {@link Object#toString()} methods.</p>
*
* <p>This class enables a good and consistent <code>toString()</code> to be built for any
* class or object. This class aims to simplify the process by:</p>
* <ul>
* <li>allowing field names</li>
* <li>handling all types consistently</li>
* <li>handling nulls consistently</li>
* <li>outputting arrays and multi-dimensional arrays</li>
* <li>enabling the detail level to be controlled for Objects and Collections</li>
* <li>handling class hierarchies</li>
* </ul>
*
* <p>To use this class write code as follows:</p>
*
* <pre>
* public class Person {
* String name;
* int age;
* boolean smoker;
*
* ...
*
* public String toString() {
* return new ToStringBuilder(this).
* append("name", name).
* append("age", age).
* append("smoker", smoker).
* toString();
* }
* }
* </pre>
*
* <p>This will produce a toString of the format:
* <code>Person@7f54[name=Stephen,age=29,smoker=false]</code></p>
*
* <p>To add the superclass <code>toString</code>, use {@link #appendSuper}.
* To append the <code>toString</code> from an object that is delegated
* to (or any other object), use {@link #appendToString}.</p>
*
* <p>Alternatively, there is a method that uses reflection to determine
* the fields to test. Because these fields are usually private, the method,
* <code>reflectionToString</code>, uses <code>AccessibleObject.setAccessible</code> to
* change the visibility of the fields. This will fail under a security manager,
* unless the appropriate permissions are set up correctly. It is also
* slower than testing explicitly.</p>
*
* <p>A typical invocation for this method would look like:</p>
*
* <pre>
* public String toString() {
* return ToStringBuilder.reflectionToString(this);
* }
* </pre>
*
* <p>You can also use the builder to debug 3rd party objects:</p>
*
* <pre>
* System.out.println("An object: " + ToStringBuilder.reflectionToString(anObject));
* </pre>
*
* <p>The exact format of the <code>toString</code> is determined by
* the {@link ToStringStyle} passed into the constructor.</p>
*
* @since 1.0
* @version $Id: ToStringBuilder.java 1088899 2011-04-05 05:31:27Z bayard $
*/
public class ToStringBuilder implements Builder<String> {
/**
* The default style of output to use, not null.
*/
private static volatile ToStringStyle defaultStyle = ToStringStyle.DEFAULT_STYLE;
//----------------------------------------------------------------------------
/**
* <p>Gets the default <code>ToStringStyle</code> to use.</p>
*
* <p>This method gets a singleton default value, typically for the whole JVM.
* Changing this default should generally only be done during application startup.
* It is recommended to pass a <code>ToStringStyle</code> to the constructor instead
* of using this global default.</p>
*
* <p>This method can be used from multiple threads.
* Internally, a <code>volatile</code> variable is used to provide the guarantee
* that the latest value set using {@link #setDefaultStyle} is the value returned.
* It is strongly recommended that the default style is only changed during application startup.</p>
*
* <p>One reason for changing the default could be to have a verbose style during
* development and a compact style in production.</p>
*
* @return the default <code>ToStringStyle</code>, never null
*/
public static ToStringStyle getDefaultStyle() {
return defaultStyle;
}
/**
* <p>Sets the default <code>ToStringStyle</code> to use.</p>
*
* <p>This method sets a singleton default value, typically for the whole JVM.
* Changing this default should generally only be done during application startup.
* It is recommended to pass a <code>ToStringStyle</code> to the constructor instead
* of changing this global default.</p>
*
* <p>This method is not intended for use from multiple threads.
* Internally, a <code>volatile</code> variable is used to provide the guarantee
* that the latest value set is the value returned from {@link #getDefaultStyle}.</p>
*
* @param style the default <code>ToStringStyle</code>
* @throws IllegalArgumentException if the style is <code>null</code>
*/
public static void setDefaultStyle(ToStringStyle style) {
if (style == null) {
throw new IllegalArgumentException("The style must not be null");
}
defaultStyle = style;
}
//----------------------------------------------------------------------------
/**
* <p>Uses <code>ReflectionToStringBuilder</code> to generate a
* <code>toString</code> for the specified object.</p>
*
* @param object the Object to be output
* @return the String result
* @see ReflectionToStringBuilder#toString(Object)
*/
public static String reflectionToString(Object object) {
return ReflectionToStringBuilder.toString(object);
}
/**
* <p>Uses <code>ReflectionToStringBuilder</code> to generate a
* <code>toString</code> for the specified object.</p>
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create, may be <code>null</code>
* @return the String result
* @see ReflectionToStringBuilder#toString(Object,ToStringStyle)
*/
public static String reflectionToString(Object object, ToStringStyle style) {
return ReflectionToStringBuilder.toString(object, style);
}
/**
* <p>Uses <code>ReflectionToStringBuilder</code> to generate a
* <code>toString</code> for the specified object.</p>
*
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create, may be <code>null</code>
* @param outputTransients whether to include transient fields
* @return the String result
* @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean)
*/
public static String reflectionToString(Object object, ToStringStyle style, boolean outputTransients) {
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, null);
}
/**
* <p>Uses <code>ReflectionToStringBuilder</code> to generate a
* <code>toString</code> for the specified object.</p>
*
* @param <T> the type of the object
* @param object the Object to be output
* @param style the style of the <code>toString</code> to create, may be <code>null</code>
* @param outputTransients whether to include transient fields
* @param reflectUpToClass the superclass to reflect up to (inclusive), may be <code>null</code>
* @return the String result
* @see ReflectionToStringBuilder#toString(Object,ToStringStyle,boolean,boolean,Class)
* @since 2.0
*/
public static <T> String reflectionToString(
T object,
ToStringStyle style,
boolean outputTransients,
Class<? super T> reflectUpToClass) {
return ReflectionToStringBuilder.toString(object, style, outputTransients, false, reflectUpToClass);
}
//----------------------------------------------------------------------------
/**
* Current toString buffer, not null.
*/
private final StringBuffer buffer;
/**
* The object being output, may be null.
*/
private final Object object;
/**
* The style of output to use, not null.
*/
private final ToStringStyle style;
/**
* <p>Constructs a builder for the specified object using the default output style.</p>
*
* <p>This default style is obtained from {@link #getDefaultStyle()}.</p>
*
* @param object the Object to build a <code>toString</code> for, not recommended to be null
*/
public ToStringBuilder(Object object) {
this(object, null, null);
}
/**
* <p>Constructs a builder for the specified object using the a defined output style.</p>
*
* <p>If the style is <code>null</code>, the default style is used.</p>
*
* @param object the Object to build a <code>toString</code> for, not recommended to be null
* @param style the style of the <code>toString</code> to create, null uses the default style
*/
public ToStringBuilder(Object object, ToStringStyle style) {
this(object, style, null);
}
/**
* <p>Constructs a builder for the specified object.</p>
*
* <p>If the style is <code>null</code>, the default style is used.</p>
*
* <p>If the buffer is <code>null</code>, a new one is created.</p>
*
* @param object the Object to build a <code>toString</code> for, not recommended to be null
* @param style the style of the <code>toString</code> to create, null uses the default style
* @param buffer the <code>StringBuffer</code> to populate, may be null
*/
public ToStringBuilder(Object object, ToStringStyle style, StringBuffer buffer) {
if (style == null) {
style = getDefaultStyle();
}
if (buffer == null) {
buffer = new StringBuffer(512);
}
this.buffer = buffer;
this.style = style;
this.object = object;
style.appendStart(buffer, object);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(boolean value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(boolean[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(byte value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(byte[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(char value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(char[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(double value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(double[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(float value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(float[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(int value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(int[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(long value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(long[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value.</p>
*
* @param obj the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(Object obj) {
style.append(buffer, null, obj, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(Object[] array) {
style.append(buffer, null, array, null);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* value.</p>
*
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(short value) {
style.append(buffer, null, value);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* array.</p>
*
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(short[] array) {
style.append(buffer, null, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, boolean value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>hashCode</code>
* @return this
*/
public ToStringBuilder append(String fieldName, boolean[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, boolean[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>byte</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, byte value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>byte</code> array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, byte[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, byte[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, char value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, char[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, char[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, double value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, double[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, double[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>float</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, float value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, float[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, float[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, int value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, int[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, int[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, long value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, long[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, long[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value.</p>
*
* @param fieldName the field name
* @param obj the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, Object obj) {
style.append(buffer, fieldName, obj, null);
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value.</p>
*
* @param fieldName the field name
* @param obj the value to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail,
* <code>false</code> for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, Object obj, boolean fullDetail) {
style.append(buffer, fieldName, obj, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, Object[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, Object[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Append to the <code>toString</code> an <code>short</code>
* value.</p>
*
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, short value) {
style.append(buffer, fieldName, value);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* array.</p>
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @return this
*/
public ToStringBuilder append(String fieldName, short[] array) {
style.append(buffer, fieldName, array, null);
return this;
}
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* array.</p>
*
* <p>A boolean parameter controls the level of detail to show.
* Setting <code>true</code> will output the array in full. Setting
* <code>false</code> will output a summary, typically the size of
* the array.
*
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info
* @return this
*/
public ToStringBuilder append(String fieldName, short[] array, boolean fullDetail) {
style.append(buffer, fieldName, array, Boolean.valueOf(fullDetail));
return this;
}
/**
* <p>Appends with the same format as the default <code>Object toString()
* </code> method. Appends the class name followed by
* {@link System#identityHashCode(Object)}.</p>
*
* @param object the <code>Object</code> whose class name and id to output
* @return this
* @since 2.0
*/
public ToStringBuilder appendAsObjectToString(Object object) {
ObjectUtils.identityToString(this.getStringBuffer(), object);
return this;
}
//----------------------------------------------------------------------------
/**
* <p>Append the <code>toString</code> from the superclass.</p>
*
* <p>This method assumes that the superclass uses the same <code>ToStringStyle</code>
* as this one.</p>
*
* <p>If <code>superToString</code> is <code>null</code>, no change is made.</p>
*
* @param superToString the result of <code>super.toString()</code>
* @return this
* @since 2.0
*/
public ToStringBuilder appendSuper(String superToString) {
if (superToString != null) {
style.appendSuper(buffer, superToString);
}
return this;
}
/**
* <p>Append the <code>toString</code> from another object.</p>
*
* <p>This method is useful where a class delegates most of the implementation of
* its properties to another class. You can then call <code>toString()</code> on
* the other class and pass the result into this method.</p>
*
* <pre>
* private AnotherObject delegate;
* private String fieldInThisClass;
*
* public String toString() {
* return new ToStringBuilder(this).
* appendToString(delegate.toString()).
* append(fieldInThisClass).
* toString();
* }</pre>
*
* <p>This method assumes that the other object uses the same <code>ToStringStyle</code>
* as this one.</p>
*
* <p>If the <code>toString</code> is <code>null</code>, no change is made.</p>
*
* @param toString the result of <code>toString()</code> on another object
* @return this
* @since 2.0
*/
public ToStringBuilder appendToString(String toString) {
if (toString != null) {
style.appendToString(buffer, toString);
}
return this;
}
/**
* <p>Returns the <code>Object</code> being output.</p>
*
* @return The object being output.
* @since 2.0
*/
public Object getObject() {
return object;
}
/**
* <p>Gets the <code>StringBuffer</code> being populated.</p>
*
* @return the <code>StringBuffer</code> being populated
*/
public StringBuffer getStringBuffer() {
return buffer;
}
//----------------------------------------------------------------------------
/**
* <p>Gets the <code>ToStringStyle</code> being used.</p>
*
* @return the <code>ToStringStyle</code> being used
* @since 2.0
*/
public ToStringStyle getStyle() {
return style;
}
/**
* <p>Returns the built <code>toString</code>.</p>
*
* <p>This method appends the end of data indicator, and can only be called once.
* Use {@link #getStringBuffer} to get the current string state.</p>
*
* <p>If the object is <code>null</code>, return the style's <code>nullText</code></p>
*
* @return the String <code>toString</code>
*/
@Override
public String toString() {
if (this.getObject() == null) {
this.getStringBuffer().append(this.getStyle().getNullText());
} else {
style.appendEnd(this.getStringBuffer(), this.getObject());
}
return this.getStringBuffer().toString();
}
/**
* Returns the String that was build as an object representation. The
* default implementation utilizes the {@link #toString()} implementation.
*
* @return the String <code>toString</code>
*
* @see #toString()
*
* @since 3.0
*/
public String build() {
return toString();
}
}
/*
* 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 external.org.apache.commons.lang3.builder;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Map;
import java.util.WeakHashMap;
import external.org.apache.commons.lang3.ClassUtils;
import external.org.apache.commons.lang3.ObjectUtils;
import external.org.apache.commons.lang3.SystemUtils;
/**
* <p>Controls <code>String</code> formatting for {@link ToStringBuilder}.
* The main public interface is always via <code>ToStringBuilder</code>.</p>
*
* <p>These classes are intended to be used as <code>Singletons</code>.
* There is no need to instantiate a new style each time. A program
* will generally use one of the predefined constants on this class.
* Alternatively, the {@link StandardToStringStyle} class can be used
* to set the individual settings. Thus most styles can be achieved
* without subclassing.</p>
*
* <p>If required, a subclass can override as many or as few of the
* methods as it requires. Each object type (from <code>boolean</code>
* to <code>long</code> to <code>Object</code> to <code>int[]</code>) has
* its own methods to output it. Most have two versions, detail and summary.
*
* <p>For example, the detail version of the array based methods will
* output the whole array, whereas the summary method will just output
* the array length.</p>
*
* <p>If you want to format the output of certain objects, such as dates, you
* must create a subclass and override a method.
* <pre>
* public class MyStyle extends ToStringStyle {
* protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
* if (value instanceof Date) {
* value = new SimpleDateFormat("yyyy-MM-dd").format(value);
* }
* buffer.append(value);
* }
* }
* </pre>
* </p>
*
* @since 1.0
* @version $Id: ToStringStyle.java 1091066 2011-04-11 13:30:11Z mbenson $
*/
public abstract class ToStringStyle implements Serializable {
/**
* Serialization version ID.
*/
private static final long serialVersionUID = -2587890625525655916L;
/**
* The default toString style. Using the Using the <code>Person</code>
* example from {@link ToStringBuilder}, the output would look like this:
*
* <pre>
* Person@182f0db[name=John Doe,age=33,smoker=false]
* </pre>
*/
public static final ToStringStyle DEFAULT_STYLE = new DefaultToStringStyle();
/**
* The multi line toString style. Using the Using the <code>Person</code>
* example from {@link ToStringBuilder}, the output would look like this:
*
* <pre>
* Person@182f0db[
* name=John Doe
* age=33
* smoker=false
* ]
* </pre>
*/
public static final ToStringStyle MULTI_LINE_STYLE = new MultiLineToStringStyle();
/**
* The no field names toString style. Using the Using the
* <code>Person</code> example from {@link ToStringBuilder}, the output
* would look like this:
*
* <pre>
* Person@182f0db[John Doe,33,false]
* </pre>
*/
public static final ToStringStyle NO_FIELD_NAMES_STYLE = new NoFieldNameToStringStyle();
/**
* The short prefix toString style. Using the <code>Person</code> example
* from {@link ToStringBuilder}, the output would look like this:
*
* <pre>
* Person[name=John Doe,age=33,smoker=false]
* </pre>
*
* @since 2.1
*/
public static final ToStringStyle SHORT_PREFIX_STYLE = new ShortPrefixToStringStyle();
/**
* The simple toString style. Using the Using the <code>Person</code>
* example from {@link ToStringBuilder}, the output would look like this:
*
* <pre>
* John Doe,33,false
* </pre>
*/
public static final ToStringStyle SIMPLE_STYLE = new SimpleToStringStyle();
/**
* <p>
* A registry of objects used by <code>reflectionToString</code> methods
* to detect cyclical object references and avoid infinite loops.
* </p>
*/
private static final ThreadLocal<WeakHashMap<Object, Object>> REGISTRY =
new ThreadLocal<WeakHashMap<Object,Object>>();
/**
* <p>
* Returns the registry of objects being traversed by the <code>reflectionToString</code>
* methods in the current thread.
* </p>
*
* @return Set the registry of objects being traversed
*/
static Map<Object, Object> getRegistry() {
return REGISTRY.get();
}
/**
* <p>
* Returns <code>true</code> if the registry contains the given object.
* Used by the reflection methods to avoid infinite loops.
* </p>
*
* @param value
* The object to lookup in the registry.
* @return boolean <code>true</code> if the registry contains the given
* object.
*/
static boolean isRegistered(Object value) {
Map<Object, Object> m = getRegistry();
return m != null && m.containsKey(value);
}
/**
* <p>
* Registers the given object. Used by the reflection methods to avoid
* infinite loops.
* </p>
*
* @param value
* The object to register.
*/
static void register(Object value) {
if (value != null) {
Map<Object, Object> m = getRegistry();
if (m == null) {
REGISTRY.set(new WeakHashMap<Object, Object>());
}
getRegistry().put(value, null);
}
}
/**
* <p>
* Unregisters the given object.
* </p>
*
* <p>
* Used by the reflection methods to avoid infinite loops.
* </p>
*
* @param value
* The object to unregister.
*/
static void unregister(Object value) {
if (value != null) {
Map<Object, Object> m = getRegistry();
if (m != null) {
m.remove(value);
if (m.isEmpty()) {
REGISTRY.remove();
}
}
}
}
/**
* Whether to use the field names, the default is <code>true</code>.
*/
private boolean useFieldNames = true;
/**
* Whether to use the class name, the default is <code>true</code>.
*/
private boolean useClassName = true;
/**
* Whether to use short class names, the default is <code>false</code>.
*/
private boolean useShortClassName = false;
/**
* Whether to use the identity hash code, the default is <code>true</code>.
*/
private boolean useIdentityHashCode = true;
/**
* The content start <code>'['</code>.
*/
private String contentStart = "[";
/**
* The content end <code>']'</code>.
*/
private String contentEnd = "]";
/**
* The field name value separator <code>'='</code>.
*/
private String fieldNameValueSeparator = "=";
/**
* Whether the field separator should be added before any other fields.
*/
private boolean fieldSeparatorAtStart = false;
/**
* Whether the field separator should be added after any other fields.
*/
private boolean fieldSeparatorAtEnd = false;
/**
* The field separator <code>','</code>.
*/
private String fieldSeparator = ",";
/**
* The array start <code>'{'</code>.
*/
private String arrayStart = "{";
/**
* The array separator <code>','</code>.
*/
private String arraySeparator = ",";
/**
* The detail for array content.
*/
private boolean arrayContentDetail = true;
/**
* The array end <code>'}'</code>.
*/
private String arrayEnd = "}";
/**
* The value to use when fullDetail is <code>null</code>,
* the default value is <code>true</code>.
*/
private boolean defaultFullDetail = true;
/**
* The <code>null</code> text <code>'&lt;null&gt;'</code>.
*/
private String nullText = "<null>";
/**
* The summary size text start <code>'<size'</code>.
*/
private String sizeStartText = "<size=";
/**
* The summary size text start <code>'&gt;'</code>.
*/
private String sizeEndText = ">";
/**
* The summary object text start <code>'&lt;'</code>.
*/
private String summaryObjectStartText = "<";
/**
* The summary object text start <code>'&gt;'</code>.
*/
private String summaryObjectEndText = ">";
//----------------------------------------------------------------------------
/**
* <p>Constructor.</p>
*/
protected ToStringStyle() {
super();
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> the superclass toString.</p>
* <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
*
* <p>A <code>null</code> <code>superToString</code> is ignored.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param superToString the <code>super.toString()</code>
* @since 2.0
*/
public void appendSuper(StringBuffer buffer, String superToString) {
appendToString(buffer, superToString);
}
/**
* <p>Append to the <code>toString</code> another toString.</p>
* <p>NOTE: It assumes that the toString has been created from the same ToStringStyle. </p>
*
* <p>A <code>null</code> <code>toString</code> is ignored.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param toString the additional <code>toString</code>
* @since 2.0
*/
public void appendToString(StringBuffer buffer, String toString) {
if (toString != null) {
int pos1 = toString.indexOf(contentStart) + contentStart.length();
int pos2 = toString.lastIndexOf(contentEnd);
if (pos1 != pos2 && pos1 >= 0 && pos2 >= 0) {
String data = toString.substring(pos1, pos2);
if (fieldSeparatorAtStart) {
removeLastFieldSeparator(buffer);
}
buffer.append(data);
appendFieldSeparator(buffer);
}
}
}
/**
* <p>Append to the <code>toString</code> the start of data indicator.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param object the <code>Object</code> to build a <code>toString</code> for
*/
public void appendStart(StringBuffer buffer, Object object) {
if (object != null) {
appendClassName(buffer, object);
appendIdentityHashCode(buffer, object);
appendContentStart(buffer);
if (fieldSeparatorAtStart) {
appendFieldSeparator(buffer);
}
}
}
/**
* <p>Append to the <code>toString</code> the end of data indicator.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param object the <code>Object</code> to build a
* <code>toString</code> for.
*/
public void appendEnd(StringBuffer buffer, Object object) {
if (this.fieldSeparatorAtEnd == false) {
removeLastFieldSeparator(buffer);
}
appendContentEnd(buffer);
unregister(object);
}
/**
* <p>Remove the last field separator from the buffer.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @since 2.0
*/
protected void removeLastFieldSeparator(StringBuffer buffer) {
int len = buffer.length();
int sepLen = fieldSeparator.length();
if (len > 0 && sepLen > 0 && len >= sepLen) {
boolean match = true;
for (int i = 0; i < sepLen; i++) {
if (buffer.charAt(len - 1 - i) != fieldSeparator.charAt(sepLen - 1 - i)) {
match = false;
break;
}
}
if (match) {
buffer.setLength(len - sepLen);
}
}
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value, printing the full <code>toString</code> of the
* <code>Object</code> passed in.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, Object value, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (value == null) {
appendNullText(buffer, fieldName);
} else {
appendInternal(buffer, fieldName, value, isFullDetail(fullDetail));
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>,
* correctly interpreting its type.</p>
*
* <p>This method performs the main lookup by Class type to correctly
* route arrays, <code>Collections</code>, <code>Maps</code> and
* <code>Objects</code> to the appropriate method.</p>
*
* <p>Either detail or summary views can be specified.</p>
*
* <p>If a cycle is detected, an object will be appended with the
* <code>Object.toString()</code> format.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>,
* not <code>null</code>
* @param detail output detail or not
*/
protected void appendInternal(StringBuffer buffer, String fieldName, Object value, boolean detail) {
if (isRegistered(value)
&& !(value instanceof Number || value instanceof Boolean || value instanceof Character)) {
appendCyclicObject(buffer, fieldName, value);
return;
}
register(value);
try {
if (value instanceof Collection<?>) {
if (detail) {
appendDetail(buffer, fieldName, (Collection<?>) value);
} else {
appendSummarySize(buffer, fieldName, ((Collection<?>) value).size());
}
} else if (value instanceof Map<?, ?>) {
if (detail) {
appendDetail(buffer, fieldName, (Map<?, ?>) value);
} else {
appendSummarySize(buffer, fieldName, ((Map<?, ?>) value).size());
}
} else if (value instanceof long[]) {
if (detail) {
appendDetail(buffer, fieldName, (long[]) value);
} else {
appendSummary(buffer, fieldName, (long[]) value);
}
} else if (value instanceof int[]) {
if (detail) {
appendDetail(buffer, fieldName, (int[]) value);
} else {
appendSummary(buffer, fieldName, (int[]) value);
}
} else if (value instanceof short[]) {
if (detail) {
appendDetail(buffer, fieldName, (short[]) value);
} else {
appendSummary(buffer, fieldName, (short[]) value);
}
} else if (value instanceof byte[]) {
if (detail) {
appendDetail(buffer, fieldName, (byte[]) value);
} else {
appendSummary(buffer, fieldName, (byte[]) value);
}
} else if (value instanceof char[]) {
if (detail) {
appendDetail(buffer, fieldName, (char[]) value);
} else {
appendSummary(buffer, fieldName, (char[]) value);
}
} else if (value instanceof double[]) {
if (detail) {
appendDetail(buffer, fieldName, (double[]) value);
} else {
appendSummary(buffer, fieldName, (double[]) value);
}
} else if (value instanceof float[]) {
if (detail) {
appendDetail(buffer, fieldName, (float[]) value);
} else {
appendSummary(buffer, fieldName, (float[]) value);
}
} else if (value instanceof boolean[]) {
if (detail) {
appendDetail(buffer, fieldName, (boolean[]) value);
} else {
appendSummary(buffer, fieldName, (boolean[]) value);
}
} else if (value.getClass().isArray()) {
if (detail) {
appendDetail(buffer, fieldName, (Object[]) value);
} else {
appendSummary(buffer, fieldName, (Object[]) value);
}
} else {
if (detail) {
appendDetail(buffer, fieldName, value);
} else {
appendSummary(buffer, fieldName, value);
}
}
} finally {
unregister(value);
}
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value that has been detected to participate in a cycle. This
* implementation will print the standard string value of the value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>,
* not <code>null</code>
*
* @since 2.2
*/
protected void appendCyclicObject(StringBuffer buffer, String fieldName, Object value) {
ObjectUtils.identityToString(buffer, value);
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value, printing the full detail of the <code>Object</code>.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, Object value) {
buffer.append(value);
}
/**
* <p>Append to the <code>toString</code> a <code>Collection</code>.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param coll the <code>Collection</code> to add to the
* <code>toString</code>, not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, Collection<?> coll) {
buffer.append(coll);
}
/**
* <p>Append to the <code>toString</code> a <code>Map<code>.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param map the <code>Map</code> to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, Map<?, ?> map) {
buffer.append(map);
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* value, printing a summary of the <code>Object</code>.</P>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, Object value) {
buffer.append(summaryObjectStartText);
buffer.append(getShortClassName(value.getClass()));
buffer.append(summaryObjectEndText);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, long value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, long value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, int value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, int value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, short value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, short value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, byte value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, byte value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, char value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, char value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, double value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, double value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, float value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, float value) {
buffer.append(value);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param value the value to add to the <code>toString</code>
*/
public void append(StringBuffer buffer, String fieldName, boolean value) {
appendFieldStart(buffer, fieldName);
appendDetail(buffer, fieldName, value);
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* value.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param value the value to add to the <code>toString</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, boolean value) {
buffer.append(value);
}
/**
* <p>Append to the <code>toString</code> an <code>Object</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the toString
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, Object[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> the detail of an
* <code>Object</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, Object[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
Object item = array[i];
if (i > 0) {
buffer.append(arraySeparator);
}
if (item == null) {
appendNullText(buffer, fieldName);
} else {
appendInternal(buffer, fieldName, item, arrayContentDetail);
}
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> the detail of an array type.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
* @since 2.0
*/
protected void reflectionAppendArrayDetail(StringBuffer buffer, String fieldName, Object array) {
buffer.append(arrayStart);
int length = Array.getLength(array);
for (int i = 0; i < length; i++) {
Object item = Array.get(array, i);
if (i > 0) {
buffer.append(arraySeparator);
}
if (item == null) {
appendNullText(buffer, fieldName);
} else {
appendInternal(buffer, fieldName, item, arrayContentDetail);
}
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of an
* <code>Object</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, Object[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>long</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, long[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>long</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, long[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>long</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, long[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> an <code>int</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, int[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of an
* <code>int</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, int[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of an
* <code>int</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, int[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>short</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, short[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>short</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, short[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>short</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, short[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>byte</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, byte[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>byte</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, byte[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>byte</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, byte[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>char</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the <code>toString</code>
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, char[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>char</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, char[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>char</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, char[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>double</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the toString
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, double[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>double</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, double[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>double</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, double[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>float</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the toString
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, float[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>float</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, float[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>float</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, float[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> a <code>boolean</code>
* array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
* @param array the array to add to the toString
* @param fullDetail <code>true</code> for detail, <code>false</code>
* for summary info, <code>null</code> for style decides
*/
public void append(StringBuffer buffer, String fieldName, boolean[] array, Boolean fullDetail) {
appendFieldStart(buffer, fieldName);
if (array == null) {
appendNullText(buffer, fieldName);
} else if (isFullDetail(fullDetail)) {
appendDetail(buffer, fieldName, array);
} else {
appendSummary(buffer, fieldName, array);
}
appendFieldEnd(buffer, fieldName);
}
/**
* <p>Append to the <code>toString</code> the detail of a
* <code>boolean</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendDetail(StringBuffer buffer, String fieldName, boolean[] array) {
buffer.append(arrayStart);
for (int i = 0; i < array.length; i++) {
if (i > 0) {
buffer.append(arraySeparator);
}
appendDetail(buffer, fieldName, array[i]);
}
buffer.append(arrayEnd);
}
/**
* <p>Append to the <code>toString</code> a summary of a
* <code>boolean</code> array.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param array the array to add to the <code>toString</code>,
* not <code>null</code>
*/
protected void appendSummary(StringBuffer buffer, String fieldName, boolean[] array) {
appendSummarySize(buffer, fieldName, array.length);
}
//----------------------------------------------------------------------------
/**
* <p>Append to the <code>toString</code> the class name.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param object the <code>Object</code> whose name to output
*/
protected void appendClassName(StringBuffer buffer, Object object) {
if (useClassName && object != null) {
register(object);
if (useShortClassName) {
buffer.append(getShortClassName(object.getClass()));
} else {
buffer.append(object.getClass().getName());
}
}
}
/**
* <p>Append the {@link System#identityHashCode(Object)}.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param object the <code>Object</code> whose id to output
*/
protected void appendIdentityHashCode(StringBuffer buffer, Object object) {
if (this.isUseIdentityHashCode() && object!=null) {
register(object);
buffer.append('@');
buffer.append(Integer.toHexString(System.identityHashCode(object)));
}
}
/**
* <p>Append to the <code>toString</code> the content start.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
*/
protected void appendContentStart(StringBuffer buffer) {
buffer.append(contentStart);
}
/**
* <p>Append to the <code>toString</code> the content end.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
*/
protected void appendContentEnd(StringBuffer buffer) {
buffer.append(contentEnd);
}
/**
* <p>Append to the <code>toString</code> an indicator for <code>null</code>.</p>
*
* <p>The default indicator is <code>'&lt;null&gt;'</code>.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
*/
protected void appendNullText(StringBuffer buffer, String fieldName) {
buffer.append(nullText);
}
/**
* <p>Append to the <code>toString</code> the field separator.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
*/
protected void appendFieldSeparator(StringBuffer buffer) {
buffer.append(fieldSeparator);
}
/**
* <p>Append to the <code>toString</code> the field start.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name
*/
protected void appendFieldStart(StringBuffer buffer, String fieldName) {
if (useFieldNames && fieldName != null) {
buffer.append(fieldName);
buffer.append(fieldNameValueSeparator);
}
}
/**
* <p>Append to the <code>toString<code> the field end.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
*/
protected void appendFieldEnd(StringBuffer buffer, String fieldName) {
appendFieldSeparator(buffer);
}
/**
* <p>Append to the <code>toString</code> a size summary.</p>
*
* <p>The size summary is used to summarize the contents of
* <code>Collections</code>, <code>Maps</code> and arrays.</p>
*
* <p>The output consists of a prefix, the passed in size
* and a suffix.</p>
*
* <p>The default format is <code>'&lt;size=n&gt;'<code>.</p>
*
* @param buffer the <code>StringBuffer</code> to populate
* @param fieldName the field name, typically not used as already appended
* @param size the size to append
*/
protected void appendSummarySize(StringBuffer buffer, String fieldName, int size) {
buffer.append(sizeStartText);
buffer.append(size);
buffer.append(sizeEndText);
}
/**
* <p>Is this field to be output in full detail.</p>
*
* <p>This method converts a detail request into a detail level.
* The calling code may request full detail (<code>true</code>),
* but a subclass might ignore that and always return
* <code>false</code>. The calling code may pass in
* <code>null</code> indicating that it doesn't care about
* the detail level. In this case the default detail level is
* used.</p>
*
* @param fullDetailRequest the detail level requested
* @return whether full detail is to be shown
*/
protected boolean isFullDetail(Boolean fullDetailRequest) {
if (fullDetailRequest == null) {
return defaultFullDetail;
}
return fullDetailRequest.booleanValue();
}
/**
* <p>Gets the short class name for a class.</p>
*
* <p>The short class name is the classname excluding
* the package name.</p>
*
* @param cls the <code>Class</code> to get the short name of
* @return the short name
*/
protected String getShortClassName(Class<?> cls) {
return ClassUtils.getShortClassName(cls);
}
// Setters and getters for the customizable parts of the style
// These methods are not expected to be overridden, except to make public
// (They are not public so that immutable subclasses can be written)
//---------------------------------------------------------------------
/**
* <p>Gets whether to use the class name.</p>
*
* @return the current useClassName flag
*/
protected boolean isUseClassName() {
return useClassName;
}
/**
* <p>Sets whether to use the class name.</p>
*
* @param useClassName the new useClassName flag
*/
protected void setUseClassName(boolean useClassName) {
this.useClassName = useClassName;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether to output short or long class names.</p>
*
* @return the current useShortClassName flag
* @since 2.0
*/
protected boolean isUseShortClassName() {
return useShortClassName;
}
/**
* <p>Sets whether to output short or long class names.</p>
*
* @param useShortClassName the new useShortClassName flag
* @since 2.0
*/
protected void setUseShortClassName(boolean useShortClassName) {
this.useShortClassName = useShortClassName;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether to use the identity hash code.</p>
*
* @return the current useIdentityHashCode flag
*/
protected boolean isUseIdentityHashCode() {
return useIdentityHashCode;
}
/**
* <p>Sets whether to use the identity hash code.</p>
*
* @param useIdentityHashCode the new useIdentityHashCode flag
*/
protected void setUseIdentityHashCode(boolean useIdentityHashCode) {
this.useIdentityHashCode = useIdentityHashCode;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether to use the field names passed in.</p>
*
* @return the current useFieldNames flag
*/
protected boolean isUseFieldNames() {
return useFieldNames;
}
/**
* <p>Sets whether to use the field names passed in.</p>
*
* @param useFieldNames the new useFieldNames flag
*/
protected void setUseFieldNames(boolean useFieldNames) {
this.useFieldNames = useFieldNames;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether to use full detail when the caller doesn't
* specify.</p>
*
* @return the current defaultFullDetail flag
*/
protected boolean isDefaultFullDetail() {
return defaultFullDetail;
}
/**
* <p>Sets whether to use full detail when the caller doesn't
* specify.</p>
*
* @param defaultFullDetail the new defaultFullDetail flag
*/
protected void setDefaultFullDetail(boolean defaultFullDetail) {
this.defaultFullDetail = defaultFullDetail;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether to output array content detail.</p>
*
* @return the current array content detail setting
*/
protected boolean isArrayContentDetail() {
return arrayContentDetail;
}
/**
* <p>Sets whether to output array content detail.</p>
*
* @param arrayContentDetail the new arrayContentDetail flag
*/
protected void setArrayContentDetail(boolean arrayContentDetail) {
this.arrayContentDetail = arrayContentDetail;
}
//---------------------------------------------------------------------
/**
* <p>Gets the array start text.</p>
*
* @return the current array start text
*/
protected String getArrayStart() {
return arrayStart;
}
/**
* <p>Sets the array start text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param arrayStart the new array start text
*/
protected void setArrayStart(String arrayStart) {
if (arrayStart == null) {
arrayStart = "";
}
this.arrayStart = arrayStart;
}
//---------------------------------------------------------------------
/**
* <p>Gets the array end text.</p>
*
* @return the current array end text
*/
protected String getArrayEnd() {
return arrayEnd;
}
/**
* <p>Sets the array end text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param arrayEnd the new array end text
*/
protected void setArrayEnd(String arrayEnd) {
if (arrayEnd == null) {
arrayEnd = "";
}
this.arrayEnd = arrayEnd;
}
//---------------------------------------------------------------------
/**
* <p>Gets the array separator text.</p>
*
* @return the current array separator text
*/
protected String getArraySeparator() {
return arraySeparator;
}
/**
* <p>Sets the array separator text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param arraySeparator the new array separator text
*/
protected void setArraySeparator(String arraySeparator) {
if (arraySeparator == null) {
arraySeparator = "";
}
this.arraySeparator = arraySeparator;
}
//---------------------------------------------------------------------
/**
* <p>Gets the content start text.</p>
*
* @return the current content start text
*/
protected String getContentStart() {
return contentStart;
}
/**
* <p>Sets the content start text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param contentStart the new content start text
*/
protected void setContentStart(String contentStart) {
if (contentStart == null) {
contentStart = "";
}
this.contentStart = contentStart;
}
//---------------------------------------------------------------------
/**
* <p>Gets the content end text.</p>
*
* @return the current content end text
*/
protected String getContentEnd() {
return contentEnd;
}
/**
* <p>Sets the content end text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param contentEnd the new content end text
*/
protected void setContentEnd(String contentEnd) {
if (contentEnd == null) {
contentEnd = "";
}
this.contentEnd = contentEnd;
}
//---------------------------------------------------------------------
/**
* <p>Gets the field name value separator text.</p>
*
* @return the current field name value separator text
*/
protected String getFieldNameValueSeparator() {
return fieldNameValueSeparator;
}
/**
* <p>Sets the field name value separator text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param fieldNameValueSeparator the new field name value separator text
*/
protected void setFieldNameValueSeparator(String fieldNameValueSeparator) {
if (fieldNameValueSeparator == null) {
fieldNameValueSeparator = "";
}
this.fieldNameValueSeparator = fieldNameValueSeparator;
}
//---------------------------------------------------------------------
/**
* <p>Gets the field separator text.</p>
*
* @return the current field separator text
*/
protected String getFieldSeparator() {
return fieldSeparator;
}
/**
* <p>Sets the field separator text.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param fieldSeparator the new field separator text
*/
protected void setFieldSeparator(String fieldSeparator) {
if (fieldSeparator == null) {
fieldSeparator = "";
}
this.fieldSeparator = fieldSeparator;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether the field separator should be added at the start
* of each buffer.</p>
*
* @return the fieldSeparatorAtStart flag
* @since 2.0
*/
protected boolean isFieldSeparatorAtStart() {
return fieldSeparatorAtStart;
}
/**
* <p>Sets whether the field separator should be added at the start
* of each buffer.</p>
*
* @param fieldSeparatorAtStart the fieldSeparatorAtStart flag
* @since 2.0
*/
protected void setFieldSeparatorAtStart(boolean fieldSeparatorAtStart) {
this.fieldSeparatorAtStart = fieldSeparatorAtStart;
}
//---------------------------------------------------------------------
/**
* <p>Gets whether the field separator should be added at the end
* of each buffer.</p>
*
* @return fieldSeparatorAtEnd flag
* @since 2.0
*/
protected boolean isFieldSeparatorAtEnd() {
return fieldSeparatorAtEnd;
}
/**
* <p>Sets whether the field separator should be added at the end
* of each buffer.</p>
*
* @param fieldSeparatorAtEnd the fieldSeparatorAtEnd flag
* @since 2.0
*/
protected void setFieldSeparatorAtEnd(boolean fieldSeparatorAtEnd) {
this.fieldSeparatorAtEnd = fieldSeparatorAtEnd;
}
//---------------------------------------------------------------------
/**
* <p>Gets the text to output when <code>null</code> found.</p>
*
* @return the current text to output when null found
*/
protected String getNullText() {
return nullText;
}
/**
* <p>Sets the text to output when <code>null</code> found.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param nullText the new text to output when null found
*/
protected void setNullText(String nullText) {
if (nullText == null) {
nullText = "";
}
this.nullText = nullText;
}
//---------------------------------------------------------------------
/**
* <p>Gets the start text to output when a <code>Collection</code>,
* <code>Map</code> or array size is output.</p>
*
* <p>This is output before the size value.</p>
*
* @return the current start of size text
*/
protected String getSizeStartText() {
return sizeStartText;
}
/**
* <p>Sets the start text to output when a <code>Collection</code>,
* <code>Map</code> or array size is output.</p>
*
* <p>This is output before the size value.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param sizeStartText the new start of size text
*/
protected void setSizeStartText(String sizeStartText) {
if (sizeStartText == null) {
sizeStartText = "";
}
this.sizeStartText = sizeStartText;
}
//---------------------------------------------------------------------
/**
* <p>Gets the end text to output when a <code>Collection</code>,
* <code>Map</code> or array size is output.</p>
*
* <p>This is output after the size value.</p>
*
* @return the current end of size text
*/
protected String getSizeEndText() {
return sizeEndText;
}
/**
* <p>Sets the end text to output when a <code>Collection</code>,
* <code>Map</code> or array size is output.</p>
*
* <p>This is output after the size value.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param sizeEndText the new end of size text
*/
protected void setSizeEndText(String sizeEndText) {
if (sizeEndText == null) {
sizeEndText = "";
}
this.sizeEndText = sizeEndText;
}
//---------------------------------------------------------------------
/**
* <p>Gets the start text to output when an <code>Object</code> is
* output in summary mode.</p>
*
* <p>This is output before the size value.</p>
*
* @return the current start of summary text
*/
protected String getSummaryObjectStartText() {
return summaryObjectStartText;
}
/**
* <p>Sets the start text to output when an <code>Object</code> is
* output in summary mode.</p>
*
* <p>This is output before the size value.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param summaryObjectStartText the new start of summary text
*/
protected void setSummaryObjectStartText(String summaryObjectStartText) {
if (summaryObjectStartText == null) {
summaryObjectStartText = "";
}
this.summaryObjectStartText = summaryObjectStartText;
}
//---------------------------------------------------------------------
/**
* <p>Gets the end text to output when an <code>Object</code> is
* output in summary mode.</p>
*
* <p>This is output after the size value.</p>
*
* @return the current end of summary text
*/
protected String getSummaryObjectEndText() {
return summaryObjectEndText;
}
/**
* <p>Sets the end text to output when an <code>Object</code> is
* output in summary mode.</p>
*
* <p>This is output after the size value.</p>
*
* <p><code>null</code> is accepted, but will be converted to
* an empty String.</p>
*
* @param summaryObjectEndText the new end of summary text
*/
protected void setSummaryObjectEndText(String summaryObjectEndText) {
if (summaryObjectEndText == null) {
summaryObjectEndText = "";
}
this.summaryObjectEndText = summaryObjectEndText;
}
//----------------------------------------------------------------------------
/**
* <p>Default <code>ToStringStyle</code>.</p>
*
* <p>This is an inner class rather than using
* <code>StandardToStringStyle</code> to ensure its immutability.</p>
*/
private static final class DefaultToStringStyle extends ToStringStyle {
/**
* Required for serialization support.
*
* @see Serializable
*/
private static final long serialVersionUID = 1L;
/**
* <p>Constructor.</p>
*
* <p>Use the static constant rather than instantiating.</p>
*/
DefaultToStringStyle() {
super();
}
/**
* <p>Ensure <code>Singleton</code> after serialization.</p>
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.DEFAULT_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* <p><code>ToStringStyle</code> that does not print out
* the field names.</p>
*
* <p>This is an inner class rather than using
* <code>StandardToStringStyle</code> to ensure its immutability.
*/
private static final class NoFieldNameToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* <p>Constructor.</p>
*
* <p>Use the static constant rather than instantiating.</p>
*/
NoFieldNameToStringStyle() {
super();
this.setUseFieldNames(false);
}
/**
* <p>Ensure <code>Singleton</code> after serialization.</p>
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.NO_FIELD_NAMES_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* <p><code>ToStringStyle</code> that prints out the short
* class name and no identity hashcode.</p>
*
* <p>This is an inner class rather than using
* <code>StandardToStringStyle</code> to ensure its immutability.</p>
*/
private static final class ShortPrefixToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* <p>Constructor.</p>
*
* <p>Use the static constant rather than instantiating.</p>
*/
ShortPrefixToStringStyle() {
super();
this.setUseShortClassName(true);
this.setUseIdentityHashCode(false);
}
/**
* <p>Ensure <code>Singleton</ode> after serialization.</p>
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.SHORT_PREFIX_STYLE;
}
}
/**
* <p><code>ToStringStyle</code> that does not print out the
* classname, identity hashcode, content start or field name.</p>
*
* <p>This is an inner class rather than using
* <code>StandardToStringStyle</code> to ensure its immutability.</p>
*/
private static final class SimpleToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* <p>Constructor.</p>
*
* <p>Use the static constant rather than instantiating.</p>
*/
SimpleToStringStyle() {
super();
this.setUseClassName(false);
this.setUseIdentityHashCode(false);
this.setUseFieldNames(false);
this.setContentStart("");
this.setContentEnd("");
}
/**
* <p>Ensure <code>Singleton</ode> after serialization.</p>
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.SIMPLE_STYLE;
}
}
//----------------------------------------------------------------------------
/**
* <p><code>ToStringStyle</code> that outputs on multiple lines.</p>
*
* <p>This is an inner class rather than using
* <code>StandardToStringStyle</code> to ensure its immutability.</p>
*/
private static final class MultiLineToStringStyle extends ToStringStyle {
private static final long serialVersionUID = 1L;
/**
* <p>Constructor.</p>
*
* <p>Use the static constant rather than instantiating.</p>
*/
MultiLineToStringStyle() {
super();
this.setContentStart("[");
this.setFieldSeparator(SystemUtils.LINE_SEPARATOR + " ");
this.setFieldSeparatorAtStart(true);
this.setContentEnd(SystemUtils.LINE_SEPARATOR + "]");
}
/**
* <p>Ensure <code>Singleton</code> after serialization.</p>
*
* @return the singleton
*/
private Object readResolve() {
return ToStringStyle.MULTI_LINE_STYLE;
}
}
}
<!--
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.
-->
<html>
<body>
Assists in creating consistent <code>equals(Object)</code>, <code>toString()</code>,
<code>hashCode()</code>, and <code>compareTo(Object)</code> methods.
@see java.lang.Object#equals(Object)
@see java.lang.Object#toString()
@see java.lang.Object#hashCode()
@see java.lang.Comparable#compareTo(Object)
@since 1.0
<p>These classes are not thread-safe.</p>
</body>
</html>
/*
* 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 external.org.apache.commons.lang3.exception;
/**
* Exception thrown when a clone cannot be created. In contrast to
* {@link CloneNotSupportedException} this is a {@link RuntimeException}.
*
* @since 3.0
*/
public class CloneFailedException extends RuntimeException {
// ~ Static fields/initializers ---------------------------------------------
private static final long serialVersionUID = 20091223L;
// ~ Constructors -----------------------------------------------------------
/**
* Constructs a CloneFailedException.
*
* @param message description of the exception
* @since upcoming
*/
public CloneFailedException(final String message) {
super(message);
}
/**
* Constructs a CloneFailedException.
*
* @param cause cause of the exception
* @since upcoming
*/
public CloneFailedException(final Throwable cause) {
super(cause);
}
/**
* Constructs a CloneFailedException.
*
* @param message description of the exception
* @param cause cause of the exception
* @since upcoming
*/
public CloneFailedException(final String message, final Throwable cause) {
super(message, cause);
}
}
<!--
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.
-->
<html>
<body>
Provides functionality for Exceptions.
<p>Contains the concept of an exception with context i.e. such an exception
will contain a map with keys and values. This provides an easy way to pass valuable
state information at exception time in useful form to a calling process.</p>
<p>Lastly, {@link org.apache.commons.lang3.exception.ExceptionUtils}
also contains <code>Throwable</code> manipulation and examination routines.</p>
@since 1.0
</body>
</html>
/*
* 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 external.org.apache.commons.lang3.mutable;
/**
* Provides mutable access to a value.
* <p>
* <code>Mutable</code> is used as a generic interface to the implementations in this package.
* <p>
* A typical use case would be to enable a primitive or string to be passed to a method and allow that method to
* effectively change the value of the primitive/string. Another use case is to store a frequently changing primitive in
* a collection (for example a total in a map) without needing to create new Integer/Long wrapper objects.
*
* @since 2.1
* @param <T> the type to set and get
* @version $Id: Mutable.java 1153213 2011-08-02 17:35:39Z ggregory $
*/
public interface Mutable<T> {
/**
* Gets the value of this mutable.
*
* @return the stored value
*/
T getValue();
/**
* Sets the value of this mutable.
*
* @param value
* the value to store
* @throws NullPointerException
* if the object is null and null is invalid
* @throws ClassCastException
* if the type is invalid
*/
void setValue(T value);
}
/*
* 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 external.org.apache.commons.lang3.mutable;
/**
* A mutable <code>int</code> wrapper.
* <p>
* Note that as MutableInt does not extend Integer, it is not treated by String.format as an Integer parameter.
*
* @see Integer
* @since 2.1
* @version $Id: MutableInt.java 1160571 2011-08-23 07:36:08Z bayard $
*/
public class MutableInt extends Number implements Comparable<MutableInt>, Mutable<Number> {
/**
* Required for serialization support.
*
* @see java.io.Serializable
*/
private static final long serialVersionUID = 512176391864L;
/** The mutable value. */
private int value;
/**
* Constructs a new MutableInt with the default value of zero.
*/
public MutableInt() {
super();
}
/**
* Constructs a new MutableInt with the specified value.
*
* @param value the initial value to store
*/
public MutableInt(int value) {
super();
this.value = value;
}
/**
* Constructs a new MutableInt with the specified value.
*
* @param value the initial value to store, not null
* @throws NullPointerException if the object is null
*/
public MutableInt(Number value) {
super();
this.value = value.intValue();
}
/**
* Constructs a new MutableInt parsing the given string.
*
* @param value the string to parse, not null
* @throws NumberFormatException if the string cannot be parsed into an int
* @since 2.5
*/
public MutableInt(String value) throws NumberFormatException {
super();
this.value = Integer.parseInt(value);
}
//-----------------------------------------------------------------------
/**
* Gets the value as a Integer instance.
*
* @return the value as a Integer, never null
*/
public Integer getValue() {
return Integer.valueOf(this.value);
}
/**
* Sets the value.
*
* @param value the value to set
*/
public void setValue(int value) {
this.value = value;
}
/**
* Sets the value from any Number instance.
*
* @param value the value to set, not null
* @throws NullPointerException if the object is null
*/
public void setValue(Number value) {
this.value = value.intValue();
}
//-----------------------------------------------------------------------
/**
* Increments the value.
*
* @since Commons Lang 2.2
*/
public void increment() {
value++;
}
/**
* Decrements the value.
*
* @since Commons Lang 2.2
*/
public void decrement() {
value--;
}
//-----------------------------------------------------------------------
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @since Commons Lang 2.2
*/
public void add(int operand) {
this.value += operand;
}
/**
* Adds a value to the value of this instance.
*
* @param operand the value to add, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void add(Number operand) {
this.value += operand.intValue();
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @since Commons Lang 2.2
*/
public void subtract(int operand) {
this.value -= operand;
}
/**
* Subtracts a value from the value of this instance.
*
* @param operand the value to subtract, not null
* @throws NullPointerException if the object is null
* @since Commons Lang 2.2
*/
public void subtract(Number operand) {
this.value -= operand.intValue();
}
//-----------------------------------------------------------------------
// shortValue and byteValue rely on Number implementation
/**
* Returns the value of this MutableInt as an int.
*
* @return the numeric value represented by this object after conversion to type int.
*/
@Override
public int intValue() {
return value;
}
/**
* Returns the value of this MutableInt as a long.
*
* @return the numeric value represented by this object after conversion to type long.
*/
@Override
public long longValue() {
return value;
}
/**
* Returns the value of this MutableInt as a float.
*
* @return the numeric value represented by this object after conversion to type float.
*/
@Override
public float floatValue() {
return value;
}
/**
* Returns the value of this MutableInt as a double.
*
* @return the numeric value represented by this object after conversion to type double.
*/
@Override
public double doubleValue() {
return value;
}
//-----------------------------------------------------------------------
/**
* Gets this mutable as an instance of Integer.
*
* @return a Integer instance containing the value from this mutable, never null
*/
public Integer toInteger() {
return Integer.valueOf(intValue());
}
//-----------------------------------------------------------------------
/**
* Compares this object to the specified object. The result is <code>true</code> if and only if the argument is
* not <code>null</code> and is a <code>MutableInt</code> object that contains the same <code>int</code> value
* as this object.
*
* @param obj the object to compare with, null returns false
* @return <code>true</code> if the objects are the same; <code>false</code> otherwise.
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof MutableInt) {
return value == ((MutableInt) obj).intValue();
}
return false;
}
/**
* Returns a suitable hash code for this mutable.
*
* @return a suitable hash code
*/
@Override
public int hashCode() {
return value;
}
//-----------------------------------------------------------------------
/**
* Compares this mutable to another in ascending order.
*
* @param other the other mutable to compare to, not null
* @return negative if this is less, zero if equal, positive if greater
*/
public int compareTo(MutableInt other) {
int anotherVal = other.value;
return value < anotherVal ? -1 : (value == anotherVal ? 0 : 1);
}
//-----------------------------------------------------------------------
/**
* Returns the String value of this mutable.
*
* @return the mutable value as a string
*/
@Override
public String toString() {
return String.valueOf(value);
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!--
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.
-->
<title></title>
</head>
<body>
Provides typed mutable wrappers to primitive values and Object.
@since 2.1
<p>These classes are not thread-safe.</p>
</body>
</html>
<!--
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.
-->
<html>
<body>
<p>
This document is the API specification for the Apache Commons Lang library.
</p>
</body>
</html>
<!--
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.
-->
<html>
<body>
Provides highly reusable static utility methods, chiefly concerned
with adding value to the {@link java.lang} classes.
@since 1.0
<p>Most of these classes are immutable and thus thread-safe.
However Charset is not currently guaranteed thread-safe under all circumstances.</p>
</body>
</html>
/*
* 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 external.org.apache.commons.lang3.reflect;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import external.org.apache.commons.lang3.ClassUtils;
/**
* Contains common code for working with Methods/Constructors, extracted and
* refactored from <code>MethodUtils</code> when it was imported from Commons
* BeanUtils.
*
* @since 2.5
* @version $Id: MemberUtils.java 1143537 2011-07-06 19:30:22Z joehni $
*/
public abstract class MemberUtils {
// TODO extract an interface to implement compareParameterSets(...)?
private static final int ACCESS_TEST = Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE;
/** Array of primitive number types ordered by "promotability" */
private static final Class<?>[] ORDERED_PRIMITIVE_TYPES = { Byte.TYPE, Short.TYPE,
Character.TYPE, Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE };
/**
* XXX Default access superclass workaround
*
* When a public class has a default access superclass with public members,
* these members are accessible. Calling them from compiled code works fine.
* Unfortunately, on some JVMs, using reflection to invoke these members
* seems to (wrongly) prevent access even when the modifier is public.
* Calling setAccessible(true) solves the problem but will only work from
* sufficiently privileged code. Better workarounds would be gratefully
* accepted.
* @param o the AccessibleObject to set as accessible
*/
static void setAccessibleWorkaround(AccessibleObject o) {
if (o == null || o.isAccessible()) {
return;
}
Member m = (Member) o;
if (Modifier.isPublic(m.getModifiers())
&& isPackageAccess(m.getDeclaringClass().getModifiers())) {
try {
o.setAccessible(true);
} catch (SecurityException e) { // NOPMD
// ignore in favor of subsequent IllegalAccessException
}
}
}
/**
* Returns whether a given set of modifiers implies package access.
* @param modifiers to test
* @return true unless package/protected/private modifier detected
*/
static boolean isPackageAccess(int modifiers) {
return (modifiers & ACCESS_TEST) == 0;
}
/**
* Returns whether a Member is accessible.
* @param m Member to check
* @return true if <code>m</code> is accessible
*/
static boolean isAccessible(Member m) {
return m != null && Modifier.isPublic(m.getModifiers()) && !m.isSynthetic();
}
/**
* Compares the relative fitness of two sets of parameter types in terms of
* matching a third set of runtime parameter types, such that a list ordered
* by the results of the comparison would return the best match first
* (least).
*
* @param left the "left" parameter set
* @param right the "right" parameter set
* @param actual the runtime parameter types to match against
* <code>left</code>/<code>right</code>
* @return int consistent with <code>compare</code> semantics
*/
public static int compareParameterTypes(Class<?>[] left, Class<?>[] right, Class<?>[] actual) {
float leftCost = getTotalTransformationCost(actual, left);
float rightCost = getTotalTransformationCost(actual, right);
return leftCost < rightCost ? -1 : rightCost < leftCost ? 1 : 0;
}
/**
* Returns the sum of the object transformation cost for each class in the
* source argument list.
* @param srcArgs The source arguments
* @param destArgs The destination arguments
* @return The total transformation cost
*/
private static float getTotalTransformationCost(Class<?>[] srcArgs, Class<?>[] destArgs) {
float totalCost = 0.0f;
for (int i = 0; i < srcArgs.length; i++) {
Class<?> srcClass, destClass;
srcClass = srcArgs[i];
destClass = destArgs[i];
totalCost += getObjectTransformationCost(srcClass, destClass);
}
return totalCost;
}
/**
* Gets the number of steps required needed to turn the source class into
* the destination class. This represents the number of steps in the object
* hierarchy graph.
* @param srcClass The source class
* @param destClass The destination class
* @return The cost of transforming an object
*/
private static float getObjectTransformationCost(Class<?> srcClass, Class<?> destClass) {
if (destClass.isPrimitive()) {
return getPrimitivePromotionCost(srcClass, destClass);
}
float cost = 0.0f;
while (srcClass != null && !destClass.equals(srcClass)) {
if (destClass.isInterface() && ClassUtils.isAssignable(srcClass, destClass)) {
// slight penalty for interface match.
// we still want an exact match to override an interface match,
// but
// an interface match should override anything where we have to
// get a superclass.
cost += 0.25f;
break;
}
cost++;
srcClass = srcClass.getSuperclass();
}
/*
* If the destination class is null, we've travelled all the way up to
* an Object match. We'll penalize this by adding 1.5 to the cost.
*/
if (srcClass == null) {
cost += 1.5f;
}
return cost;
}
/**
* Gets the number of steps required to promote a primitive number to another
* type.
* @param srcClass the (primitive) source class
* @param destClass the (primitive) destination class
* @return The cost of promoting the primitive
*/
private static float getPrimitivePromotionCost(final Class<?> srcClass, final Class<?> destClass) {
float cost = 0.0f;
Class<?> cls = srcClass;
if (!cls.isPrimitive()) {
// slight unwrapping penalty
cost += 0.1f;
cls = ClassUtils.wrapperToPrimitive(cls);
}
for (int i = 0; cls != destClass && i < ORDERED_PRIMITIVE_TYPES.length; i++) {
if (cls == ORDERED_PRIMITIVE_TYPES[i]) {
cost += 0.1f;
if (i < ORDERED_PRIMITIVE_TYPES.length - 1) {
cls = ORDERED_PRIMITIVE_TYPES[i + 1];
}
}
}
return cost;
}
}
/*
* 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 external.org.apache.commons.lang3.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import external.org.apache.commons.lang3.ArrayUtils;
import external.org.apache.commons.lang3.ClassUtils;
/**
* <p>Utility reflection methods focused on methods, originally from Commons BeanUtils.
* Differences from the BeanUtils version may be noted, especially where similar functionality
* already existed within Lang.
* </p>
*
* <h3>Known Limitations</h3>
* <h4>Accessing Public Methods In A Default Access Superclass</h4>
* <p>There is an issue when invoking public methods contained in a default access superclass on JREs prior to 1.4.
* Reflection locates these methods fine and correctly assigns them as public.
* However, an <code>IllegalAccessException</code> is thrown if the method is invoked.</p>
*
* <p><code>MethodUtils</code> contains a workaround for this situation.
* It will attempt to call <code>setAccessible</code> on this method.
* If this call succeeds, then the method can be invoked as normal.
* This call will only succeed when the application has sufficient security privileges.
* If this call fails then the method may fail.</p>
*
* @since 2.5
* @version $Id: MethodUtils.java 1166253 2011-09-07 16:27:42Z ggregory $
*/
public class MethodUtils {
/**
* <p>MethodUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* <code>MethodUtils.getAccessibleMethod(method)</code>.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public MethodUtils() {
super();
}
/**
* <p>Invokes a named method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* would match a <code>boolean</code> primitive.</p>
*
* <p>This is a convenient wrapper for
* {@link #invokeMethod(Object object,String methodName, Object[] args, Class[] parameterTypes)}.
* </p>
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the method invoked
* @throws IllegalAccessException if the requested method is not accessible via reflection
*/
public static Object invokeMethod(Object object, String methodName,
Object... args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class<?>[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeMethod(object, methodName, args, parameterTypes);
}
/**
* <p>Invokes a named method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> object
* would match a <code>boolean</code> primitive.</p>
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the method invoked
* @throws IllegalAccessException if the requested method is not accessible via reflection
*/
public static Object invokeMethod(Object object, String methodName,
Object[] args, Class<?>[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Method method = getMatchingAccessibleMethod(object.getClass(),
methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ object.getClass().getName());
}
return method.invoke(object, args);
}
/**
* <p>Invokes a method whose parameter types match exactly the object
* types.</p>
*
* <p>This uses reflection to invoke the method obtained from a call to
* <code>getAccessibleMethod()</code>.</p>
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactMethod(Object object, String methodName,
Object... args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class<?>[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactMethod(object, methodName, args, parameterTypes);
}
/**
* <p>Invokes a method whose parameter types match exactly the parameter
* types given.</p>
*
* <p>This uses reflection to invoke the method obtained from a call to
* <code>getAccessibleMethod()</code>.</p>
*
* @param object invoke method on this object
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactMethod(Object object, String methodName,
Object[] args, Class<?>[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Method method = getAccessibleMethod(object.getClass(), methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on object: "
+ object.getClass().getName());
}
return method.invoke(object, args);
}
/**
* <p>Invokes a static method whose parameter types match exactly the parameter
* types given.</p>
*
* <p>This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.</p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactStaticMethod(Class<?> cls, String methodName,
Object[] args, Class<?>[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
Method method = getAccessibleMethod(cls, methodName, parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* <p>Invokes a named static method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
* <p>This is a convenient wrapper for
* {@link #invokeStaticMethod(Class objectClass,String methodName,Object [] args,Class[] parameterTypes)}.
* </p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeStaticMethod(Class<?> cls, String methodName,
Object... args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class<?>[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* <p>Invokes a named static method whose parameter type matches the object type.</p>
*
* <p>This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.</p>
*
* <p>This method supports calls to methods taking primitive parameters
* via passing in wrapping classes. So, for example, a <code>Boolean</code> class
* would match a <code>boolean</code> primitive.</p>
*
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @param parameterTypes match these parameters - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeStaticMethod(Class<?> cls, String methodName,
Object[] args, Class<?>[] parameterTypes)
throws NoSuchMethodException, IllegalAccessException,
InvocationTargetException {
if (parameterTypes == null) {
parameterTypes = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
Method method = getMatchingAccessibleMethod(cls, methodName,
parameterTypes);
if (method == null) {
throw new NoSuchMethodException("No such accessible method: "
+ methodName + "() on class: " + cls.getName());
}
return method.invoke(null, args);
}
/**
* <p>Invokes a static method whose parameter types match exactly the object
* types.</p>
*
* <p>This uses reflection to invoke the method obtained from a call to
* {@link #getAccessibleMethod(Class, String, Class[])}.</p>
*
* @param cls invoke static method on this class
* @param methodName get method with this name
* @param args use these arguments - treat null as empty array
* @return The value returned by the invoked method
*
* @throws NoSuchMethodException if there is no such accessible method
* @throws InvocationTargetException wraps an exception thrown by the
* method invoked
* @throws IllegalAccessException if the requested method is not accessible
* via reflection
*/
public static Object invokeExactStaticMethod(Class<?> cls, String methodName,
Object... args) throws NoSuchMethodException,
IllegalAccessException, InvocationTargetException {
if (args == null) {
args = ArrayUtils.EMPTY_OBJECT_ARRAY;
}
int arguments = args.length;
Class<?>[] parameterTypes = new Class[arguments];
for (int i = 0; i < arguments; i++) {
parameterTypes[i] = args[i].getClass();
}
return invokeExactStaticMethod(cls, methodName, args, parameterTypes);
}
/**
* <p>Returns an accessible method (that is, one that can be invoked via
* reflection) with given name and parameters. If no such method
* can be found, return <code>null</code>.
* This is just a convenient wrapper for
* {@link #getAccessibleMethod(Method method)}.</p>
*
* @param cls get method from this class
* @param methodName get method with this name
* @param parameterTypes with these parameters types
* @return The accessible method
*/
public static Method getAccessibleMethod(Class<?> cls, String methodName,
Class<?>... parameterTypes) {
try {
return getAccessibleMethod(cls.getMethod(methodName,
parameterTypes));
} catch (NoSuchMethodException e) {
return null;
}
}
/**
* <p>Returns an accessible method (that is, one that can be invoked via
* reflection) that implements the specified Method. If no such method
* can be found, return <code>null</code>.</p>
*
* @param method The method that we wish to call
* @return The accessible method
*/
public static Method getAccessibleMethod(Method method) {
if (!MemberUtils.isAccessible(method)) {
return null;
}
// If the declaring class is public, we are done
Class<?> cls = method.getDeclaringClass();
if (Modifier.isPublic(cls.getModifiers())) {
return method;
}
String methodName = method.getName();
Class<?>[] parameterTypes = method.getParameterTypes();
// Check the implemented interfaces and subinterfaces
method = getAccessibleMethodFromInterfaceNest(cls, methodName,
parameterTypes);
// Check the superclass chain
if (method == null) {
method = getAccessibleMethodFromSuperclass(cls, methodName,
parameterTypes);
}
return method;
}
/**
* <p>Returns an accessible method (that is, one that can be invoked via
* reflection) by scanning through the superclasses. If no such method
* can be found, return <code>null</code>.</p>
*
* @param cls Class to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
* @return the accessible method or <code>null</code> if not found
*/
private static Method getAccessibleMethodFromSuperclass(Class<?> cls,
String methodName, Class<?>... parameterTypes) {
Class<?> parentClass = cls.getSuperclass();
while (parentClass != null) {
if (Modifier.isPublic(parentClass.getModifiers())) {
try {
return parentClass.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
return null;
}
}
parentClass = parentClass.getSuperclass();
}
return null;
}
/**
* <p>Returns an accessible method (that is, one that can be invoked via
* reflection) that implements the specified method, by scanning through
* all implemented interfaces and subinterfaces. If no such method
* can be found, return <code>null</code>.</p>
*
* <p>There isn't any good reason why this method must be private.
* It is because there doesn't seem any reason why other classes should
* call this rather than the higher level methods.</p>
*
* @param cls Parent class for the interfaces to be checked
* @param methodName Method name of the method we wish to call
* @param parameterTypes The parameter type signatures
* @return the accessible method or <code>null</code> if not found
*/
private static Method getAccessibleMethodFromInterfaceNest(Class<?> cls,
String methodName, Class<?>... parameterTypes) {
Method method = null;
// Search up the superclass chain
for (; cls != null; cls = cls.getSuperclass()) {
// Check the implemented interfaces of the parent class
Class<?>[] interfaces = cls.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
// Is this interface public?
if (!Modifier.isPublic(interfaces[i].getModifiers())) {
continue;
}
// Does the method exist on this interface?
try {
method = interfaces[i].getDeclaredMethod(methodName,
parameterTypes);
} catch (NoSuchMethodException e) { // NOPMD
/*
* Swallow, if no method is found after the loop then this
* method returns null.
*/
}
if (method != null) {
break;
}
// Recursively check our parent interfaces
method = getAccessibleMethodFromInterfaceNest(interfaces[i],
methodName, parameterTypes);
if (method != null) {
break;
}
}
}
return method;
}
/**
* <p>Finds an accessible method that matches the given name and has compatible parameters.
* Compatible parameters mean that every method parameter is assignable from
* the given parameters.
* In other words, it finds a method with the given name
* that will take the parameters given.<p>
*
* <p>This method is used by
* {@link
* #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
*
* <p>This method can match primitive parameter by passing in wrapper classes.
* For example, a <code>Boolean</code> will match a primitive <code>boolean</code>
* parameter.
*
* @param cls find method in this class
* @param methodName find method with this name
* @param parameterTypes find method with most compatible parameters
* @return The accessible method
*/
public static Method getMatchingAccessibleMethod(Class<?> cls,
String methodName, Class<?>... parameterTypes) {
try {
Method method = cls.getMethod(methodName, parameterTypes);
MemberUtils.setAccessibleWorkaround(method);
return method;
} catch (NoSuchMethodException e) { // NOPMD - Swallow the exception
}
// search through all methods
Method bestMatch = null;
Method[] methods = cls.getMethods();
for (Method method : methods) {
// compare name and parameters
if (method.getName().equals(methodName) && ClassUtils.isAssignable(parameterTypes, method.getParameterTypes(), true)) {
// get accessible version of method
Method accessibleMethod = getAccessibleMethod(method);
if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareParameterTypes(
accessibleMethod.getParameterTypes(),
bestMatch.getParameterTypes(),
parameterTypes) < 0)) {
bestMatch = accessibleMethod;
}
}
}
if (bestMatch != null) {
MemberUtils.setAccessibleWorkaround(bestMatch);
}
return bestMatch;
}
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<!--
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.
-->
<title></title>
</head>
<body>
Accumulates common high-level uses of the <code>java.lang.reflect</code> APIs.
@since 3.0
<p>These classes are immutable, and therefore thread-safe.</p>
</body>
</html>
/*
* 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 external.org.apache.commons.lang3.tuple;
/**
* <p>An immutable pair consisting of two {@code Object} elements.</p>
*
* <p>Although the implementation is immutable, there is no restriction on the objects
* that may be stored. If mutable objects are stored in the pair, then the pair
* itself effectively becomes mutable. The class is also not {@code final}, so a subclass
* could add undesirable behaviour.</p>
*
* <p>#ThreadSafe# if the objects are threadsafe</p>
*
* @param <L> the left element type
* @param <R> the right element type
*
* @since Lang 3.0
* @version $Id: ImmutablePair.java 1127544 2011-05-25 14:35:42Z scolebourne $
*/
public final class ImmutablePair<L, R> extends Pair<L, R> {
/** Serialization version */
private static final long serialVersionUID = 4954918890077093841L;
/** Left object */
public final L left;
/** Right object */
public final R right;
/**
* <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
*
* <p>This factory allows the pair to be created using inference to
* obtain the generic types.</p>
*
* @param <L> the left element type
* @param <R> the right element type
* @param left the left element, may be null
* @param right the right element, may be null
* @return a pair formed from the two parameters, not null
*/
public static <L, R> ImmutablePair<L, R> of(L left, R right) {
return new ImmutablePair<L, R>(left, right);
}
/**
* Create a new pair instance.
*
* @param left the left value, may be null
* @param right the right value, may be null
*/
public ImmutablePair(L left, R right) {
super();
this.left = left;
this.right = right;
}
//-----------------------------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public L getLeft() {
return left;
}
/**
* {@inheritDoc}
*/
@Override
public R getRight() {
return right;
}
/**
* <p>Throws {@code UnsupportedOperationException}.</p>
*
* <p>This pair is immutable, so this operation is not supported.</p>
*
* @param value the value to set
* @return never
* @throws UnsupportedOperationException as this operation is not supported
*/
public R setValue(R value) {
throw new UnsupportedOperationException();
}
}
/*
* 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 external.org.apache.commons.lang3.tuple;
import java.io.Serializable;
import java.util.Map;
import external.org.apache.commons.lang3.ObjectUtils;
import external.org.apache.commons.lang3.builder.CompareToBuilder;
/**
* <p>A pair consisting of two elements.</p>
*
* <p>This class is an abstract implementation defining the basic API.
* It refers to the elements as 'left' and 'right'. It also implements the
* {@code Map.Entry} interface where the key is 'left' and the value is 'right'.</p>
*
* <p>Subclass implementations may be mutable or immutable.
* However, there is no restriction on the type of the stored objects that may be stored.
* If mutable objects are stored in the pair, then the pair itself effectively becomes mutable.</p>
*
* @param <L> the left element type
* @param <R> the right element type
*
* @since Lang 3.0
* @version $Id: Pair.java 1142401 2011-07-03 08:30:12Z bayard $
*/
public abstract class Pair<L, R> implements Map.Entry<L, R>, Comparable<Pair<L, R>>, Serializable {
/** Serialization version */
private static final long serialVersionUID = 4954918890077093841L;
/**
* <p>Obtains an immutable pair of from two objects inferring the generic types.</p>
*
* <p>This factory allows the pair to be created using inference to
* obtain the generic types.</p>
*
* @param <L> the left element type
* @param <R> the right element type
* @param left the left element, may be null
* @param right the right element, may be null
* @return a pair formed from the two parameters, not null
*/
public static <L, R> Pair<L, R> of(L left, R right) {
return new ImmutablePair<L, R>(left, right);
}
//-----------------------------------------------------------------------
/**
* <p>Gets the left element from this pair.</p>
*
* <p>When treated as a key-value pair, this is the key.</p>
*
* @return the left element, may be null
*/
public abstract L getLeft();
/**
* <p>Gets the right element from this pair.</p>
*
* <p>When treated as a key-value pair, this is the value.</p>
*
* @return the right element, may be null
*/
public abstract R getRight();
/**
* <p>Gets the key from this pair.</p>
*
* <p>This method implements the {@code Map.Entry} interface returning the
* left element as the key.</p>
*
* @return the left element as the key, may be null
*/
public final L getKey() {
return getLeft();
}
/**
* <p>Gets the value from this pair.</p>
*
* <p>This method implements the {@code Map.Entry} interface returning the
* right element as the value.</p>
*
* @return the right element as the value, may be null
*/
public R getValue() {
return getRight();
}
//-----------------------------------------------------------------------
/**
* <p>Compares the pair based on the left element followed by the right element.
* The types must be {@code Comparable}.</p>
*
* @param other the other pair, not null
* @return negative if this is less, zero if equal, positive if greater
*/
public int compareTo(Pair<L, R> other) {
return new CompareToBuilder().append(getLeft(), other.getLeft())
.append(getRight(), other.getRight()).toComparison();
}
/**
* <p>Compares this pair to another based on the two elements.</p>
*
* @param obj the object to compare to, null returns false
* @return true if the elements of the pair are equal
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof Map.Entry<?, ?>) {
Map.Entry<?, ?> other = (Map.Entry<?, ?>) obj;
return ObjectUtils.equals(getKey(), other.getKey())
&& ObjectUtils.equals(getValue(), other.getValue());
}
return false;
}
/**
* <p>Returns a suitable hash code.
* The hash code follows the definition in {@code Map.Entry}.</p>
*
* @return the hash code
*/
@Override
public int hashCode() {
// see Map.Entry API specification
return (getKey() == null ? 0 : getKey().hashCode()) ^
(getValue() == null ? 0 : getValue().hashCode());
}
/**
* <p>Returns a String representation of this pair using the format {@code ($left,$right)}.</p>
*
* @return a string describing this object, not null
*/
@Override
public String toString() {
return new StringBuilder().append('(').append(getLeft()).append(',').append(getRight()).append(')').toString();
}
/**
* <p>Formats the receiver using the given format.</p>
*
* <p>This uses {@link java.util.Formattable} to perform the formatting. Two variables may
* be used to embed the left and right elements. Use {@code %1$s} for the left
* element (key) and {@code %2$s} for the right element (value).
* The default format used by {@code toString()} is {@code (%1$s,%2$s)}.</p>
*
* @param format the format string, optionally containing {@code %1$s} and {@code %2$s}, not null
* @return the formatted string, not null
*/
public String toString(String format) {
return String.format(format, getLeft(), getRight());
}
}
<!--
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.
-->
<html>
<body>
Tuple classes, starting with a Pair class in version 3.0.
@since 3.0
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment