Search code examples
javajava-8functional-programmingjava-streamconsumer

Java 8 Consumer with additional parameters


I want to write a generic DTO updater, which updates some of it's properties. My object looks like this:

class Person {
    String firsName;
    String lastName;
    Integer age;
    setter/getter
}

I have an enum which defines which fields can be overridden:

enum OverriddenType {
    FIRST_NAME,
    LAST_NAME,
    AGE
}

Instead of doing a "hardcoded" setter like this...

public void override(Person person, Map<OverriddenType,Object> newValuesForProperties) {
    newValuesForProperties.forEach((type,value)) -> {
        if(type == OverriddenType.FIRST_NAME) {
            person.setFirstName((String)value);
        } else if(type == OverriddenType.LAST_NAME) {
            person.setLastName((String)value);
        } else if(type == OverriddenType.AGE) {
            person.setAge((Integer)value);
        }
    });
}

... I would like to use some Java 8 Function/Consumer features to define the setters in each enum. I tried something like this:

enum OverriddenType {
    FIRST_NAME(p -> p.setFirstName(???????)),  //don't know what to set here since the value is not here
    LAST_NAME(p -> p.setLastName(???????)),
    AGE(p -> p.setAge(???????));
    
    Consumer<Person> consumer;
    OverriddenType(Consumer<Person> consumer) {
        this.consumer = consumer;
    }
    public Consumer<Person> getConsumer();
}

But as you can see I cannot pass the dynamic value here. Also don't know how the logic would look like, but I would imagine something like this:

public void override(Person person, Map<OverriddenType,Object> newValuesForProperties) {
    newValuesForProperties.forEach((type,value)) -> 
        type.getConsumer().accept(person, value) // this doesn't exist, but I can imagine some additional parameter passing
    );
}

Can you provide me a solution for this? Can it work? I am afraid that the incoming value is a dynamic therefore it won't work for enums..


Solution

  • A setter method is a BiConsumer<T,U>, where T is the object instance, and U is the value.

    enum OverriddenType {
        FIRST_NAME((person, value) -> person.setFirsName((String) value)),
        LAST_NAME ((person, value) -> person.setLastName((String) value)),
        AGE       ((person, value) -> person.setAge((Integer) value));
    
        private final BiConsumer<Person, Object> setter;
    
        private OverriddenType(BiConsumer<Person, Object> setter) {
            this.setter = setter;
        }
    
        public void override(Person person, Object value) {
            this.setter.accept(person, value);
        }
    }
    
    public void override(Person person, Map<OverriddenType, Object> newValuesForProperties) {
        newValuesForProperties.forEach((type, value) -> type.override(person, value));
    }