简体   繁体   中英

Java class method with Class and Field as parameters

How can i create a method that accepts Class and Field as parameters? Like this:

List<SomeClassEntity> list = ...;
// Service to make useful things around a list of objects
UsefulThingsService<SomeClassEntity> usefulThingsService = new UsefulThingsService<>();
// Maybe invoke like this. Did't work 
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, SomeClassEntity::getFieldOne);
// or like this. Will cause delayed runtime erros
usefulThingsService.makeUsefulThings(list, SomeClassEntity.class, "fieldTwo");



public class SomeClassEntity {

    Integer fieldOne = 10;
    Double fieldThree = 0.123;

    public Integer getFieldOne() {
        return fieldOne;
    }
    public void setFieldOne(Integer fieldOne) {
        this.fieldOne = fieldOne;
    }
    public Double getFieldThree() {
        return fieldThree;
    }
    public void setFieldThree(Double fieldThree) {
        this.fieldThree = fieldThree;
    }
}


public class UsefulThingsService<T> {
    public void makeUsefulThings(Class<T> someClassBClass, String fieldName) {
        // there is some code
    }
}

Want to have correct references on compile stage, not at runtime.

Update: I need code that would look more convenient than this:

    Field fieldOne = null;
    try {
        fieldOne = SomeClassEntity.class.getDeclaredField("fieldOne");
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    }
    usefulThingsService.makeUsefulThings(SomeClassEntity.class, fieldOne);

I apologize for the next clarification.
Update 2:
- The service compares the list with the previous list, reveals only the changed fields of objects (list items) and updates these fields in the objects in the original list.
- Currently i use annotation on entity's field that is actually ID of the entity and that ID is used to detect identically entities (old and new) when i need to update field of entity in source list.
- Service detect annotated field and use it for next update process.
- I want to refuse to use annotations and provide an Field directly in constructor of service. Or use something other that could establish a relationship between class and field on compilation stage.

Assuming that you want field access because you want to get and set the value, you'd need two functions:

public class UsefulThingsService<T> {
    public <V> void makeUsefulThings(List<T> list, Function<T,V> get, BiConsumer<T,V> set) {
        for(T object: list) {
            V v = get.apply(object);
            // there is some code
            set.accept(object, v);
        }
    }
}

and

usefulThingsService.makeUsefulThings(
    list, SomeClassEntity::getFieldOne, SomeClassEntity::setFieldOne);

usefulThingsService.makeUsefulThings(
    list, SomeClassEntity::getFieldThree, SomeClassEntity::setFieldThree);

There are, however, some things open. Eg, how is this service supposed to do something useful with the field resp. property, without even knowing its actual type. In your example, both are subtypes of Number , so you could declare <V extends Number> , so the method knows how to extract numerical values, however, constructing an appropriate result object would require specifying another function argument.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM