значение перезаписи в экземпляре сложного объекта с отражением java - PullRequest
0 голосов
/ 26 января 2020

Я пытаюсь написать метод, который изменяет одно вложенное значение объекта. Я думаю, что java отражения - лучший способ сделать это, но у меня проблемы с разработкой решения. Я пытаюсь сделать следующее:

package abcClass;

import overwrite.ValueOverwriter;

public class main {
    public static void main(String[] args) {
        A obj1 = new A();
        B bClass = new B();
        C cClass = new C();
        cClass.setStringValue("XXX");
        bClass.setcClass(cClass);
        obj1.setbClass(bClass);

        E obj2 = new E();
        D dClass = new D();
        dClass.setSomeInt(10);
        obj2.setdClass(dClass);

        A newObj1 = (A) ValueOverwriter.overwiteValue(obj1, "bClass.cClass.someString", "YYY");
        E newObj2 = (E) ValueOverwriter.overwiteValue(obj2, "dClass.someInt", "20");
    }
}

Класс с методом, который я пытаюсь реализовать:

package overwrite;

import abcClass.Abcdef;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

public class ValueOverwriter {

    //        String path is path to value that is to be changed like: " aClass.bClass.cClass.stringValue"
    public static Abcdef overwiteValue(Abcdef obj, String path, String newValue) {
        List<String> propertyAddress = Arrays.asList(path.split("\\."));
        StringBuilder methodToInvokeName = new StringBuilder("obj");

        for (int i = 0; i < propertyAddress.size() - 1; i++) {
            methodToInvokeName.append("." + returnMethodName("get", propertyAddress.get(i)));
        }
        String setterMethodName = methodToInvokeName.toString() + "." + returnMethodName("set", propertyAddress.get(propertyAddress.size() - 1));
        String getterMethodName = methodToInvokeName.toString() + "." + returnMethodName("get", propertyAddress.get(propertyAddress.size() - 1));

        try {
            Method setterMethod = obj.getClass().getMethod(setterMethodName);
            setterMethod.invoke(obj, newValue);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }


    private static String returnMethodName(String method, String field) {
        return method + field.substring(0, 1)
                .toUpperCase() + field.substring(1);
    }
}

И несколько простых классов:

Abcdef интерфейс:

    package abcClass;

    public interface Abcdef {
    }

A класс:

    package abcClass;

    public class A implements Abcdef{
        private B bClass;

        public B getbClass() {
            return bClass;
        }

        public void setbClass(B bClass) {
            this.bClass = bClass;
        }
    }

B класс:

package abcClass;

public class B{
    private C cClass;

    public C getcClass() {
        return cClass;
    }

    public void setcClass(C cClass) {
        this.cClass = cClass;
    }
}

C класс:

package abcClass;

public class C{
    private String stringValue = "some String";

    public String getStringValue() {
        return stringValue;
    }

    public void setStringValue(String stringValue) {
        this.stringValue = stringValue;
    }
}

D класс:

package abcClass;

public class D {
    private int someInt = 10;

    public int getSomeInt() {
        return someInt;
    }

    public void setSomeInt(int someInt) {
        this.someInt = someInt;
    }
}

E класс:

package abcClass;

public class E implements Abcdef{
        private D dClass;

    public D getdClass() {
        return dClass;
    }

    public void setdClass(D bClass) {
        this.dClass = bClass;
    }
}

Мне нужно, чтобы этот метод мог обрабатывать различные типы значений, может быть, я должен сделать для этого интерфейс с OverRider?

Теперь я получаю исключение:

"C:\Program Files\Java\jdk1.8.0_191\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\lib\idea_rt.jar=64108:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2019.3.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_191\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_191\jre\lib\rt.jar;C:\Users\karolina.kosmala\batchWorkspace\spring-batch-master\field_overwrite\target\classes;C:\Users\karolina.kosmala\.m2\repository\org\springframework\spring-beans\5.2.3.RELEASE\spring-beans-5.2.3.RELEASE.jar;C:\Users\karolina.kosmala\.m2\repository\org\springframework\spring-core\5.2.3.RELEASE\spring-core-5.2.3.RELEASE.jar;C:\Users\karolina.kosmala\.m2\repository\org\springframework\spring-jcl\5.2.3.RELEASE\spring-jcl-5.2.3.RELEASE.jar" abcClass.main
java.lang.NoSuchMethodException: abcClass.A.obj.getBClass.getCClass.setSomeString()
    at java.lang.Class.getMethod(Class.java:1786)
    at overwrite.ValueOverwriter.overwiteValue(ValueOverwriter.java:25)
    at abcClass.main.main(main.java:19)
java.lang.NoSuchMethodException: abcClass.E.obj.getDClass.setSomeInt()
    at java.lang.Class.getMethod(Class.java:1786)
    at overwrite.ValueOverwriter.overwiteValue(ValueOverwriter.java:25)
    at abcClass.main.main(main.java:20)

Process finished with exit code 0

1 Ответ

0 голосов
/ 26 января 2020

abcClass.A.obj.getBClass.getCClass.setSomeString() показывает, что вам не хватает паратезов для методов получения. Это верно? Это должна быть сгенерированная строка, я думаю: abcClass.A.obj.getBClass().getCClass().setSomeString().

Может потребоваться это изменение на returnMethodName():

private static String returnMethodName(String method, String field) {
    return method + field.substring(0, 1)
            .toUpperCase() + field.substring(1) + "()"; //parantheses
}

Однако, все сказано и сделано, я не уверен если подход, который вы выбрали, хорош - тот, который использует рефлексию. Для таких целей уже существует Java API Beans . Вы проверили это?

...