Kopiowanie wszystkich wartości z pól w jednej klasie do drugiej poprzez odbicie
Mam klasę, która jest w zasadzie kopią innej klasy.
public class A {
int a;
String b;
}
public class CopyA {
int a;
String b;
}
To, co robię, to umieszczanie wartości z klasy A
do CopyA
przed wysłaniem CopyA
przez wywołanie webservice. Teraz chciałbym stworzyć metodę reflection, która w zasadzie kopiuje wszystkie pola, które są identyczne (według nazwy i typu) z klasy A
do klasy CopyA
.
private <T extends Object, Y extends Object> void copyFields(T from, Y too) {
Class<? extends Object> fromClass = from.getClass();
Field[] fromFields = fromClass.getDeclaredFields();
Class<? extends Object> tooClass = too.getClass();
Field[] tooFields = tooClass.getDeclaredFields();
if (fromFields != null && tooFields != null) {
for (Field tooF : tooFields) {
logger.debug("toofield name #0 and type #1", tooF.getName(), tooF.getType().toString());
try {
// Check if that fields exists in the other method
Field fromF = fromClass.getDeclaredField(tooF.getName());
if (fromF.getType().equals(tooF.getType())) {
tooF.set(tooF, fromF);
}
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Jestem pewien, że musi być ktoś, kto już to jakoś zrobił
15 answers
Jeśli nie masz nic przeciwko użyciu biblioteki innej firmy, BeanUtils z Apache Commons poradzi sobie z tym dość łatwo, używając copyProperties(Object, Object)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-31 16:52:44
Dlaczego nie używasz biblioteki gson https://github.com/google/gson
Po prostu konwertujesz klasę A na łańcuch json. Następnie Konwertuj js na podklasę (CopyA) .użycie poniższego kodu:
Gson gson= new Gson();
String tmp = gson.toJson(a);
CopyA myObject = gson.fromJson(tmp,CopyA.class);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-09 05:31:24
BeanUtils kopiuje tylko publiczne pola i jest nieco powolny. Zamiast tego stosuj metody getter i setter.
public Object loadData (RideHotelsService object_a) throws Exception{
Method[] gettersAndSetters = object_a.getClass().getMethods();
for (int i = 0; i < gettersAndSetters.length; i++) {
String methodName = gettersAndSetters[i].getName();
try{
if(methodName.startsWith("get")){
this.getClass().getMethod(methodName.replaceFirst("get", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
}else if(methodName.startsWith("is") ){
this.getClass().getMethod(methodName.replaceFirst("is", "set") , gettersAndSetters[i].getReturnType() ).invoke(this, gettersAndSetters[i].invoke(object_a, null));
}
}catch (NoSuchMethodException e) {
// TODO: handle exception
}catch (IllegalArgumentException e) {
// TODO: handle exception
}
}
return null;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-12 09:29:55
Pierwszym argumentem do tooF.set()
powinien być Obiekt docelowy (too
), a nie pole, a drugim argument powinien być wartość , a nie pole, z którego pochodzi wartość. (Aby uzyskać wartość, należy wywołać fromF.get()
-- ponownie przekazując obiekt docelowy, w tym przypadku from
.)
Większość API reflection działa w ten sposób. Otrzymujesz Field
obiekty, Method
obiekty itd. z klasy, a nie z instancji, więc aby z nich korzystać (z wyjątkiem statyki), zazwyczaj musisz je przekazać przykład.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 15:14:57
Aktualizacja 19 listopada 2012: jest teraz nowy projekt ModelMapper zbyt.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-19 11:44:29
-
Bez użycia BeanUtils lub Apache Commons
public static <T1 extends Object, T2 extends Object> void copy(T1 origEntity, T2 destEntity) throws IllegalAccessException, NoSuchFieldException { Field[] fields = origEntity.getClass().getDeclaredFields(); for (Field field : fields){ origFields.set(destEntity, field.get(origEntity)); } }
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-19 13:36:27
Myślę, że możesz spróbować dozer . Ma dobre wsparcie dla konwersji fasoli na fasolę. Jest również łatwy w użyciu. Możesz albo wstrzyknąć go do aplikacji sprężynowej, albo dodać jar w ścieżce klasowej i gotowe.
Na przykład twojego przypadku:
DozerMapper mapper = new DozerMapper();
A a= new A();
CopyA copyA = new CopyA();
a.set... // set fields of a.
mapper.map(a,copyOfA); // will copy all fields from a to copyA
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-17 10:40:42
Moje rozwiązanie:
public static <T > void copyAllFields(T to, T from) {
Class<T> clazz = (Class<T>) from.getClass();
// OR:
// Class<T> clazz = (Class<T>) to.getClass();
List<Field> fields = getAllModelFields(clazz);
if (fields != null) {
for (Field field : fields) {
try {
field.setAccessible(true);
field.set(to,field.get(from));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
public static List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-20 14:10:01
Oto działające i sprawdzone rozwiązanie. Możesz kontrolować głębokość mapowania w hierarchii klas.
public class FieldMapper {
public static void copy(Object from, Object to) throws Exception {
FieldMapper.copy(from, to, Object.class);
}
public static void copy(Object from, Object to, Class depth) throws Exception {
Class fromClass = from.getClass();
Class toClass = to.getClass();
List<Field> fromFields = collectFields(fromClass, depth);
List<Field> toFields = collectFields(toClass, depth);
Field target;
for (Field source : fromFields) {
if ((target = findAndRemove(source, toFields)) != null) {
target.set(to, source.get(from));
}
}
}
private static List<Field> collectFields(Class c, Class depth) {
List<Field> accessibleFields = new ArrayList<>();
do {
int modifiers;
for (Field field : c.getDeclaredFields()) {
modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
accessibleFields.add(field);
}
}
c = c.getSuperclass();
} while (c != null && c != depth);
return accessibleFields;
}
private static Field findAndRemove(Field field, List<Field> fields) {
Field actual;
for (Iterator<Field> i = fields.iterator(); i.hasNext();) {
actual = i.next();
if (field.getName().equals(actual.getName())
&& field.getType().equals(actual.getType())) {
i.remove();
return actual;
}
}
return null;
}
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-30 08:39:20
Tak lub BeanUtils z Apache Jakarta.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-03 15:07:38
Orika jest prostym, szybszym frameworkiem mapowania bean, ponieważ generuje kod bajtowy. Robi zagnieżdżone mapowania i mapowania o różnych nazwach. Aby uzyskać więcej informacji, proszę Sprawdź tutaj Przykładowe mapowanie może wyglądać na złożone, ale w przypadku złożonych scenariuszy byłoby proste.
MapperFactory factory = new DefaultMapperFactory.Builder().build();
mapperFactory.registerClassMap(mapperFactory.classMap(Book.class,BookDto.class).byDefault().toClassMap());
MapperFacade mapper = factory.getMapperFacade();
BookDto bookDto = mapperFacade.map(book, BookDto.class);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-30 03:12:55
Jeśli masz spring w zależności możesz również użyć org.springframework.fasola.BeanUtils .
Https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/BeanUtils.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-10 11:15:12
Sprężyna ma wbudowaną metodę BeanUtils.copyProperties
. Ale to nie działa z klasami bez getterów/setterów. Kolejną opcją do kopiowania pól może być serializacja/deserializacja JSON. Jackson może być używany do tego celu. Jeśli używasz Springa w większości przypadków Jackson jest już na twojej liście zależności.
ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Clazz copyObject = mapper.readValue(mapper.writeValueAsString(sourceObject), Clazz.class);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-28 20:46:09
Jest to późny post, ale nadal może być skuteczny dla ludzi w przyszłości.
Spring dostarcza narzędzie BeanUtils.copyProperties(srcObj, tarObj)
, które kopiuje wartości z obiektu źródłowego do obiektu docelowego, gdy nazwy zmiennych składowych obu klas są takie same.
Jeśli istnieje konwersja daty, (np. Łańcuch do daty) 'null' zostanie skopiowany do obiektu docelowego. Możemy wtedy jawnie ustawić wartości daty zgodnie z wymaganiami.
BeanUtils z Apache Common
rzuca błąd, gdy występuje niedopasowanie z typów danych (esp. konwersja do I Od Daty)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-06 14:04:38
Nie chciałem z tego powodu dodawać zależności do innego pliku JAR, więc napisałem coś, co odpowiadałoby moim potrzebom. I follow the convention of fjorm https://code.google.com/p/fjorm / co oznacza, że moje ogólnie dostępne pola są publiczne i że nie zawracam sobie głowy pisaniem setterów i getterów. (moim zdaniem kod jest łatwiejszy do zarządzania i bardziej czytelny)
Więc napisałem coś (nie jest to właściwie trudne), co odpowiada moim potrzebom (zakłada, że klasa ma public constructor bez args) i może być wyodrębniony do klasy użytkowej
public Effect copyUsingReflection() {
Constructor constructorToUse = null;
for (Constructor constructor : this.getClass().getConstructors()) {
if (constructor.getParameterTypes().length == 0) {
constructorToUse = constructor;
constructorToUse.setAccessible(true);
}
}
if (constructorToUse != null) {
try {
Effect copyOfEffect = (Effect) constructorToUse.newInstance();
for (Field field : this.getClass().getFields()) {
try {
Object valueToCopy = field.get(this);
//if it has field of the same type (Effect in this case), call the method to copy it recursively
if (valueToCopy instanceof Effect) {
valueToCopy = ((Effect) valueToCopy).copyUsingReflection();
}
//TODO add here other special types of fields, like Maps, Lists, etc.
field.set(copyOfEffect, valueToCopy);
} catch (IllegalArgumentException | IllegalAccessException ex) {
Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
}
}
return copyOfEffect;
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) {
Logger.getLogger(Effect.class.getName()).log(Level.SEVERE, null, ex);
}
}
return null;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-04 18:28:07