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

com.phloc.commons.lang.CloneHelper Maven / Gradle / Ivy

There is a newer version: 5.0.0
Show newest version
/**
 * Copyright (C) 2006-2014 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * Licensed 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 com.phloc.commons.lang;

import java.lang.reflect.Constructor;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phloc.commons.ICloneable;
import com.phloc.commons.annotations.PresentForCodeCoverage;

/**
 * Helper class for cloning objects.
 * 
 * @author Philip Helger
 */
@Immutable
public final class CloneHelper
{
  private static final Logger s_aLogger = LoggerFactory.getLogger (CloneHelper.class);

  @PresentForCodeCoverage
  @SuppressWarnings ("unused")
  private static final CloneHelper s_aInstance = new CloneHelper ();

  private CloneHelper ()
  {}

  @Nullable
  private static  DATATYPE _getGenericClone (@Nonnull final DATATYPE aObject)
  {
    // 1. check ICloneable interface
    if (aObject instanceof ICloneable )
      return GenericReflection.> uncheckedCast (aObject).getClone ();

    try
    {
      try
      {
        // 2. find Object.clone method
        return GenericReflection. invokeMethod (aObject, "clone");
      }
      catch (final Exception ex)
      {
        s_aLogger.warn ("Failed to invoke clone on " + aObject.getClass ().getName ());
      }

      // 3. find copy-constructor
      final Constructor  aCtor = GenericReflection.findConstructor (aObject, aObject.getClass ());
      if (aCtor != null)
        return aCtor.newInstance (aObject);
    }
    catch (final IllegalAccessException ex)
    {
      s_aLogger.error ("Failed to clone object of type '" +
                       aObject.getClass ().getName () +
                       "' because it has neither a (visible) clone method nor a copy constructor or the methods are invisible.");
    }
    catch (final NoSuchMethodException ex)
    {
      s_aLogger.error ("Failed to clone object of type '" +
                       aObject.getClass ().getName () +
                       "' because it has neither a clone method nor a (visible) copy constructor or the methods are invisible.");
    }
    catch (final Exception ex)
    {
      s_aLogger.error ("Failed to clone object of type '" +
                       aObject.getClass ().getName () +
                       "' because it has neither a (visible) clone method nor a copy constructor.", ex);
    }
    return null;
  }

  /**
   * Get a clone (= deep copy) of the passed value. The following things are
   * tried for cloning:
   * 
    *
  1. If the object is immutable, it is returned as is (if it is a primitive * type or marked with the {@link Immutable} annotation.
  2. *
  3. If the object implements {@link ICloneable} it is invoked.
  4. *
  5. If the object implements {@link Cloneable} it is invoked.
  6. *
  7. If a copy constructor (a constructor taking one argument of the same * class as it declares)
  8. *
* If all tries fail, null is returned. * * @param aObject * The object to be copied. * @return null if the passed value is null or if no * cloning could be performed. */ @Nullable public static DATATYPE getClonedValue (@Nullable final DATATYPE aObject) { // null -> null if (aObject == null) return null; final Class aClass = aObject.getClass (); // special handling for immutable objects without equals or clone if (ClassHelper.isPrimitiveWrapperType (aClass) || aObject instanceof String || aClass.getAnnotation (Immutable.class) != null) return aObject; // generic clone return _getGenericClone (aObject); } /** * Get a clone (= deep copy) of the passed value for all objects implementing * {@link ICloneable}. * * @param aObject * The object to be copied. May be null. * @return null if the passed value is null or a * clone of the object. */ @Nullable public static > DATATYPE getCloneIfNotNull (@Nullable final DATATYPE aObject) { // null -> null if (aObject == null) return null; return aObject.getClone (); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy