com.foilen.smalltools.reflection.BeanPropertiesCopierTools.java Source code

Java tutorial

Introduction

Here is the source code for com.foilen.smalltools.reflection.BeanPropertiesCopierTools.java

Source

/*
Java Libraries https://github.com/foilen/java-libraries
Copyright (c) 2015-2018 Foilen (http://foilen.com)
    
The MIT License
http://opensource.org/licenses/MIT
    
 */
package com.foilen.smalltools.reflection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.foilen.smalltools.exception.SmallToolsException;
import com.foilen.smalltools.tools.AssertTools;

/**
 * Helps copying properties from one bean to another bean. It can also update a collection's items on place. See {@link #updateCollection(String)}.
 *
 * <pre>
 * Employee employee = ...;
 * EmployeeTo employeeTo = new EmployeeTo();
 *
 * BeanPropertiesCopierTools copierTools = new BeanPropertiesCopierTools(employee, employeeTo);
 *
 * // Same property name
 * copierTools.copyProperty("firstName");
 * copierTools.copyProperty("LastName");
 *
 * //
 * copierTools.copyProperty("LastName");
 *
 * // Different property name
 * copierTools.copyProperty("address", "homeAddress");
 * </pre>
 *
 * <pre>
 * Dependencies:
 * compile 'org.apache.commons:commons-lang3:3.6'
 * compile 'org.slf4j:slf4j-api:1.7.25'
 * compile 'org.springframework:spring-orm:4.3.11.RELEASE'
 * </pre>
 */
public class BeanPropertiesCopierTools {

    private BeanWrapper sourceWrapper;
    private BeanWrapper destinationWrapper;

    /**
     * Provide the bean wrappers.
     *
     * @param sourceWrapper
     *            the source
     * @param destinationWrapper
     *            the destination
     */
    public BeanPropertiesCopierTools(BeanWrapper sourceWrapper, BeanWrapper destinationWrapper) {
        AssertTools.assertNotNull(sourceWrapper, "The sourceWrapper cannot be null");
        AssertTools.assertNotNull(sourceWrapper.getWrappedInstance(), "The source cannot be null");
        AssertTools.assertNotNull(destinationWrapper, "The destinationWrapper cannot be null");
        AssertTools.assertNotNull(destinationWrapper.getWrappedInstance(), "The destination cannot be null");

        this.sourceWrapper = sourceWrapper;
        this.destinationWrapper = destinationWrapper;
    }

    /**
     * Provide the source object and the destination class to instantiate. You can then retrieve the destination with {@link #getDestination()}.
     *
     * @param source
     *            the source
     * @param destinationClass
     *            the class to instantiate for the destination
     */
    public BeanPropertiesCopierTools(Object source, Class<?> destinationClass) {
        AssertTools.assertNotNull(destinationClass, "The destinationClass cannot be null");
        Object destination = ReflectionTools.instantiate(destinationClass);
        init(source, destination);
    }

    /**
     * Provide the objects.
     *
     * @param source
     *            the source
     * @param destination
     *            the destination
     */
    public BeanPropertiesCopierTools(Object source, Object destination) {
        init(source, destination);
    }

    /**
     * Copy the property.
     *
     * @param propertyName
     *            the name of the source's and destination's property
     * @return this
     */
    public BeanPropertiesCopierTools copyProperty(String propertyName) {
        return copyProperty(propertyName, propertyName);
    }

    /**
     * Copy the property.
     *
     * @param sourcePropertyName
     *            the name of the source's property
     * @param destinationPropertyName
     *            the name of the destination's property
     * @return this
     */
    public BeanPropertiesCopierTools copyProperty(String sourcePropertyName, String destinationPropertyName) {
        Object value = sourceWrapper.getPropertyValue(sourcePropertyName);
        destinationWrapper.setPropertyValue(destinationPropertyName, value);
        return this;
    }

    public Object getDestination() {
        return destinationWrapper.getWrappedInstance();
    }

    public Object getSource() {
        return sourceWrapper.getWrappedInstance();
    }

    /**
     * Get the property's value from the source.
     *
     * @param <T>
     *            the return type
     * @param propertyName
     *            the name of the property
     * @param type
     *            the type to return
     * @return the value
     */
    @SuppressWarnings("unchecked")
    public <T> T getSourceProperty(String propertyName, Class<T> type) {
        Object value = sourceWrapper.getPropertyValue(propertyName);
        if (value == null) {
            return null;
        }
        return (T) value;
    }

    private void init(Object source, Object destination) {
        AssertTools.assertNotNull(source, "The source cannot be null");
        AssertTools.assertNotNull(destination, "The destination cannot be null");
        this.sourceWrapper = new BeanWrapperImpl(source);
        this.destinationWrapper = new BeanWrapperImpl(destination);
    }

    /**
     * Set a value on the destination.
     *
     * @param propertyName
     *            the name of the property
     * @param value
     *            the value to set
     */
    public void setDestinationProperty(String propertyName, Object value) {
        destinationWrapper.setPropertyValue(propertyName, value);
    }

    @SuppressWarnings("unchecked")
    public BeanPropertiesCopierTools updateCollection(Collection<?> sourceCollection,
            String destinationPropertyName) {
        // Get or create the destination
        Object destinationObject = destinationWrapper.getPropertyValue(destinationPropertyName);
        boolean setDestination = destinationObject == null;
        Set<Object> destinationSet = null;
        List<Object> destinationList = null;
        Class<?> destinationPropertyType;
        if (setDestination) {
            destinationPropertyType = destinationWrapper.getPropertyType(destinationPropertyName);
            if (destinationPropertyType == List.class) {
                destinationList = new ArrayList<>();
                destinationObject = destinationList;
            }
            if (destinationPropertyType == Set.class) {
                destinationSet = new HashSet<>();
                destinationObject = destinationSet;
            }
        } else {
            destinationPropertyType = destinationObject.getClass();

            if (destinationObject instanceof List) {
                destinationList = (List<Object>) destinationObject;
            }
            if (destinationObject instanceof Set) {
                destinationSet = (Set<Object>) destinationObject;
            }
        }

        // Check we have a valid destination
        if (destinationList == null && destinationSet == null) {
            throw new SmallToolsException(
                    "The destination must be a List or a Set. Is a " + destinationPropertyType.getName());
        }

        // Get the source
        if (sourceCollection == null) {
            sourceCollection = Collections.emptyList();
        }

        // Copy depending on the type
        if (destinationList != null) {
            int destPos = 0;
            for (Object next : sourceCollection) {
                // Skip or insert
                if (destPos >= destinationList.size() || !destinationList.get(destPos).equals(next)) {
                    destinationList.add(destPos, next);
                }

                ++destPos;
            }
            // Remove extra
            while (destPos < destinationList.size()) {
                destinationList.remove(destPos);
            }

        }
        if (destinationSet != null) {
            // Remove
            Iterator<?> destinationIt = destinationSet.iterator();
            while (destinationIt.hasNext()) {
                Object next = destinationIt.next();
                if (!sourceCollection.contains(next)) {
                    destinationIt.remove();
                }
            }

            // Add
            for (Object next : sourceCollection) {
                if (!destinationSet.contains(next)) {
                    destinationSet.add(next);
                }
            }
        }

        // Set the destination
        if (setDestination) {
            destinationWrapper.setPropertyValue(destinationPropertyName, destinationObject);
        }

        return this;
    }

    /**
     * Take or create the collection on the destination and update with the source. This is useful when the destination collection could be a wrapper of the collection to keep track of it (e.g when
     * using Hibernate)
     *
     * @param propertyName
     *            the name of the source's and destination's property
     * @return this
     */
    public BeanPropertiesCopierTools updateCollection(String propertyName) {
        return updateCollection(propertyName, propertyName);
    }

    /**
     * Take or create the collection on the destination and update with the source. This is useful when the destination collection could be a wrapper of the collection to keep track of it (e.g when
     * using Hibernate)
     *
     * @param sourcePropertyName
     *            the name of the source's property
     * @param destinationPropertyName
     *            the name of the destination's property
     * @return this
     */
    public BeanPropertiesCopierTools updateCollection(String sourcePropertyName, String destinationPropertyName) {
        Collection<?> sourceCollection = (Collection<?>) sourceWrapper.getPropertyValue(sourcePropertyName);
        return updateCollection(sourceCollection, destinationPropertyName);
    }
}