Konwersja obiektów z użyciem ConversionService Skip to content →

Konwersja obiektów z użyciem ConversionService

Projekt, nad którym obecnie pracuję, to system aplikacji mikroserwisowych komunikujących się za pomocą protokołu HTTP. Ze względu na ograniczone konteksty używanej domeny poszczególne aplikacje nie mają pełnej wiedzy o encjach – po prostu nie ma takiej potrzeby. Niestety „odchudzenie” encji w pewnych częściach systemu powoduje konieczność ich konwertowania i uzupełniania o dodatkowe dane podczas komunikacji. W celu enkapsulacji logiki konwersji tworzyłem kolejne konwertery, które z czasem zaczęły być uciążliwe i niepraktyczne w zastosowaniu.

Pierwsze rozwiązanie

Pierwszym zastosowanym rozwiązaniem były klasy specjalizujące się w konwersji dwóch typów w każdym kierunku. Przykładem jest klasa FolderConverter, która transformowała obiekty Folder na FolderDTO i odwrotnie.

Jej użycie było całkiem wygodne:

Niestety pojawił się problem przy konwertowaniu list. Nie mogłem znaleźć generycznego rozwiązania zarówno dla pojedynczych encji jak i całych kolekcji.

Interfejs Converter

Kilka zapytań do wyszukiwarki i nieco więcej postów na stackoverflow podpowiedziało zastosowanie interfejsu Converter<> dostarczanego przez framework Spring.

Po przeczytaniu dokumentacji i kilku przykładów postanowiłem spróbować tego podejścia. W kodzie zmieniły się tylko dwie konwencje:

  1. dla każdego kierunku transformacji stworzony został osobny konwerter
  2.  każda klasa implementowała interfejs Converter<>

Ta zmiana, jak wynikało z dokumentacji oraz przykładów, miała zapewnić bardziej generyczne rozwiązanie i ratunek przy konwertowaniu kolekcji. I tak rzeczywiście było. Niestety używanie konwerterów w takim zapisie stało się nieco uciążliwe:

ConversionService

Kolejne akapity dokumentacji naprowadziły mnie na użycie domyślnego serwisu konwersji. Jedyne czego wymagał to rejestracja własnych konwerterów.

Rozwiązaniem było stworzenie nowego pliku konfiguracyjnego, który byłby odpowiedzialny za uzupełnienie paczki konwerterów w serwisie.

Pierwsze próby zamiany obiektów zakończyły się powodzeniem. Niestety problem pojawił się przy konwerterach, które potrzebowały innych zależności. Nie były one poprawnie wstrzykiwane przez co w logach aplikacji można było znaleźć dużo informacji o NullPointerException. Debug aplikacji potwierdził ten problem.

ConverterRegistryPostProcessor

Kolejne godziny szukania rozwiązania doprowadziły mnie do artykułu na stronie apprenticeshipnotes.org.

Po drobnym przerobieniu zaprezentowanego kodu konfiguracja ConversionService wygląda następująco:

Do kodu z powyższego artykułu wprowadziłem następujące zmiany:

  1. nie tworzę nowej instancji ConversionService, a uzupełniam tę istniejącą (mvcConversionService)
  2. dodaję wszystkie implementacje interfejsu Converter zamiast klas oznaczonych adnotacją TypeConverter

Użycie tak skonfigurowanego serwisu jest bardzo proste

Konwersja kolekcji

Konwersja kolekcji stała się nieco prostsza:

Rozwiązanie to nie jest najwygodniejsze i najładniejsze, ale niestety obecnie nie znalazłem lepszego.

Testowanie jednostkowe

Każdy z konwerterów jest traktowany jak normalna klasa, więc nie pojawia się tutaj nic niezwykłego podczas testów.

Nieco ciekawiej jest przy testowaniu klas, które używają ConversionService. W takim przypadku musimy użyć mechanizmu mockowania: