Is there a better way to clone values from an object without using reflection?

Viewed 103

Trying to efficiently check to see if a new copy of the object has any different fields, and if they do, update the local ones and make a note of it. If any of the fields change then I need to persist the object to the database. I don't want to make that call if I don't have to, hence the boolean.

I couldn't think of a better way to do this without using reflection, but I don't want to use reflection here because of the lack of compiler-backed safety (would have string references to field names), and not all the fields are the same type (I have some Java 8 Instant fields in there).

What I really want to avoid is the book-keeping of having to remember to add or subtract to/from the sync method when the fields are modified. Obviously subtracting is not a big deal because the method will break, but adding is scary if someone doesn't remember to update the new field.

public boolean syncWithFieldsFrom(User currentUser) {
    boolean doesUserNeedUpdating = false;
    if (!StringUtils.equals(email, currentUser.email)) {
        email = currentUser.email;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(firstName, currentUser.firstName)) {
        firstName = currentUser.firstName;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(lastName, currentUser.lastName)) {
        lastName = currentUser.lastName;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(fullName, currentUser.fullName)) {
        fullName = currentUser.fullName;
        doesUserNeedUpdating = true;
    }
    return doesUserNeedUpdating;
}
2 Answers

This may be a little overkill, but you can use lambdas to extract the fields and run a loop against them. I'll assume you have getters and setters for simplicity's sake.

private static class Field<T> {
    final Function<User, T> getter;
    final BiConsumer<User, T> setter;

    Field(Function<User, T> getter, BiConsumer<User, T> setter) {
        this.getter = getter;
        this.setter = setter;
    }

    boolean sync(User src, User dst) {
        T srcField = getter.apply(src);
        if (!Objects.equal(srcField, getter.apply(dst))) {
            setter.accept(dst, srcField);
            return true;
        }
        return false;
    }
}

private static final List<Field<?>> FIELDS = Arrays.asList(
        new Field<>(User::getEmail, User::setEmail),
        new Field<>(User::getFirstName, User::setFirstName),
        new Field<>(User::getLastName, User::setLastName),
        new Field<>(User::getFullName, User::setFullName));

public boolean syncWithFieldsFrom(User currentUser) {
    boolean updated = false;
    for (Field<?> f : FIELDS) {
        updated |= f.sync(currentUser, this);
    }
    return updated;
}

For deep cloning (clones the entire object hierarchy): commons-lang SerializationUtils - using serialization - if all classes are in your control and you can force implementing Serializable.

Java Deep Cloning Library - using reflection - in cases when the classes or the 
objects you want to clone are out of your control (a 3rd party library) and you can't 
make them implement Serializable, or in cases you don't want to implement Serializable.

For shallow cloning (clones only the first level properties): commons-beanutils BeanUtils - in most cases.

 Spring BeanUtils - if you are already using spring and hence have this utility on 
 the classpath.

 I deliberately omitted the "do-it-yourself" option - the API's above provide a good 
 control over what to and what not to clone (for example using transient, or String[] 
 ignoreProperties), so reinventing the wheel isn't preferred.

please refer below url. might help you to get some idea.

Java: recommended solution for deep cloning/copying an instance

Related