001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027package org.apache.http.client.utils;
028
029import java.lang.reflect.InvocationTargetException;
030import java.lang.reflect.Method;
031
032/**
033 * A collection of utilities to workaround limitations of Java clone framework.
034 *
035 * @since 4.0
036 */
037public class CloneUtils {
038
039    /**
040     * @since 4.3
041     */
042    public static <T> T cloneObject(final T obj) throws CloneNotSupportedException {
043        if (obj == null) {
044            return null;
045        }
046        if (obj instanceof Cloneable) {
047            final Class<?> clazz = obj.getClass ();
048            final Method m;
049            try {
050                m = clazz.getMethod("clone", (Class<?>[]) null);
051            } catch (final NoSuchMethodException ex) {
052                throw new NoSuchMethodError(ex.getMessage());
053            }
054            try {
055                @SuppressWarnings("unchecked") // OK because clone() preserves the class
056                final T result = (T) m.invoke(obj, (Object []) null);
057                return result;
058            } catch (final InvocationTargetException ex) {
059                final Throwable cause = ex.getCause();
060                if (cause instanceof CloneNotSupportedException) {
061                    throw ((CloneNotSupportedException) cause);
062                } else {
063                    throw new Error("Unexpected exception", cause);
064                }
065            } catch (final IllegalAccessException ex) {
066                throw new IllegalAccessError(ex.getMessage());
067            }
068        } else {
069            throw new CloneNotSupportedException();
070        }
071    }
072
073    public static Object clone(final Object obj) throws CloneNotSupportedException {
074        return cloneObject(obj);
075    }
076
077    /**
078     * This class should not be instantiated.
079     */
080    private CloneUtils() {
081    }
082
083}