# Class MetadataCopier

Object
MetadataCopier

public class MetadataCopier extends Object
Performs deep copies of given metadata instances. This class performs copies, not clones, since the copied metadata may not be instances of the same class as the original metadata. This class performs the following steps:

- Get the implementation class of the given metadata instance.
- Create a new instance of the implementation class using the public no-argument constructor.
- Invoke all non-deprecated setter methods on the new instance with the corresponding value from the given metadata.
- If any of the values copied in above step is itself a metadata, recursively performs deep copy on those metadata instances too.

This copier may be used for converting metadata tree of unknown implementations (for example the result of a call to `MetadataSource​.lookup(Class, String)`) into instances of `AbstractMetadata`. The copier may also be used if a modifiable metadata is desired after the original metadata has been made final.

Default implementation copies all copiable children, regardless their state. Static factory methods allow to construct some variants, for example skipping the copy of unmodifiable metadata instances since they can be safely shared.

This class supports cyclic graphs in the metadata tree. It may return the given `metadata` object directly if the implementation class does not provide any setter method.

This class is not thread-safe. In multi-threads environment, each thread should use its own `MetadataCopier` instance.

Since:
  0.8

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `MetadataCopier(MetadataStandard standard)`
  Creates a new metadata copier.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `<T> T`
  `copy(Class<T> type, T metadata)`
  Performs a potentially deep copy of the given metadata object.
  `Object`
  `copy(Object metadata)`
  Performs a potentially deep copy of a metadata object of unknown type.
  `protected Object`
  `copyRecursively(Class<?> type, Object metadata)`
  Performs the actual copy operation on a single metadata instance.
  `static MetadataCopier`
  `forModifiable(MetadataStandard standard)`
  Creates a new metadata copier which avoid copying unmodifiable metadata.
  `protected List<String>`
  `getCurrentPropertyPath()`
  Returns the path to the currently copied property.

  ### Methods inherited from class Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Constructor Details

  - ### MetadataCopier

    public MetadataCopier(MetadataStandard standard)
    Creates a new metadata copier.
    Parameters:
      `standard` - the default metadata standard to use for object that are not `AbstractMetadata` instances, or `null` if none.

- ## Method Details

  - ### forModifiable

    public static MetadataCopier forModifiable(MetadataStandard standard)
    Creates a new metadata copier which avoid copying unmodifiable metadata. More specifically, any `ModifiableMetadata` instance in final state will be kept as-is; those final metadata will not be copied since they can be safely shared.
    Parameters:
      `standard` - the default metadata standard to use for object that are not `AbstractMetadata` instances, or `null` if none.
    Returns:
      a metadata copier which skip the copy of unmodifiable metadata.
    Since:
      1.0

  - ### copy

    public Object copy(Object metadata)
    Performs a potentially deep copy of a metadata object of unknown type. The return value does not need to be of the same class as the argument.
    Parameters:
      `metadata` - the metadata object to copy, or `null`.
    Returns:
      a copy of the given metadata object, or `null` if the given argument is `null`.
    Throws:
      `UnsupportedOperationException` - if there is no implementation class for a metadata to copy, or an implementation class does not provide a public default constructor.

  - ### copy

    public <T> T copy(Class<T> type, T metadata)
    Performs a potentially deep copy of the given metadata object. This method is preferred to `copy(Object)` when the type is known. The specified type should be an interface, not an implementation (for example `Metadata`, not `DefaultMetadata`).
    Type Parameters:
      `T` - compile-time value of the `type` argument.
    Parameters:
      `type` - the interface of the metadata object to copy.
      `metadata` - the metadata object to copy, or `null`.
    Returns:
      a copy of the given metadata object, or `null` if the given argument is `null`.
    Throws:
      `IllegalArgumentException` - if `type` is an implementation class instead of interface.
      `UnsupportedOperationException` - if there is no implementation class for a metadata to copy, or an implementation class does not provide a public default constructor.

  - ### copyRecursively

    protected Object copyRecursively(Class<?> type, Object metadata)
    Performs the actual copy operation on a single metadata instance. This method is invoked by all public `copy(…)` method with the root `metadata` object in argument, then is invoked recursively for all properties in that metadata object. If a metadata property is a collection, then this method is invoked for each element in the collection.

    Subclasses can override this method if they need some control on the copy process.

    Parameters:
      `type` - the interface of the metadata object to copy, or `null` if unspecified.
      `metadata` - the metadata object to copy, or `null`.
    Returns:
      a copy of the given metadata object, or `null` if the given argument is `null`.
    Throws:
      `UnsupportedOperationException` - if there is no implementation class for a metadata to copy, or an implementation class does not provide a public default constructor.

  - ### getCurrentPropertyPath

    protected List<String> getCurrentPropertyPath()
    Returns the path to the currently copied property. Each element in the list is the UML identifier of a property. Element at index 0 is the name of the property of the root metadata object being copied. Element at index 1 is the name of a property which is a children of above property, etc.

    The returned list is valid only during `copyRecursively(Class, Object)` method execution. The content of this list become undetermined after the `copyRecursively` method returned.

    Returns:
      the path to the currently copied property.
    Since:
      1.0