2009-08-31 14 views
19

chciałbym zrobić coś takiego:Jak zbiory map w spycharek

ArrayList<CustomObject> objects = new ArrayList<CustomObject>(); 
... 
DozerBeanMapper MAPPER = new DozerBeanMapper(); 
... 
ArrayList<NewObject> newObjects = MAPPER.map(objects, ...); 

Zakładając:

<mapping> 
    <class-a>com.me.CustomObject</class-a> 
    <class-b>com.me.NewObject</class-b> 
    <field> 
     <a>id</a> 
     <b>id2</b> 
    </field> 
</mapping> 

Próbowałem:

ArrayList<NewObject> holder = new ArrayList<NewObject>(); 
MAPPER.map(objects, holder); 

ale obiekt posiadacz jest pusty . Grałem też przy zmianie drugiego argumentu bez powodzenia ...

Odpowiedz

28

Cytując:

„zagnieżdżone zbiory są obsługiwane automatycznie, ale masz rację że zbiory najwyższego poziomu musi być powtórzyć W tej chwili nie ma bardziej eleganckiego sposobu na obsłużenie tego. "

Someone has figured a way to do it without a looping construct in your code base, ale myślę, że to po prostu łatwiejsze (i bardziej czytelne/linkujących), aby umieścić go w kodzie. Mam nadzieję, że dodadzą tę umiejętność wcześniej niż później.

+1

Adres wątku zmieniono na: http://sourceforge.net/projects/dozer/forums/forum/452530/topic/3017095 (na wszelki wypadek, gdy zdecydują się usunąć automatyczne przekierowanie) – Mark

+0

@Gnoupi Dzięki za dodanie linku –

+0

Teraz na http://sourceforge.net/p/dozer/discussion/452530/thread/012023da/ – dschulten

5

To, co się dzieje, to to, że zostajesz ukąszony przez wymazanie typu. W środowisku wykonawczym java widzi tylko ArrayList.class. Typy CustomObject i NewObject nie istnieją, więc Dozer próbuje mapować java.util.ArrayList, a nie CustomObject na NewObject.

Co powinno działać (całkowicie niesprawdzone):

List<CustomObject> ori = new ArrayList<CustomObject>(); 
List<NewObject> n = new ArrayList<NewObject>(); 
for (CustomObject co : ori) { 
    n.add(MAPPER.map(co, CustomObject.class)); 
} 
+0

W jaki sposób zrobiłbyś to, gdyby nie pętla odwzorowująca każdy obiekt jeden po drugim? –

+0

Nie ma innego sposobu niż pętla, którą widzę (chyba że Dozer obsługuje operacje na kolekcjach, nie znam się na API). – Yishai

+0

Oto jest pytanie. Wierzę, że to ma wspierać sposób bez pętli. Po prostu nie mogę znaleźć konkretnych szczegółów. –

2

W tym przypadku użycia Napisałem kiedyś trochę klasy pomocnika:

import java.util.Collection; 

/** 
* Helper class for wrapping top level collections in dozer mappings. 
* 
* @author Michael Ebert 
* @param <E> 
*/ 
public final class TopLevelCollectionWrapper<E> { 

    private final Collection<E> collection; 

    /** 
    * Private constructor. Create new instances via {@link #of(Collection)}. 
    * 
    * @see {@link #of(Collection)} 
    * @param collection 
    */ 
    private TopLevelCollectionWrapper(final Collection<E> collection) { 
     this.collection = collection; 
    } 

    /** 
    * @return the wrapped collection 
    */ 
    public Collection<E> getCollection() { 
     return collection; 
    } 

    /** 
    * Create new instance of {@link TopLevelCollectionWrapper}. 
    * 
    * @param <E> 
    *   Generic type of {@link Collection} element. 
    * @param collection 
    *   {@link Collection} 
    * @return {@link TopLevelCollectionWrapper} 
    */ 
    public static <E> TopLevelCollectionWrapper<E> of(final Collection<E> collection) { 
     return new TopLevelCollectionWrapper<E>(collection); 
    } 
} 

Następnie nazwałbym dozownik w następujący sposób:

private Mapper mapper; 

@SuppressWarnings("unchecked") 
public Collection<MappedType> getMappedCollection(final Collection<SourceType> collection) { 
    TopLevelCollectionWrapper<MappedType> wrapper = mapper.map(
      TopLevelCollectionWrapper.of(collection), 
      TopLevelCollectionWrapper.class); 

    return wrapper.getCollection(); 
} 

Jedyną wadą: Dostajesz „niesprawdzony” ostrzeżenie na mapper.map(...) z powodu interfejsu spekulantów Mapper, który nie obsługuje typów ogólnych.

7

Zmierzyłem się z podobnym problemem i zdecydowałem się na użycie ogólnej metody, aby uniknąć iteracji za każdym razem, gdy potrzebowałem wykonać takie mapowanie.

public static <T, U> List<U> map(final Mapper mapper, final List<T> source, final Class<U> destType) { 

    final List<U> dest = new ArrayList<>(); 

    for (T element : source) { 
     dest.add(mapper.map(element, destType)); 
    } 

    return dest; 
} 

Wykorzystanie byłby wtedy coś takiego:

final List<CustomObject> accounts..... 
    final List<NewObject> actual = Util.map(mapper, accounts, NewObject.class); 

Ewentualnie może to być uproszczone dalej chociaż.

+0

To zadziałało dla mnie. Dzięki! –

1

Niezupełnie poprawa, bardziej jak cukru składniowej, które można osiągnąć dzięki Guava (i najprawdopodobniej coś podobnego jest możliwe z Apache Commons):

final List<MyPojo> mapped = Lists.newArrayList(Iterables.transform(inputList, new Function<MyEntity, MyPojo>() { 
    @Override public MyPojo apply(final MyEntity arg) { 
     return mapper.map(arg, MyPojo.class); 
    } 
})); 

To może być włączony do funkcji rodzajowy - jak sugerowano w innych odpowiedziach.

3

można zrobić to tak:

public <T,S> List<T> mapListObjectToListNewObject(List<S> objects, Class<T> newObjectClass) { 
final List<T> newObjects = new ArrayList<T>(); 
for (S s : objects) { 
    newObjects.add(mapper.map(s, newObjectClass)); 
} 
return newObjects; 

}

i używać go:

ArrayList<CustomObject> objects = .... 
List<NewObject> newObjects = mapListObjectToListNewObject(objects,NewObject.class); 
1

można zaimplementować własną klasę odwzorowujący która rozszerzy spycharki mapowania. Przykład: utworzyć interfejs, który dodaje dodatkowe metody dozer mapowania:

public interface Mapper extends org.dozer.Mapper { 
    <T> List<T> mapAsList(Iterable<?> sources, Class<T> destinationClass); 
} 

Następny krok: Napisz klasę Mapper wdrażając powyżej interfejs.

dodać poniżej metody do klasy realizacji:

public class MyMapper implements Mapper { 
    @Override 
    public <T> List<T> mapAsList(Iterable<?> sources, Class<T> destinationClass) { 
     //can add validation methods to check if the object is iterable 
     ArrayList<T> targets = new ArrayList<T>(); 
     for (Object source : sources) { 
      targets.add(map(source, destinationClass)); 
     } 
     return targets; 
    } 
    //other overridden methods. 
} 

Nadzieja to pomaga

1

zrobiłem go za pomocą Java 8 i dozer 5.5. Do mapowania nie potrzebujesz żadnych plików XML. Możesz to zrobić w Javie.

Nie potrzeba żadnego dodatkowego odwzorowanie dla list, Jedyne czego potrzebujesz to

trzeba dodać do listy jako pola w mapowaniu

. Zobacz przykładową konfigurację komponentu bean poniżej.

klasa konfiguracja Wiosna

@Configuration 
public class Config { 

@Bean 
    public DozerBeanMapper dozerBeanMapper() throws Exception { 
     DozerBeanMapper mapper = new DozerBeanMapper(); 
     mapper.addMapping(new BeanMappingBuilder() { 
      @Override 
      protected void configure() { 
       mapping(Answer.class, AnswerDTO.class); 
       mapping(QuestionAndAnswer.class, QuestionAndAnswerDTO.class).fields("answers", "answers");     
      } 
     }); 
     return mapper; 
    } 

} 

klas // klasa Odbierz i AnswerDTO mają te same atrybuty

public class AnswerDTO { 

    public AnswerDTO() { 
     super(); 
    } 

    protected int id; 
    protected String value; 

    //setters and getters 
} 

// klasa QuestionAndAnswerDTO ma listę odpowiedzi

public class QuestionAndAnswerDTO { 

    protected String question; 
    protected List<AnswerDTO> answers; 

    //setters and getters 
} 

// Następnie korzystać z programu odwzorowującego w swoim kodzie, przeprowadź autouzupełnianie go

@Autowired 
private DozerBeanMapper dozerBeanMapper; 
// in your method 


QuestionAndAnswerDTO questionAndAnswerDTO = 
    dozerBeanMapper.map(questionAndAnswer, QuestionAndAnswerDTO.class); 

Mam nadzieję, że pomoże to komuś zastosować się do metody Java zamiast XML.