All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.unkrig.commons.lang.ObjectUtil Maven / Gradle / Ivy


/*
 * de.unkrig.commons - A general-purpose Java class library
 *
 * Copyright (c) 2011, Arno Unkrig
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
 * following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
 *       following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
 *       following disclaimer in the documentation and/or other materials provided with the distribution.
 *    3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
 *       products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package de.unkrig.commons.lang;

import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.util.EnumSet;
import java.util.regex.Pattern;

import de.unkrig.commons.nullanalysis.NotNull;
import de.unkrig.commons.nullanalysis.Nullable;

/**
 * Various {@code java.lang.Object}-related utility methods.
 */
public final
class ObjectUtil {

    private static final Pattern WORD_SEPARATOR = Pattern.compile("[\\s,]+");

    private ObjectUtil() {}

    /**
     * The often-needed "equal" method that handles {@code null} references.
     * 

* Redeemed by {@code java.util.Objects.equals(Object, Object)} which is available since Java 1.7. *

* * @return Both arguments are {@code null}, or are {@link CharSequence}s with equal contents, or are equal */ public static boolean equals(@Nullable T o1, @Nullable T o2) { if (o1 == null) return o2 == null; if (o2 == null) return false; if (o1 instanceof CharSequence && o2 instanceof CharSequence) { return StringUtil.equals((CharSequence) o1, (CharSequence) o2); } return o1.equals(o2); } /** * @return {@code Null} iff {@code o == null}, otherwise {@code o.hashCode()} */ public static int hashCode(@Nullable Object o) { return o == null ? 0 : o.hashCode(); } /** * @return Returns {@code value.toString()} or the defaultValue iff {@code value == null} */ public static String toString(@Nullable T value, String defaultValue) { return value != null ? value.toString() : defaultValue; } /** * @return lhs, or rhs iff {@code lhs == null} */ public static T or(@Nullable T lhs, T rhs) { return lhs == null ? rhs : lhs; } /** * Converts a string to an object of the given targetType. *

* For primitive targetTypes, the corresponding wrapper object is returned. *

*

* Supports all primitive types (except {@code void}), their wrapper types, {@link String}, {@code char[]}, * {@link Charset}, {@link Class}, {@link Pattern}, enum types, and classes that have a single-string-parameter * constructor. *

*

* Supports (one-dimensional) arrays of these types, where the text is split into words at commas * and/or whitespace, and each word converted to the component type. *

*

* Does not support collections, including {@link EnumSet}s, because the element type cannot be determined * through REFLECTION. Usage of an array is recommended as a workaround, as follows: *

*
{@code
     *String  s   = "RED,GREEN";
     *Color[] tmp = ObjectUtil.fromString(s, Color[].class);
     *
     *List    list    = Arrays.asList(tmp);
     *EnumSet enumSet = EnumSet.copyOf(Arrays.asList(tmp));
     *Set     set     = new HashSet(Arrays.asList(tmp));
     *}
* * @throws NumberFormatException The string could not be converted to the targetType * @throws IllegalArgumentException The string could not be converted to the targetType * @throws RuntimeException The string could not be converted to the targetType */ @SuppressWarnings("unchecked") public static T fromString(String text, Class targetType) { if (targetType.isArray()) { Class componentType = targetType.getComponentType(); String[] words = ObjectUtil.WORD_SEPARATOR.split(text); Object array = Array.newInstance(componentType, words.length); for (int i = 0; i < words.length; i++) { Array.set(array, i, ObjectUtil.fromString(words[i], componentType)); } return (T) array; } if (targetType == String.class) return (T) text; try { if (targetType == boolean.class || targetType == Boolean.class) return (T) Boolean.valueOf(text); if (targetType == byte.class || targetType == Byte.class) return (T) Byte.valueOf(text); if (targetType == short.class || targetType == Short.class) return (T) Short.valueOf(text); if (targetType == int.class || targetType == Integer.class) return (T) Integer.valueOf(text); if (targetType == long.class || targetType == Long.class) return (T) Long.valueOf(text); if (targetType == float.class || targetType == Float.class) return (T) Float.valueOf(text); if (targetType == double.class || targetType == Double.class) return (T) Double.valueOf(text); } catch (IllegalArgumentException iae) { throw new IllegalArgumentException( "Cannot convert \"" + text + "\" to " + targetType.getSimpleName().toLowerCase() ); } if (targetType == char.class || targetType == Character.class) { if (text.length() == 0) throw new IllegalArgumentException("Empty string"); if (text.length() > 1) throw new IllegalArgumentException("String too long"); return (T) Character.valueOf(text.charAt(0)); } if (targetType == char[].class) return (T) text.toCharArray(); if (targetType == Charset.class) return (T) Charset.forName(text); if (targetType == Class.class) { try { return (T) Class.forName(text); } catch (ClassNotFoundException cnfe) { throw new IllegalArgumentException(cnfe); } catch (NoClassDefFoundError ncdfe) { throw new IllegalArgumentException(ncdfe); } } if (targetType == Pattern.class) return (T) Pattern.compile(text); if (Enum.class.isAssignableFrom(targetType)) { try { @SuppressWarnings("rawtypes") Enum constant = Enum.valueOf((Class) targetType, text); return (T) constant; } catch (IllegalArgumentException iae) { @SuppressWarnings("rawtypes") EnumSet allConstants = EnumSet.allOf((Class) targetType); throw new IllegalArgumentException( "Invalid constant \"" + text + "\"; valid values are " + allConstants ); } } // For all other parameter types, use the single-string-parameter constructor. try { return targetType.getConstructor(String.class).newInstance(text); } catch (Exception e) { throw new IllegalArgumentException(( "Instantiating " + targetType.getSimpleName() + ": " + e.getMessage() ), e); } } /** * This method returns {@code null} although it is declared {@link NotNull @NotNull}. This comes in handy to * initialize a field that is declared as {@code NotNull @NotNull}, but is filled reflectively, e.g. by * frameworks like JUNIT or SPRING. */ @SuppressWarnings("null") public static T almostNull() { return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy