001/* ===========================================================
002 * JFreeChart : a free chart library for the Java(tm) platform
003 * ===========================================================
004 *
005 * (C) Copyright 2000-present, by David Gilbert and Contributors.
006 *
007 * Project Info:  http://www.jfree.org/jfreechart/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
022 * USA.
023 *
024 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
025 * Other names may be trademarks of their respective owners.]
026 * 
027 * ---------------
028 * CloneUtils.java
029 * ---------------
030 * (C) Copyright 2014-present, by David Gilbert.
031 *
032 * Original Author:  David Gilbert;
033 * Contributor(s):   -;
034 *
035 */
036package org.jfree.chart.util;
037
038import java.lang.reflect.InvocationTargetException;
039import java.lang.reflect.Method;
040import java.lang.reflect.Modifier;
041import java.util.ArrayList;
042import java.util.HashMap;
043import java.util.List;
044import java.util.Map;
045
046/**
047 * Utilities for cloning.
048 */
049public class CloneUtils {
050
051    /**
052     * Returns a clone of the specified object, if it can be cloned, otherwise
053     * throws a {@code CloneNotSupportedException}.
054     *
055     * @param object the object to clone ({@code null} not permitted).
056     * @return A clone of the specified object.
057     * @throws CloneNotSupportedException if the object cannot be cloned.
058     */
059    public static Object clone(Object object)
060        throws CloneNotSupportedException {
061        if (object == null) {
062            throw new IllegalArgumentException("Null 'object' argument.");
063        }
064        if (object instanceof PublicCloneable) {
065            PublicCloneable pc = (PublicCloneable) object;
066            return pc.clone();
067        }
068        else {
069            try {
070                Method method = object.getClass().getMethod("clone",
071                        (Class[]) null);
072                if (Modifier.isPublic(method.getModifiers())) {
073                    return method.invoke(object, (Object[]) null);
074                }
075            }
076            catch (NoSuchMethodException e) {
077                throw new CloneNotSupportedException("Object without clone() method is impossible.");
078            }
079            catch (IllegalAccessException e) {
080                throw new CloneNotSupportedException("Object.clone(): unable to call method.");
081            }
082            catch (InvocationTargetException e) {
083                throw new CloneNotSupportedException("Object without clone() method is impossible.");
084            }
085        }
086        throw new CloneNotSupportedException("Failed to clone.");
087    }
088
089    /**
090     * Returns a list containing cloned copies of the items in the source
091     * list.
092     * 
093     * @param source  the source list ({@code null} not permitted).
094     * 
095     * @return A new list. 
096     */
097    public static List<?> cloneList(List<?> source) {
098        Args.nullNotPermitted(source, "source");
099        List result = new ArrayList();
100        for (Object obj: source) {
101            if (obj == null) {
102                result.add(null);
103            } else if (obj.getClass() == String.class) {
104                result.add(obj);
105            } else {
106                try {
107                    result.add(ObjectUtils.clone(obj));
108                } catch (CloneNotSupportedException ex) {
109                    throw new RuntimeException(ex);
110                }
111            }
112        }
113        return result;
114    }
115    
116    /**
117     * Returns a new map that contains the same keys and cloned copied of the
118     * values.
119     * 
120     * @param source  the source map ({@code null} not permitted).
121     * 
122     * @return A new map. 
123     */
124    public static Map cloneMapValues(Map source) {
125        Args.nullNotPermitted(source, "source");
126        Map result = new HashMap();
127        for (Object key : source.keySet()) {
128            Object value = source.get(key);
129            if (value != null) {
130                try {
131                    result.put(key, ObjectUtils.clone(value));
132                } catch (CloneNotSupportedException ex) {
133                    throw new RuntimeException(ex);
134                }
135            } else {
136                result.put(key, null);
137            }
138        }
139        return result;
140    }
141   
142}