Инициализировать POJO динамически из другого метода

Допустим, у меня есть этот набор классов POJO, которые реализуют интерфейс, но здесь нет общих атрибутов.

public interface MainIfc {}

class Ifc1 implements MainIfc {
    private String a1;
    public String getA1() {
        return a1;
    }
    public void setA1(String a1) {
        this.a1 = a1;
    }
}

class Ifc2 implements MainIfc {
    private String x1;
    private String x2;
    public String getX1() {
        return x1;
    }
    public void setX1(String x1) {
        this.x1 = x1;
    }
    public String getX2() {
        return x2;
    }
    public void setX2(String x2) {
        this.x2 = x2;
    }
}

И в сочетании с этими классами POJO у меня есть несколько методов, которые я могу использовать для получения типа возвращаемого POJO на основе другого значения и фактического POJO со значениями.

public class GetIfc {
    public Class getIfcType(int code) {
        if (code==1)
            return Ifc1.class;
        else
            return Ifc2.class;
    }
    public MainIfc getIfc(int code) {
        if (code==1) {
            Ifc1 thisIfc = new Ifc1();
            thisIfc.setA1("Ifc1");
            return thisIfc;
        } else {
            Ifc2 thisIfc = new Ifc2();
            thisIfc.setX1("Ifc2");
            thisIfc.setX2("Ifc2");
            return thisIfc;
        }
    }
}

Есть ли способ, с помощью которого я могу безопасно прочитать конкретный POJO в своем коде и использовать геттеры/сеттеры? Я рассмотрел довольно много вопросов, которые дают ответы на основе Reflection, но это не работает для меня. Геттеры/сеттеры не видны, и когда я вызываю .getClass() для возвращаемого объекта, я вижу, что это интерфейс MainIfc.

Проблема дизайна, которую я пытаюсь решить, относится к инфраструктуре автоматизации REST API, которую я пытаюсь разработать. По сути, у меня есть парсер ClientResponse, который отправит обратно POJO, который я ищу. Но я не хочу, чтобы люди, пишущие тестовые примеры, беспокоились о типе возвращаемого POJO. Итак, я подумал, что могу вернуть тип и созданный экземпляр POJO, чтобы получить значения, но меня беспокоит, как добиться этого динамически.


person mbsingh    schedule 26.08.2016    source источник
comment
Мне непонятно, что вы пытаетесь сделать. Я чувствую желание вести себя как Боб, но могу ошибаться.   -  person Fildor    schedule 26.08.2016
comment
когда я вызываю .getClass() для возвращаемого объекта, я вижу, что это интерфейс MainIfc. Я считаю, что трудно поверить. Пожалуйста, добавьте немного кода, который показывает это поведение. Также, пожалуйста, уточните: вы ищете какой-либо способ заставить его работать или вас интересует правильный способ OO для решения этой проблемы?   -  person Cephalopod    schedule 26.08.2016
comment
Вы можете добавить в свои классы метод, который возвращает все (общедоступные) поля в виде списка объектов Field. Вероятно, член MainIfc. Тем не менее, я чувствую, что это X-Y-вопрос. Какую проблему вы пытаетесь решить?   -  person Fildor    schedule 26.08.2016
comment
Я попробовал упомянутый здесь ответ - stackoverflow.com/questions/ 8479943/. Я обновил свой вопрос, указав точную проблему дизайна, которую я пытаюсь решить.   -  person mbsingh    schedule 26.08.2016
comment
Можете ли вы привести пример того, как вы собираетесь использовать это?   -  person talex    schedule 07.09.2016


Ответы (4)


Нужны ли потребителям MainIfc POJO или только данные внутри них?

Дизайн может быть чище, если MainIfc объявит один или два метода, предоставляющих данные, которые потребуются его потребителям. Затем ваши POJO могут реализовывать методы, объявленные интерфейсом MainIfc. Или вы можете создать класс-оболочку для каждого POJO, который согласует его с интерфейсом, если вы хотите, чтобы проблемы реализации вашего интерфейса были отделены от ваших POJO.

В идеале интерфейс должен предоставлять несколько методов, которые можно использовать для взаимодействия с любым классом, который его реализует, и никому не нужно знать о базовых POJO/реализации.

public interface MainIfc {
  public Hash getAttributes();
  public setAttributes(Hash attributes);
}

class Ifc1 implements MainIfc {
  private String a1;
  public String getA1() {
    return a1;
  }
  public void setA1(String a1) {
    this.a1 = a1;
  }
  public Hash getAttributes() {
    // return a hash with data that MainIfc consumer will need from this POJO
  }
  public setAttributes(Hash attributes) {
    // copy hash attributes to corresponding POJO fields
  }
}

class Ifc2 implements MainIfc {
  private String x1;
  private String x2;
  public String getX1() {
    return x1;
  }
  public void setX1(String x1) {
    this.x1 = x1;
  }
  public String getX2() {
    return x2;
  }
  public void setX2(String x2) {
    this.x2 = x2;
  }
  public Hash getAttributes() {
    // return a hash with data that MainIfc consumer will need from this POJO
  }
  public setAttributes(Hash attributes) {
    // copy hash attributes to corresponding POJO fields
  }
}
person Ken Hill    schedule 08.09.2016

Попробуйте этот код. Возможно, это вернет все методы класса, а также методы, унаследованные от класса Object.

   public static void main(String[] args) throws ClassNotFoundException {
        GetIfc getIfc=new GetIfc();
        MainIfc clas1s=getIfc.getIfc(1);
        Class class1= clas1s.getClass();
        System.out.println(class1);
        Method[] mem= class1.getMethods();
        for(Method mmm : mem) {
            System.out.println(mmm.getName());
        }
    }
person Bhupender Sharma    schedule 26.08.2016
comment
Я обновил свой вопрос для точного требования и проблемы проектирования, с которой я столкнулся. Пожалуйста, порекомендуйте. - person mbsingh; 29.08.2016

Мне кажется, вы пытаетесь сделать что-то довольно нелогичное. Шаблон стратегии или абстрактная фабрика могут подойти для ваших требований, но на данный момент я не совсем понимаю, чего именно вы пытаетесь достичь. Вы определенно не должны условно приводить и вызывать разные методы для этих классов. Если вы действительно хотите продолжить этот путь, я бы предложил пойти с отражением, если это не вариант, и вам нужна гибкость, я бы, вероятно, выбрал какую-то карту.

Но я бы определенно переосмыслил ваш дизайн, если это вообще возможно.

person dieterh    schedule 07.09.2016

Попробуйте этот фрагмент кода, я не знаю, полностью ли я понимаю ваше требование, но, исходя из моего понимания, я думаю, что приведенный ниже код поможет.

public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException,
    IllegalArgumentException, InvocationTargetException {
GetIfc getIfc = new GetIfc();
MainIfc clas1s = getIfc.getIfc(1);
Field[] fields = clas1s.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
    Field field = fields[i];
    Class fieldClasslasse = field.getType();

    if (field.getModifiers() == Modifier.PRIVATE) {

    // you need to check fieldClass, if it is boolean then initials of the getter could be 'is' instead of 'get'
    String methodNameGet = "get" + Character.toUpperCase(field.getName().charAt(0))
        + field.getName().substring(1);
    String methodNameSet = "set" + Character.toUpperCase(field.getName().charAt(0))
        + field.getName().substring(1);

    Method methodGet = clas1s.getClass().getDeclaredMethod(methodNameGet, null);
    Object value =  methodGet.invoke(clas1s, null);
    if (value != null && value instanceof String) {
        String valueUpper = ((String)value).toUpperCase();

        Class[] cArg = new Class[1];
        cArg[0] = String.class;
        Method methodSet = clas1s.getClass().getDeclaredMethod(methodNameSet, cArg);
        Object[] var = new Object[1];
        var[0] = valueUpper;
        methodSet.invoke((Object) clas1s, var);
    }

    }
}

}

Небольшое объяснение приведенного выше кода: Получите все поля объекта и проверьте, является ли оно частным свойством, если да, то он должен иметь общедоступный геттер и сеттер, угадать их имя на основе соглашения Java, вызвать геттер, получить значение, проверьте, является ли это экземпляром класса String, если да, сделайте его ПРОПИСНЫМ, затем вызовите установщик, чтобы установить новое значение.

person Nikhil    schedule 07.09.2016