修改值的Java框架/模式

修改值的Java框架/模式,java,java-8,expression,comparator,Java,Java 8,Expression,Comparator,我有一个客观的人 public class Person { private String name; private Integer age ; private String address; private String group; private String id; public Person(String name, Integer age, String address, String group, String id) {

我有一个客观的人

public class Person {
    private String name;
    private Integer age ;
    private String address;
    private String group;
    private String id;

    public Person(String name, Integer age, String address, String group, String id) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.group = group;
        this.id = id;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", address='" + address + '\'' +
                ", group='" + group + '\'' +
                ", id='" + id + '\'' +
                '}';
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public void setGroup(String group) {
        this.group = group;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public Integer getAge() {
        return age;
    }

    public String getAddress() {
        return address;
    }

    public String getGroup() {
        return group;
    }

    public String getId() {
        return id;
    }
}
元数据

public class MetaData {
    private String fieldName;
    private String comparator;
    private String fieldValue;
    private String newFieldName;
    private String newFieldValue;

    public MetaData(String fieldName, String comparator, String fieldValue, String newFieldName, String newFieldValue) {
        this.fieldName = fieldName;
        this.comparator = comparator;
        this.fieldValue = fieldValue;
        this.newFieldName = newFieldName;
        this.newFieldValue = newFieldValue;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getComparator() {
        return comparator;
    }

    public void setComparator(String comparator) {
        this.comparator = comparator;
    }

    public String getFieldValue() {
        return fieldValue;
    }

    public void setFieldValue(String fieldValue) {
        this.fieldValue = fieldValue;
    }

    public String getNewFieldName() {
        return newFieldName;
    }

    public void setNewFieldName(String newFieldName) {
        this.newFieldName = newFieldName;
    }

    public String getNewFieldValue() {
        return newFieldValue;
    }

    public void setNewFieldValue(String newFieldValue) {
        this.newFieldValue = newFieldValue;
    }
}
我得到一张名单。对于每个人,我都必须检查元数据(基于ID) 对于每个元数据,我必须查看要匹配的字段以及要重放的值

比如说

public class TestPersonModifier {

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("John", 22, "London", "BETA", "ABC"));
        personList.add(new Person("Mathew", 44, "Glasgow", "ALPHA", "XYZ"));

        List<MetaData> metaData = new ArrayList<>();

        metaData.add(new MetaData("name", "EQUALS", "John", "group", "SIGMA"));
        metaData.add(new MetaData("name", "EQUALS", "Mathew", "address", "Singapore"));

        //g
        personList.forEach(p -> {

            metaData.forEach(m -> {

                if (m.getFieldName().equals("name")) {
                    if (m.getComparator().equals("EQUALS")) {

                        if (p.getName().equals(m.getFieldValue())) {

                            if (m.getNewFieldName().equals("group")) {

                                System.out.println(p.getId() + "::The group value changed from " + p.getGroup() + " to " + m.getNewFieldValue());
                                p.setGroup(m.getNewFieldValue());
                            }
                            if (m.getNewFieldName().equals("address")) {
                                System.out.println(p.getId() + "::The address value changed from " + p.getAddress() + " to " + m.getNewFieldValue());

                                p.setGroup(m.getNewFieldValue());
                            }
                        }
                    }
                }
            });
        });

    }
}
公共类TestPersonModifier{
公共静态void main(字符串[]args){
List personList=新建ArrayList();
添加(新人(“约翰”,22岁,“伦敦”,“贝塔”,“ABC”);
添加(新人物(“马修”,44,“格拉斯哥”,“阿尔法”,“XYZ”);
列表元数据=新的ArrayList();
添加(新的元数据(“名称”、“相等”、“约翰”、“组”、“西格玛”);
添加(新的元数据(“名称”、“相等”、“马修”、“地址”、“新加坡”);
//g
personList.forEach(p->{
metaData.forEach(m->{
if(m.getFieldName().equals(“name”)){
if(m.getComparator().equals(“equals”)){
如果(p.getName().equals(m.getFieldValue())){
if(m.getNewFieldName().equals(“组”)){
System.out.println(p.getId()+”::组值从“+p.getGroup()+”更改为“+m.getNewFieldValue());
p、 setGroup(m.getNewFieldValue());
}
if(m.getNewFieldName().equals(“地址”)){
System.out.println(p.getId()+”::地址值从“+p.getAddress()+”更改为“+m.getNewFieldValue());
p、 setGroup(m.getNewFieldValue());
}
}
}
}
});
});
}
}
如上所述,这将是非常笨拙的,因为将有更多的比较器运算符和更多的字段


是否有我可以使用的表达式语言框架、JAva库或任何开源框架,使其成为通用解决方案

假设您对稍微不那么方便的形式感到满意

import com.google.common.base.Equivalence;
...
metaData.add(new MetaData(Person.class, Equivalence.equals(), "name", "John", "group", "SIGMA"));
最简单的基于Java的解决方案是将内省实例类添加到元数据中,参数化比较对象的方式(我在这里使用了Guava,您也可以使用纯Java 8
BiPredicate
)并指定属性名称

执行时,您可以利用
java.beans.Introspector#getBeanInfo()
来发现getter和setter名称(这是克服各种java bean怪癖的最安全的方法,例如布尔属性、完全大写的属性名等-我建议您更喜欢它,而不是基于半成品字符串替换的工具)并相应地调用它们

您可以使用

metaData.add(new MetaData<Person>(Equivalence.equals(), "name", "John", "group", "SIGMA"));
它更长,但类型更安全-您可以确保参数
John
SIGMA
与getter和setter类型相对应



要使用外部工具实现它,我建议查看mapstruct.org。Dozer也是可能的,但是在我们的项目中,由于基于生成代码的性能和原理,我们迁移到mapstruct,IMHO可以更好地了解转换过程中实际发生的情况。

主要有三个陷阱:

  • 首先,需要从字段名到getter/setter方法的某种映射,以便从POJO模型类访问字段值
  • 其次,各个字段的数据类型不同。因此,如果字段值未实现
    compariable
    ,则需要不同的比较器。您使用的类型实现了
    可比性
    ,因此您很好
  • 第三,Java不能以通用方式将内置值类型从
    对象转换为
    ;i、 getter方法的签名通常不匹配。您已经通过为诸如int之类的普通数据类型选择装箱类型来避免了这种情况
要使所有这些工作正常进行,您需要采取以下步骤:

  • 因此,在第一步中,您需要构建getter方法的存储库。例如,类似于
    HashMap map1
    。您可以通过
    map1.put(“name”,Person::getName)
    或通过反射显式添加所有getter来静态地实现这一点

  • 接下来,您需要为setter构建一个存储库。例如,类似于
    HashMap map2
    。同样,您可以使用反射或显式初始化。在后一种情况下,还有另一个陷阱,因为setter的泛型类型转换不再是协变的。这可以通过双重未选中强制转换来处理:

    map2.put("name", (BiConsumer)(BiConsumer<Person, String>)Person::setName);
    
    这将从getter(用作键)映射到匹配的setter方法。

    如果需要的话,我更喜欢这种方式,因为强类型值不太容易出错,而且重构更安全。

    投票决定关闭问题的人应该注意发表评论。
    map2.put("name", (BiConsumer)(BiConsumer<Person, String>)Person::setName);
    
    HashMap<Function<Person, Object>, BiConsumer<Person, Object>> map;