JavaRush /Java blogi /Random-UZ /Mapstruct nima va uni SpringBoot ilovalarida birlik sinov...

Mapstruct nima va uni SpringBoot ilovalarida birlik sinovi uchun qanday qilib to'g'ri sozlash kerak

Guruhda nashr etilgan

Fon

Hammaga salom, aziz do'stlarim va o'quvchilarim! Maqolani yozishdan oldin biroz ma'lumot... Yaqinda Mapstruct kutubxonasi bilan ishlashda muammoga duch keldim , bu haqda telegram kanalimda bu yerda qisqacha bayon qildim . Izohlarda post bilan bog'liq muammo hal qilindi, mening oldingi loyihadagi hamkasbim bunga yordam berdi. Mapstruct nima va uni SpringBoot ilovalarida birlik sinovi uchun qanday qilib to'g'ri sozlash kerak.  1-1-qismShundan so'ng men ushbu mavzu bo'yicha maqola yozishga qaror qildim, lekin, albatta, biz tor nuqtai nazarga ega bo'lmaymiz va birinchi navbatda tezlikni oshirishga, Mapstruct nima ekanligini va nima uchun kerakligini tushunishga harakat qilamiz va haqiqiy misoldan foydalanib, biz buni qilamiz. ilgari yuzaga kelgan vaziyatni va uni qanday hal qilishni tahlil qilish. Shuning uchun men hamma narsani amalda sinab ko'rish uchun maqolani o'qish bilan parallel ravishda barcha hisob-kitoblarni bajarishni qat'iy tavsiya qilaman. Ishni boshlashdan oldin, mening telegram kanalimga obuna bo'ling , men u erda o'z faoliyatimni to'playman, Java va umuman IT-dagi rivojlanish haqida fikrlarni yozaman. Obuna bo'ldingizmi? Ajoyib! Xo'sh, endi ketaylik!

Mapstruct, savol-javob?

Tez turdagi xavfsiz loviya xaritalari uchun kod generatori. Bizning birinchi vazifamiz Mapstruct nima ekanligini va nima uchun bizga kerakligini aniqlashdir. Umuman olganda, siz bu haqda rasmiy veb-saytda o'qishingiz mumkin. Saytning asosiy sahifasida savollarga uchta javob bor: bu nima? Nima uchun? Qanaqasiga? Biz ham buni qilishga harakat qilamiz:

Bu nima?

Mapstruct - bu interfeyslar orqali tasvirlangan konfiguratsiyalar asosida yaratilgan koddan foydalangan holda ba'zi ob'ektlarning ob'ektlarini boshqa ob'ektlarning ob'ektlariga xaritalashda (xarita, umuman olganda, ular doimo shunday deyishadi: xarita, xarita va hokazo) yordam beradigan kutubxona.

Nima uchun?

Ko'pincha biz ko'p qatlamli ilovalarni ishlab chiqamiz (ma'lumotlar bazasi bilan ishlash qatlami, biznes mantig'i qatlami, ilovaning tashqi dunyo bilan o'zaro ta'siri uchun qatlam) va har bir qatlam ma'lumotlarni saqlash va qayta ishlash uchun o'z ob'ektlariga ega. . Va bu ma'lumotlarni bir ob'ektdan ikkinchisiga o'tkazish orqali qatlamdan qatlamga o'tkazish kerak. Ushbu yondashuv bilan ishlamaganlar uchun bu biroz murakkab ko'rinishi mumkin. Masalan, bizda Student ma'lumotlar bazasi uchun ob'ekt mavjud. Ushbu ob'ektning ma'lumotlari biznes mantig'i (xizmatlar) qatlamiga o'tganda, biz ma'lumotlarni Student sinfidan StudentModel sinfiga o'tkazishimiz kerak. Keyinchalik, biznes mantig'i bilan barcha manipulyatsiyalardan so'ng, ma'lumotlar tashqariga chiqarilishi kerak. Buning uchun bizda StudentDto sinfi mavjud. Albatta, biz StudentModel sinfidan StudentDto-ga ma'lumotlarni uzatishimiz kerak. Har safar o'tkaziladigan usullarni qo'lda yozish ko'p mehnat talab qiladi. Bundan tashqari, bu saqlanishi kerak bo'lgan kod bazasida qo'shimcha kod. Siz xato qilishingiz mumkin. Mapstruct kompilyatsiya bosqichida bunday usullarni yaratadi va ularni yaratilgan manbalarda saqlaydi.

Qanaqasiga?

Annotatsiyalardan foydalanish. Biz kutubxonaga ushbu interfeysdagi usullarni bir ob'ektdan ikkinchisiga tarjima qilish uchun foydalanish mumkinligini aytadigan asosiy Mapper annotatsiyasiga ega bo'lgan izohni yaratishimiz kerak. Talabalar haqida yuqorida aytganimdek, bizning holatlarimizda bu StudentMapper interfeysi bo'lib, unda ma'lumotlarni bir qatlamdan ikkinchisiga o'tkazishning bir necha usullari mavjud:
public class Student {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}

public class StudentDTO {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}

public class StudentModel {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}
Ushbu sinflar uchun biz mapper yaratamiz (bundan keyin biz nima va qayerga o'tkazmoqchi ekanligimizni tavsiflovchi interfeys deb ataladi):
@Mapper
public interface StudentMapper {
   StudentModel toModel(StudentDTO dto);
   Student toEntity(StudentModel model);
   StudentModel toModel(Student entity);
   StudentDTO toDto(StudentModel model);
}
Ushbu yondashuvning go'zalligi shundaki, agar turli sinflarda maydonlarning nomlari va turlari bir xil bo'lsa (bizning holatimizda bo'lgani kabi), Mapstruct sozlamalari kompilyatsiya bosqichida StudentMapper interfeysi asosida kerakli dasturni yaratish uchun etarli bo'ladi. tarjima qiladi. Demak, bu allaqachon aniq bo'ldi, to'g'rimi? Keling, oldinga boraylik va Spring Boot ilovasidagi ishni tahlil qilish uchun haqiqiy misoldan foydalanamiz.

Spring Boot va Mapstruct ishiga misol

Bizga kerak bo'lgan birinchi narsa - Spring Boot loyihasini yaratish va unga Mapstruct qo'shish. Bu borada mening GitHub-da omborlar uchun shablonlarga ega tashkilotim bor va Spring Boot-ning boshlanishi ulardan biri. Unga asoslanib, biz yangi loyiha yaratamiz: Keyinchalik, biz loyihaniMapstruct nima va uni SpringBoot ilovalarida birlik sinovi uchun qanday qilib to'g'ri sozlash kerak.  1-2 qism olamiz . Ha, do'stlar, loyihani foydali deb topsangiz, unga yulduzcha bering , shuning uchun men buni behuda qilmayotganimni bilib olaman. Ushbu loyihada men ish joyida olgan va Telegram kanalimdagi postda tasvirlangan vaziyatni ochib beramiz . Men bilmaganlar uchun vaziyatni qisqacha aytib beraman: biz xaritachilar uchun testlarni yozganimizda (ya'ni, biz ilgari aytib o'tgan interfeyslarni amalga oshirish uchun), biz testlarni iloji boricha tezroq topshirishni xohlaymiz. Xaritachilar bilan eng oddiy variant sinovni o'tkazishda SpringBootTest izohidan foydalanish bo'lib, u Spring Boot ilovasining butun ApplicationContext-ni tanlaydi va test ichidagi test uchun zarur bo'lgan xaritachini kiritadi. Ammo bu variant resurslarni talab qiladi va ko'proq vaqt talab etadi, shuning uchun u biz uchun mos emas. Biz shunchaki kerakli mapperni yaratadigan va uning usullari biz kutgandek ishlashini tekshiradigan birlik testini yozishimiz kerak. Nima uchun tezroq ishlash uchun testlar kerak? Agar testlar uzoq vaqt talab qilsa, u butun rivojlanish jarayonini sekinlashtiradi. Sinovlar yangi kodni o'tkazmaguncha, ushbu kodni to'g'ri deb hisoblash mumkin emas va sinovdan o'tkazilmaydi, ya'ni u ishlab chiqarishga olinmaydi va ishlab chiquvchi ishni tugatmaganligini anglatadi. Ko'rinishidan, nima uchun ishlashi shubhasiz bo'lgan kutubxona uchun test yozish kerak? Va shunga qaramay, biz test yozishimiz kerak, chunki biz xaritachini qanchalik to'g'ri tasvirlaganimizni va u biz kutgan narsani qiladimi yoki yo'qligini sinab ko'rmoqdamiz. Avvalo, ishimizni osonlashtirish uchun, keling, pom.xml ga boshqa qaramlikni qo'shish orqali loyihamizga Lombokni qo'shamiz:
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <scope>provided</scope>
</dependency>
Loyihamizda namunaviy sinflardan (biznes mantig'i bilan ishlash uchun foydalaniladi) tashqi dunyo bilan muloqot qilish uchun foydalaniladigan DTO sinflariga o'tishimiz kerak bo'ladi. Bizning soddalashtirilgan versiyamizda biz maydonlar o'zgarmasligini va xaritachilarimiz oddiy bo'lishini taxmin qilamiz. Ammo, agar istak bo'lsa, Mapstruct bilan qanday ishlash, uni qanday sozlash va uning afzalliklaridan qanday foydalanish haqida batafsilroq maqola yozish mumkin edi. Ammo keyin, chunki bu maqola juda uzoq bo'ladi. Aytaylik, bizda u qatnashadigan ma'ruzalar va ma'ruzachilar ro'yxati bor talaba bor. Keling, model paketini yarataylik . Bunga asoslanib, biz oddiy modelni yaratamiz:
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

import java.util.List;

@Data
public class StudentDTO {

   private Long id;

   private String name;

   private List<LectureDTO> lectures;

   private List<LecturerDTO> lecturers;
}
uning ma'ruzalari
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LectureDTO {

   private Long id;

   private String name;
}
va o'qituvchilar
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LecturerDTO {

   private Long id;

   private String name;
}
Va model paketi yonida dto paketini yarating :
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

import java.util.List;

@Data
public class StudentDTO {

   private Long id;

   private String name;

   private List<LectureDTO> lectures;

   private List<LecturerDTO> lecturers;
}
ma'ruzalar
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LectureDTO {

   private Long id;

   private String name;
}
va o'qituvchilar
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LecturerDTO {

   private Long id;

   private String name;
}
Keling, ma'ruza modellari to'plamini DTO ma'ruzalari to'plamiga aylantiradigan mapper yarataylik. Birinchi narsa Mapstruct-ni loyihaga qo'shishdir. Buning uchun biz ularning rasmiy veb-saytidan foydalanamiz , u erda hamma narsa tasvirlangan. Ya'ni, biz xotiramizga bitta bog'liqlik va plagin qo'shishimiz kerak (agar sizda xotira nima haqida savollaringiz bo'lsa, 1-modda va 2-modda ):
<dependency>
   <groupId>org.mapstruct</groupId>
   <artifactId>mapstruct</artifactId>
   <version>1.4.2.Final</version>
</dependency>
va <build/> blokidagi xotirada. bizda hali bo'lmagan:
<build>
   <plugins>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.5.1</version>
           <configuration>
               <source>1.8</source>
               <target>1.8</target>
               <annotationProcessorPaths>
                   <path>
                       <groupId>org.mapstruct</groupId>
                       <artifactId>mapstruct-processor</artifactId>
                       <version>1.4.2.Final</version>
                   </path>
               </annotationProcessorPaths>
           </configuration>
       </plugin>
   </plugins>
</build>
Keyin dto va model yonidagi mapper paketini yaratamiz . Biz ilgari ko'rsatgan sinflarga asoslanib, siz yana beshta mapper yaratishingiz kerak bo'ladi:
  • Mapper LectureModel <-> LectureDTO
  • Mapper List<LectureModel> <-> List<LectureDTO>
  • Mapper LecturerModel <-> LecturerDTO
  • Mapper List<LecturerModel> <-> List<LecturerDTO>
  • Mapper StudentModel <-> StudentDTO
Boring:

LectureMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface LectureMapper {
   LectureDTO toDTO(LectureModel model);

   LectureModel toModel(LecturerDTO dto);
}

LectureListMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

import java.util.List;

@Mapper(componentModel = "spring", uses = LectureMapper.class)
public interface LectureListMapper {
   List<LectureModel> toModelList(List<LectureDTO> dtos);
   List<LectureDTO> toDTOList(List<LectureModel> models);
}

O'qituvchi Mapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface LectureMapper {
   LectureDTO toDTO(LectureModel model);

   LectureModel toModel(LectureDTO dto);
}

O'qituvchi ListMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LecturerModel;
import org.mapstruct.Mapper;

import java.util.List;

@Mapper(componentModel = "spring", uses = LecturerMapper.class)
public interface LecturerListMapper {
   List<LecturerModel> toModelList(List<LecturerDTO> dloList);
   List<LecturerDTO> toDTOList(List<LecturerModel> modelList);
}

StudentMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.StudentDTO;
import com.github.romankh3.templaterepository.springboot.model.StudentModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
public interface StudentMapper {
   StudentDTO toDTO(StudentModel model);
   StudentModel toModel(StudentDTO dto);
}
Alohida ta'kidlash kerakki, xaritachilarda biz boshqa xaritachilarga murojaat qilamiz. Bu StudentMapper da qilinganidek, Xaritachi izohidagi uses maydoni orqali amalga oshiriladi :
@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
Bu erda ma'ruzalar ro'yxati va o'qituvchilar ro'yxatini to'g'ri xaritalash uchun ikkita mapperdan foydalanamiz. Endi biz kodimizni kompilyatsiya qilishimiz va u erda nima va qanday ekanligini ko'rishimiz kerak. Buni mvn clean compile buyrug'i yordamida amalga oshirish mumkin . Ammo, ma'lum bo'lishicha, xaritachilarimizning Mapstruct ilovalarini yaratishda, xaritalash ilovalari maydonlarni qayta yozmagan. Nega? Ma'lum bo'lishicha, Lombokdan Data annotatsiyasini olishning iloji bo'lmagan. Va nimadir qilish kerak edi ... Shuning uchun, biz maqolada yangi bo'limga egamiz.

Lombok va Mapstructni ulash

Bir necha daqiqa qidiruvdan so'ng, biz Lombok va Mapstruct-ni ma'lum bir tarzda ulashimiz kerakligi ma'lum bo'ldi. Mapstruct hujjatlarida bu haqda ma'lumot mavjud . Mapstruct-dan ishlab chiquvchilar tomonidan taklif qilingan misolni ko'rib chiqqandan so'ng, keling, pom.xml-ni yangilaymiz: Keling, alohida versiyalarni qo'shamiz:
​​<properties>
   <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
   <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
Keling, etishmayotgan bog'liqlikni qo'shamiz:
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok-mapstruct-binding</artifactId>
   <version>${lombok-mapstruct-binding.version}</version>
</dependency>
Keling, kompilyator plaginini Lombok va Mapstruct-ni ulashi uchun yangilaymiz:
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.5.1</version>
   <configuration>
       <source>1.8</source>
       <target>1.8</target>
       <annotationProcessorPaths>
           <path>
               <groupId>org.mapstruct</groupId>
               <artifactId>mapstruct-processor</artifactId>
               <version>${org.mapstruct.version}</version>
           </path>
           <path>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <version>${lombok.version}</version>
           </path>
           <path>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok-mapstruct-binding</artifactId>
               <version>${lombok-mapstruct-binding.version}</version>
           </path>
       </annotationProcessorPaths>
   </configuration>
</plugin>
Shundan so'ng hamma narsa ishlashi kerak. Keling, loyihamizni yana kompilyatsiya qilaylik. Mapstruct tomonidan yaratilgan sinflarni qayerdan topishingiz mumkin? Ular yaratilgan manbalarda: ${projectDir}/target/generated-sources/annotations/ Mapstruct nima va uni SpringBoot ilovalarida birlik sinovi uchun qanday qilib to'g'ri sozlash kerak.  1-3 qism Mapstruct postidan hafsalam pir bo'lganini anglab yetishga tayyormiz, endi xaritachilar uchun testlar yaratishga harakat qilaylik.

Biz xaritachilarimiz uchun testlar yozamiz

Men integratsiya testini yaratayotgan va uning tugash vaqti haqida tashvishlanmasangiz, xaritachilardan birini sinab ko'radigan tez va oddiy test yarataman:

LectureMapperTest

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class LectureMapperTest {

   @Autowired
   private LectureMapper mapperUnderTest;

   @Test
   void shouldProperlyMapModelToDto() {
       //given
       LectureModel model = new LectureModel();
       model.setId(11L);
       model.setName("lecture name");

       //when
       LectureDTO dto = mapperUnderTest.toDTO(model);

       //then
       Assertions.assertNotNull(dto);
       Assertions.assertEquals(model.getId(), dto.getId());
       Assertions.assertEquals(model.getName(), dto.getName());
   }

   @Test
   void shouldProperlyMapDtoToModel() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(11L);
       dto.setName("lecture name");

       //when
       LectureModel model = mapperUnderTest.toModel(dto);

       //then
       Assertions.assertNotNull(model);
       Assertions.assertEquals(dto.getId(), model.getId());
       Assertions.assertEquals(dto.getName(), model.getName());
   }
}
Bu erda, SpringBootTest izohidan foydalanib, biz butun dasturKontekstini ishga tushiramiz va undan Autowired izohidan foydalanib, sinov uchun kerakli sinfni chiqaramiz. Tezlik va test yozish qulayligi nuqtai nazaridan, bu juda yaxshi. Sinov muvaffaqiyatli o'tdi, hamma narsa yaxshi. Ammo biz boshqa yo'ldan boramiz va xaritalash vositasi uchun birlik testini yozamiz, masalan, LectureListMapper...
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;

class LectureListMapperTest {

   private final LectureListMapper lectureListMapper = new LectureListMapperImpl();

   @Test
   void shouldProperlyMapListDtosToListModels() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(12L);
       dto.setName("I'm BATMAN!");

       List<LectureDTO> dtos = Collections.singletonList(dto);

       //when
       List<LectureModel> models = lectureListMapper.toModelList(dtos);

       //then
       Assertions.assertNotNull(models);
       Assertions.assertEquals(1, models.size());
       Assertions.assertEquals(dto.getId(), models.get(0).getId());
       Assertions.assertEquals(dto.getName(), models.get(0).getName());
   }
}
Mapstruct yaratadigan ilovalar bizning loyihamiz bilan bir xil sinfda bo'lganligi sababli, biz ulardan testlarimizda osongina foydalanishimiz mumkin. Hammasi ajoyib ko'rinadi - izohlar yo'q, biz o'zimizga kerakli sinfni eng oddiy tarzda yaratamiz va tamom. Ammo testni o'tkazganimizda, biz uning ishdan chiqishini va konsolda NullPointerException bo'lishini tushunamiz... Buning sababi, LectureListMapper mapperning amalga oshirilishi quyidagicha ko'rinadi:
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Generated(
   value = "org.mapstruct.ap.MappingProcessor",
   date = "2021-12-09T21:46:12+0300",
   comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {

   @Autowired
   private LectureMapper lectureMapper;

   @Override
   public List<LectureModel> toModelList(List<LectureDTO> dtos) {
       if ( dtos == null ) {
           return null;
       }

       List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
       for ( LectureDTO lectureDTO : dtos ) {
           list.add( lectureMapper.toModel( lectureDTO ) );
       }

       return list;
   }

   @Override
   public List<LectureDTO> toDTOList(List<LectureModel> models) {
       if ( models == null ) {
           return null;
       }

       List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
       for ( LectureModel lectureModel : models ) {
           list.add( lectureMapper.toDTO( lectureModel ) );
       }

       return list;
   }
}
Agar biz NPE ga qarasak (NullPointerException so'zining qisqartmasi), biz uni lectureMapper o'zgaruvchisidan olamiz , bu ishga tushirilmagan bo'lib chiqadi. Ammo amalga oshirishda bizda o'zgaruvchini ishga tushirishimiz mumkin bo'lgan konstruktor yo'q. Mapstruct xaritachini shu tarzda amalga oshirganining sababi aynan shu! Bahorda siz fasolni sinflarga bir necha usul bilan qo'shishingiz mumkin, ularni yuqoridagi kabi Autowired izohi bilan birga maydon orqali kiritishingiz mumkin yoki ularni konstruktor orqali kiritishingiz mumkin. Sinovni bajarish vaqtini optimallashtirish kerak bo'lganda, men ishda shunday muammoli vaziyatga tushib qoldim. Hech narsa qilib bo'lmaydi, deb o'yladim va o'z dardimni Telegram kanalimda to'kib tashladim. Va keyin ular menga sharhlarda yordam berishdi va inyeksiya strategiyasini sozlash mumkinligini aytishdi. Mapper interfeysida injectionStrategy maydoni mavjud bo'lib , u faqat InjectionStrategy nomini qabul qiladi , bu ikki qiymatga ega: FIELD va CONSTRUCTOR . Endi buni bilib, ushbu parametrni xaritachilarimizga qo'shamiz; Men uni LectureListMapper yordamida misol sifatida ko'rsataman :
@Mapper(componentModel = "spring", uses = LectureMapper.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface LectureListMapper {
   List<LectureModel> toModelList(List<LectureDTO> dtos);
   List<LectureDTO> toDTOList(List<LectureModel> models);
}
Men qo'shilgan qismni qalin qilib ta'kidladim. Keling, ushbu parametrni boshqalar uchun qo'shamiz va loyihani qayta kompilyatsiya qilamiz, shunda xaritachilar yangi qator bilan yaratiladi. Buni amalga oshirgandan so'ng, keling, LectureListMapper uchun xaritachining amalga oshirilishi qanday o'zgarganini ko'rib chiqamiz (bizga kerak bo'lgan qism qalin qilib belgilangan):
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Generated(
   value = "org.mapstruct.ap.MappingProcessor",
   date = "2021-12-09T22:25:37+0300",
   comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {

   private final LectureMapper lectureMapper;

   @Autowired
   public LectureListMapperImpl(LectureMapper lectureMapper) {

       this.lectureMapper = lectureMapper;
   }

   @Override
   public List<LectureModel> toModelList(List<LectureDTO> dtos) {
       if ( dtos == null ) {
           return null;
       }

       List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
       for ( LectureDTO lectureDTO : dtos ) {
           list.add( lectureMapper.toModel( lectureDTO ) );
       }

       return list;
   }

   @Override
   public List<LectureDTO> toDTOList(List<LectureModel> models) {
       if ( models == null ) {
           return null;
       }

       List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
       for ( LectureModel lectureModel : models ) {
           list.add( lectureMapper.toDTO( lectureModel ) );
       }

       return list;
   }
}
Endi Mapstruct konstruktor orqali mapper inyeksiyasini amalga oshirdi. Aynan shu narsaga erishmoqchi edik. Endi bizning testimiz kompilyatsiya qilishni to'xtatadi, keling, uni yangilaymiz va olamiz:
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;

class LectureListMapperTest {

   private final LectureListMapper lectureListMapper = new LectureListMapperImpl(new LectureMapperImpl());

   @Test
   void shouldProperlyMapListDtosToListModels() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(12L);
       dto.setName("I'm BATMAN!");

       List<LectureDTO> dtos = Collections.singletonList(dto);

       //when
       List<LectureModel> models = lectureListMapper.toModelList(dtos);

       //then
       Assertions.assertNotNull(models);
       Assertions.assertEquals(1, models.size());
       Assertions.assertEquals(dto.getId(), models.get(0).getId());
       Assertions.assertEquals(dto.getName(), models.get(0).getName());
   }
}
Endi testni o'tkazsak, hamma narsa kutilganidek ishlaydi, chunki LectureListMapperImpl da biz unga kerak bo'lgan LectureMapper ni topshiramiz... G'alaba! Bu siz uchun qiyin emas, lekin men mamnunman: Do'stlar, hamma narsa odatdagidek, mening GitHub akkauntimga , Telegram akkauntimga obuna bo'ling . U erda men faoliyatim natijalarini joylashtiraman, haqiqatan ham foydali narsalar bor) Men sizni ayniqsa telegram kanalining muhokama guruhiga qo'shilishga taklif qilaman . Shunday bo'ladiki, agar kimdir texnik savolga ega bo'lsa, u erda javob olishi mumkin. Ushbu format hamma uchun qiziqarli, siz kim nimani bilishini o'qib, tajriba orttirishingiz mumkin.

Xulosa

Ushbu maqola doirasida biz Mapstruct kabi zarur va tez-tez ishlatiladigan mahsulot bilan tanishdik. Biz nima ekanligini, nima uchun va qanday ekanligini aniqladik. Haqiqiy misoldan foydalanib, biz nima qilish mumkinligini va uni qanday o'zgartirish mumkinligini his qildik. Biz, shuningdek, konstruktor orqali loviya inyeksiyasini qanday sozlashni ko'rib chiqdik, shunda xaritachilarni to'g'ri sinab ko'rish mumkin edi. Mapstruct hamkasblari o'z mahsulotining foydalanuvchilariga xaritachilarni qanday kiritishni tanlashga imkon berishdi, buning uchun biz ularga minnatdorchilik bildiramiz. LEKIN, Spring loviyani konstruktor orqali in'ektsiya qilishni tavsiya qilganiga qaramay, Mapstruct yigitlari sukut bo'yicha dala orqali in'ektsiyani o'rnatdilar. Nega bunday? Javobsiz. O'ylaymanki, biz bilmagan sabablar bo'lishi mumkin va shuning uchun ular buni shunday qilishdi. Va ulardan bilish uchun men ularning rasmiy mahsulot omborida GitHub muammosini yaratdim.
Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION