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

com.mchange.v2.util.CollectionUtils Maven / Gradle / Ivy

There is a newer version: 0.2.20_1
Show newest version
/*
 * Distributed as part of mchange-commons-java 0.2.11
 *
 * Copyright (C) 2015 Machinery For Change, Inc.
 *
 * Author: Steve Waldman 
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of EITHER:
 *
 *     1) The GNU Lesser General Public License (LGPL), version 2.1, as 
 *        published by the Free Software Foundation
 *
 * OR
 *
 *     2) The Eclipse Public License (EPL), version 1.0
 *
 * You may choose which license to accept if you wish to redistribute
 * or modify this work. You may offer derivatives of this work
 * under the license you have chosen, or you may provide the same
 * choice of license which you have been offered here.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received copies of both LGPL v2.1 and EPL v1.0
 * along with this software; see the files LICENSE-EPL and LICENSE-LGPL.
 * If not, the text of these licenses are currently available at
 *
 * LGPL v2.1: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
 *  EPL v1.0: http://www.eclipse.org/org/documents/epl-v10.php 
 * 
 */

package com.mchange.v2.util;

import java.util.*;
import java.lang.reflect.*;

/*
 * Note: This class makes assumptions about the implementation of Collections.unmodifiableXXX( ... )
 * and Collections.synchronizedXXX( ... ) that could conceivably not hold in some Java std class
 * implementation... but the implementation is robust to the most likely implementations of these
 * methods.
 */
public final class CollectionUtils
{
    public final static SortedSet EMPTY_SORTED_SET = Collections.unmodifiableSortedSet( new TreeSet() );

    final static Class[]  EMPTY_ARG_CLASSES = { };
    final static Object[] EMPTY_ARGS        = { };

    final static Class[] COMPARATOR_ARG_CLASSES = { Comparator.class };
    final static Class[] COLLECTION_ARG_CLASSES = { Collection.class };
    final static Class[] SORTED_SET_ARG_CLASSES = { SortedSet.class };
    final static Class[] MAP_ARG_CLASSES        = { Map.class };
    final static Class[] SORTED_MAP_ARG_CLASSES = { SortedMap.class };

    final static Class STD_UNMODIFIABLE_COLLECTION_CL;
    final static Class STD_UNMODIFIABLE_SET_CL;
    final static Class STD_UNMODIFIABLE_LIST_CL;
    final static Class STD_UNMODIFIABLE_RA_LIST_CL;
    final static Class STD_UNMODIFIABLE_SORTED_SET_CL;
    final static Class STD_UNMODIFIABLE_MAP_CL;
    final static Class STD_UNMODIFIABLE_SORTED_MAP_CL;
    final static Class STD_SYNCHRONIZED_COLLECTION_CL;
    final static Class STD_SYNCHRONIZED_SET_CL;
    final static Class STD_SYNCHRONIZED_LIST_CL;
    final static Class STD_SYNCHRONIZED_RA_LIST_CL;
    final static Class STD_SYNCHRONIZED_SORTED_SET_CL;
    final static Class STD_SYNCHRONIZED_MAP_CL;
    final static Class STD_SYNCHRONIZED_SORTED_MAP_CL;

    final static Set UNMODIFIABLE_WRAPPERS;
    final static Set SYNCHRONIZED_WRAPPERS;
    final static Set ALL_COLLECTIONS_WRAPPERS;

    static
    {
	HashSet hs = new HashSet();
	TreeSet ts = new TreeSet();
	LinkedList ll = new LinkedList();
	ArrayList al = new ArrayList();
	HashMap hm = new HashMap();
	TreeMap tm = new TreeMap();

	HashSet tmp0 = new HashSet();
	HashSet tmp1 = new HashSet();

	tmp0.add( STD_UNMODIFIABLE_COLLECTION_CL = Collections.unmodifiableCollection( al ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_SET_CL = Collections.unmodifiableSet( hs ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_LIST_CL = Collections.unmodifiableList( ll ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_RA_LIST_CL = Collections.unmodifiableList( al ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_SORTED_SET_CL = Collections.unmodifiableSortedSet( ts ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_MAP_CL = Collections.unmodifiableMap( hm ).getClass() );
	tmp0.add( STD_UNMODIFIABLE_SORTED_MAP_CL = Collections.unmodifiableSortedMap( tm ).getClass() );

	tmp1.add( STD_SYNCHRONIZED_COLLECTION_CL = Collections.synchronizedCollection( al ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_SET_CL = Collections.synchronizedSet( hs ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_LIST_CL = Collections.synchronizedList( ll ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_RA_LIST_CL = Collections.synchronizedList( al ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_SORTED_SET_CL = Collections.synchronizedSortedSet( ts ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_MAP_CL = Collections.synchronizedMap( hm ).getClass() );
	tmp1.add( STD_SYNCHRONIZED_SORTED_MAP_CL = Collections.synchronizedMap( tm ).getClass() );

	UNMODIFIABLE_WRAPPERS = Collections.unmodifiableSet( tmp0 );

	SYNCHRONIZED_WRAPPERS = Collections.unmodifiableSet( tmp1 );

	HashSet tmp2 = new HashSet( tmp0 );
	tmp2.addAll( tmp1 );
	ALL_COLLECTIONS_WRAPPERS = Collections.unmodifiableSet( tmp2 );
    }

    public static boolean isCollectionsWrapper( Class cl )
    { return ALL_COLLECTIONS_WRAPPERS.contains( cl ); }

    public static boolean isCollectionsWrapper( Collection c )
    { return isCollectionsWrapper( c.getClass() ); }

    public static boolean isCollectionsWrapper( Map m )
    { return isCollectionsWrapper( m.getClass() ); }

    public static boolean isSynchronizedWrapper( Class cl )
    { return SYNCHRONIZED_WRAPPERS.contains( cl ); }

    public static boolean isSynchronizedWrapper( Collection c )
    { return isSynchronizedWrapper( c.getClass() ); }

    public static boolean isSynchronizedWrapper( Map m )
    { return isSynchronizedWrapper( m.getClass() ); }

    public static boolean isUnmodifiableWrapper( Class cl )
    { return UNMODIFIABLE_WRAPPERS.contains( cl ); }

    public static boolean isUnmodifiableWrapper( Collection c )
    { return isUnmodifiableWrapper( c.getClass() ); }

    public static boolean isUnmodifiableWrapper( Map m )
    { return isUnmodifiableWrapper( m.getClass() ); }

    /*
     * should we worry about the case where an Object (bizarrely)
     * implements both Set and List? don't think so...
     */
    public static Collection narrowUnmodifiableCollection( Collection c )
    {
	if (c instanceof SortedSet)
	    return Collections.unmodifiableSortedSet( (SortedSet) c );
	else if (c instanceof Set)
	    return Collections.unmodifiableSet( (Set) c );
	else if (c instanceof List)
	    return Collections.unmodifiableList( (List) c );
	else
	    return Collections.unmodifiableCollection( c );
    }

    /*
     * should we worry about the case where an Object (bizarrely)
     * implements both Set and List? don't think so...
     */
    public static Collection narrowSynchronizedCollection( Collection c )
    {
	if (c instanceof SortedSet)
	    return Collections.synchronizedSortedSet( (SortedSet) c );
	else if (c instanceof Set)
	    return Collections.synchronizedSet( (Set) c );
	else if (c instanceof List)
	    return Collections.synchronizedList( (List) c );
	else
	    return Collections.synchronizedCollection( c );
    }

    public static Map narrowUnmodifiableMap( Map m )
    {
	if (m instanceof SortedMap)
	    return Collections.unmodifiableSortedMap( (SortedMap) m );
	else
	    return Collections.unmodifiableMap( m );
    }

    public static Map narrowSynchronizedMap( Map m )
    {
	if (m instanceof SortedMap)
	    return Collections.synchronizedSortedMap( (SortedMap) m );
	else
	    return Collections.synchronizedMap( m );
    }

    /**
     *  Attempts to find a public clone() method or a copy constructor, in that
     *  order, and calls what it finds. If neither is available, throws a NoSuchMethodException.
     */
    public static Collection attemptClone( Collection c ) throws NoSuchMethodException
    {
	if (c instanceof Vector) return (Collection) ((Vector) c).clone();
	else if (c instanceof ArrayList) return (Collection) ((ArrayList) c).clone();
	else if (c instanceof LinkedList) return (Collection) ((LinkedList) c).clone();
	else if (c instanceof HashSet) return (Collection) ((HashSet) c).clone();
	else if (c instanceof TreeSet) return (Collection) ((TreeSet) c).clone();
	else
	    {
		Collection out = null;
		Class colClass = c.getClass();
		try
		    {
			Method m = colClass.getMethod("clone", EMPTY_ARG_CLASSES);
			out = (Collection) m.invoke( c, EMPTY_ARGS );
		    }
		catch ( Exception e )
		    { 
			/* IGNORE... just means there's no accessible clone() here */ 
			if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
			    e.printStackTrace();
		    }

		if ( out == null )
		    {
			try
			    {
				Constructor ctor = colClass.getConstructor( (c instanceof SortedSet) ? SORTED_SET_ARG_CLASSES : COLLECTION_ARG_CLASSES );
				out = (Collection) ctor.newInstance( new Object[] { c } );
			    }
			catch ( Exception e )
			    { 
				/* IGNORE... just means there's no accessible ctor here */ 
				if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
				    e.printStackTrace();
			    }
		    }

		if ( out == null )
		    {
			try
			    {
				Constructor ctor = colClass.getConstructor( new Class[] { colClass } );
				out = (Collection) ctor.newInstance( new Object[] { c } );
			    }
			catch ( Exception e )
			    { 
				/* IGNORE... just means there's no accessible ctor here */ 
				if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
				    e.printStackTrace();
			    }
		    }

		if (out == null)
		    throw new NoSuchMethodException("No accessible clone() method or reasonable copy constructor could be called on Collection " + c);
		else
		    return out;
	    }
    }

    /**
     *  Attempts to find a public clone() method or a copy constructor, in that
     *  order, and calls what it finds. If neither is available, throws a NoSuchMethodException.
     */
    public static Map attemptClone( Map m ) throws NoSuchMethodException
    {
	if (m instanceof Properties) return (Map) ((Properties) m).clone();
	else if (m instanceof Hashtable) return (Map) ((Hashtable) m).clone();
	else if (m instanceof HashMap) return (Map) ((HashMap) m).clone();
	else if (m instanceof TreeMap) return (Map) ((TreeMap) m).clone();
	else
	    {
		Map out = null;
		Class mapClass = m.getClass();
		try
		    {
			Method meth = mapClass.getMethod("clone", EMPTY_ARG_CLASSES);
			out = (Map) meth.invoke( m, EMPTY_ARGS );
		    }
		catch ( Exception e )
		    { 
			/* IGNORE... just means there's no accessible clone() here */ 
			if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
			    e.printStackTrace();
		    }

		if ( out == null )
		    {
			try
			    {
				Constructor ctor = mapClass.getConstructor( (m instanceof SortedMap) ? SORTED_MAP_ARG_CLASSES : MAP_ARG_CLASSES );
				out = (Map) ctor.newInstance( new Object[] { m } );
			    }
			catch ( Exception e )
			    { 
				/* IGNORE... just means there's no accessible ctor here */ 
				if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
				    e.printStackTrace();
			    }
		    }

		if ( out == null )
		    {
			try
			    {
				Constructor ctor = mapClass.getConstructor( new Class[] { mapClass } );
				out = (Map) ctor.newInstance( new Object[] { m } );
			    }
			catch ( Exception e )
			    { 
				/* IGNORE... just means there's no accessible ctor here */ 
				if ( Debug.DEBUG && Debug.TRACE == Debug.TRACE_MAX )
				    e.printStackTrace();
			    }
		    }

		if (out == null)
		    throw new NoSuchMethodException("No accessible clone() method or reasonable copy constructor could be called on Map " + m);
		else
		    return out;
	    }
    }

    /*
     * These functions are primarily motivated by a desire
     * to manipulate Collections from JSP 2.0 Expression
     * Language functions, which must be mapped to public 
     * static functions.
     */ 
    public static void add(Collection c, Object o)
    { c.add( o ); }

    public static void remove(Collection c, Object o)
    { c.remove( o ); }

    public static int size( Object o )
    {
	if (o instanceof Collection)
	    return ((Collection) o).size();
	else if (o instanceof Map)
	    return ((Map) o).size();
	else if (o instanceof Object[])
	    return ((Object[]) o).length;
	else if (o instanceof boolean[])
	    return ((boolean[]) o).length;
	else if (o instanceof byte[])
	    return ((byte[]) o).length;
	else if (o instanceof char[])
	    return ((char[]) o).length;
	else if (o instanceof short[])
	    return ((short[]) o).length;
	else if (o instanceof int[])
	    return ((int[]) o).length;
	else if (o instanceof long[])
	    return ((long[]) o).length;
	else if (o instanceof float[])
	    return ((float[]) o).length;
	else if (o instanceof double[])
	    return ((double[]) o).length;
	else
	    throw new IllegalArgumentException(o + " must be a Collection, Map, or array!");
    }

    private CollectionUtils()
    {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy