Копирование полей между аналогичными классами в java
У меня есть пары классов, где поля одного являются подмножеством полей другого, а геттеры классов надмножеств все предположительно называются (getFoo()
). Есть ли способ эффективно копировать все общие поля из класса superset в класс подмножества или, по крайней мере, автоматически генерировать код для этого.
Я должен отметить, что:
- По разным причинам я не могу редактировать классы надмножеств, а также не могу использовать их во всем, чтобы избежать копирования данных.
- Я могу потенциально создать новые методы в классах подмножеств, но я не могу изменить их поля.
- У нас есть десятки этих пар, и некоторые из классов имеют много полей, поэтому делать это вручную громоздко, если не сказать больше.
- Сотрудник разработал метод создания универсального метода копирования, который использует java-отражение для принятия любых двух классов, итерации по полям как строки, выполняет строчную манипуляцию, чтобы определить имя получателя, а затем выполнить его для автоматического набора поле в классе подмножества. Это ужасно, но, похоже, это работает. Я действительно надеюсь, что там будет лучший способ.
Изменить: некоторый простой код по запросу
public class SuperClass {
private int foo;
private int bar;
private float bat;
public int getFoo() { return foo; }
public int getBar() { return bar; }
public float getBat() { return bat; }
}
public class SubClass {
private int foo;
private float bat;
}
//wanted
public static copySuperFieldsToSubMethod(Object super, Object sub) { ??? }
// also acceptable would be some way to autogenerate all the assignment
// functions needed
Ответы
Ответ 1
Для этого можно использовать класс BeanUtils
в Spring Framework. Возможно, это не обязательно будет более эффективным, чем ваш метод, основанный на отражении, но он, безусловно, прост в кодировании. Я ожидаю, что все, что вам нужно сделать, это:
BeanUtils.copyProperties(source, target);
Javadoc для этого метода доступен в http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/beans/BeanUtils.html#copyProperties(java.lang.Object,%20java.lang.Object)
Если это не подходит, вы можете также рассмотреть возможность использования BeanWrapper
/BeanWrapperImpl
в Spring Framework для повторения свойств ваших классов. Это было бы проще, чем использование API-интерфейсов с низким уровнем отражения.
Ответ 2
Как и в первом ответе, но уточнить - spring не требуется. Commons BeanUtils.copy свойства (Object dest, Object orig)
http://commons.apache.org/beanutils/api/org/apache/commons/beanutils/BeanUtils.html#copyProperties (java.lang. Объект, %20java.lang.Object)
Ответ 3
Если вы хотите эффективно выполнять задачу (с точки зрения производительности во время выполнения), то способ кодирования копии с использованием геттеров и сеттеров - это путь. Если в методах getter или setter не существует чего-то напуганного, их тела будут встраиваться так, чтобы они были такими же быстрыми, как и задания полей.
Отражательный подход (например, с использованием существующего класса, такого как BeanUtils
), является менее кодирующим, но, вероятно, на порядок медленнее, чем вызов геттеров и сеттеров простым способом. Если вы попытаетесь реализовать это самостоятельно, вы можете столкнуться с большей работой, чем вы рассчитывали, особенно если ваш рефлексивный класс/метод копирования должен справляться с перегруженными методами, наследованием, преобразованием значений, боксированием/распаковкой и т.д.
При подходе к генерации кода вам необходимо сбалансировать усилия и сложность внедрения генерации кода (используя любую технологию, которую вы выберете) по сравнению с попыткой написать методы копирования вручную. Вероятно, вы, вероятно, не столкнетесь с подходом к генерации кода до 20 классов... и еще много, если вы не знакомы с технологией.
Ответ 4
Чтобы скопировать на основе полей, а не геттеров и сеттеров, вы можете использовать Spring ReflectionUtils.shallowCopyFieldState().
Ответ 5
Я бы написал простой инструмент java для автоматического генерации исходного кода для классов, которые могут заполнять поля подмножеств с общими полями из надмножества. Этот инструмент будет использовать отражение, чтобы получить имена методов getter и setter. Остальные являются (тривиальными) строковыми операциями для "записи" исходного файла в память и сохранения его в файл *.java
. Скомпилируйте все эти автоматически созданные файлы и добавьте файлы классов в путь к классам.
Класс может выглядеть следующим образом:
class AClassToBClassPopulator implements Populator {
@Overwrite
public void populate(Object superSet, Object subSet) {
subSet.setFieldA(superSet.getFieldA());
subSet.setFieldB(superSet.getFieldB());
// .. and so on. The method body is created through reflection
}
}
Ответ 6
Можете ли вы предоставить пример кода из вашего приложения, в котором показан сценарий, упомянутый в вашем сообщении?
Прямо сейчас отражение кажется лучшим, поскольку оно позволяет вам проверять членов класса во время выполнения.
Ответ 7
Это, очевидно, задача для отражения Java, и в то время как другие уже предложили правильные, хотя, возможно, несколько тяжеловесных решений, здесь еще одно:
Примерно год назад я написал небольшую библиотеку модификаторов свойств JavaBean под названием BeanPropertyController. Хотя я специально не рекомендую его кому-либо, я думаю, что тезисный класс библиотеки (см. Источник) можно использовать в качестве ссылки использовать аналогичные функции для ваших нужд. В качестве быстрого примера, здесь, как я использовал BPC (почти!), Что вы спрашиваете:
// somewhere in code...
SuperClass a = new SuperClass();
a.foo = 101;
a.bar = 102;
a.bat = 103f;
SubClass b = new SubClass();
b.foo = 201;
b.bat = 202f;
BeanPropertyController fromB = BeanPropertyController.of(b, ExtractionDepth.QUESTIMATE);
BeanPropertyController toA = BeanPropertyController.of(a, ExtractionDepth.QUESTIMATE);
// This is where the magic happens:
for (String propertyName : fromB.getPropertyNames()) {
toA.mutate(propertyName, fromB.access(propertyName));
}
a = (SuperClass) toA.getObject();
b = (SubClass) fromB.getObject();
System.out.println("SuperClass' foo="+a.foo+" bar="+a.bar+" bat="+a.bat);
System.out.println("SubClass' foo="+b.foo+" bat="+b.bat);
Отпечатает
SuperClass' foo=201 bar=102 bat=202.0
SubClass' foo=201 bat=202.0
Итак, я предлагаю вам перейти к URL-адресу, который я связал, и адаптировать этот фрагмент кода к вашим потребностям. Я совершенно уверен, что вам не нужны различные методы создания экземпляров, поставщики стоимости по умолчанию и т.д., Которые я включил. И да, BPC можно считать устаревшим.