Mapstruct full rehber, advanced senaryolar ve kod çözümleri.



Elbette, MapStruct oldukça güçlü bir Java kütüphanesidir ve nesneler arasında dönüşüm yaparken çok kullanışlıdır. Spring Boot ile birlikte kullanıldığında, veri tabanı varlıkları ile DTO (Data Transfer Objects) arasındaki dönüşümü kolaylaştırabilir.


Öncelikle basit bir senaryo ile başlayalım ve ardından daha karmaşık durumlara geçelim.


1. Basit Senaryo: Varlık (Entity) ve DTO arasında dönüşüm


Öncelikle gerekli bağımlılıkları ekleyelim.

xml

Copy code

<!-- pom.xml -->

<dependency>

    <groupId>org.mapstruct</groupId>

    <artifactId>mapstruct</artifactId>

    <version>1.4.2.Final</version>

</dependency>

<dependency>

    <groupId>org.mapstruct</groupId>

    <artifactId>mapstruct-processor</artifactId>

    <version>1.4.2.Final</version>

    <scope>provided</scope>

</dependency>

Şimdi basit bir varlık ve DTO oluşturalım:

java

Copy code

// UserEntity.java

public class UserEntity {

    private Long id;

    private String name;

    // getters, setters ...

}


// UserDTO.java

public class UserDTO {

    private Long id;

    private String name;

    // getters, setters ...

}

MapStruct mapper interface'ini oluşturun:

java

Copy code

@Mapper

public interface UserMapper {

    UserDTO toDTO(UserEntity entity);

    UserEntity toEntity(UserDTO dto);

}

MapStruct, yukarıdaki tanıma göre bir implementasyon oluşturacaktır. Implementasyonu manuel olarak yapmamıza gerek yoktur.

2. Gelişmiş Senaryo: Özelleştirilmiş dönüşüm


Bazen otomatik dönüşümler yeterli olmayabilir. Özelleştirilmiş bir dönüşüm işlevi eklemek için @Mapping anotasyonunu kullanabilirsiniz.


Örneğin, varlığımızın name alanının DTO'da fullName olarak adlandırılmasını istiyorsak:


java

Copy code

@Mapper

public interface UserMapper {

    @Mapping(source = "name", target = "fullName")

    UserDTO toDTO(UserEntity entity);

    UserEntity toEntity(UserDTO dto); // bu dönüşüm için özelleştirme yapmadık

}

3. Nested (İç içe) Dönüşümler


Eğer varlığınızın iç içe başka bir varlık veya DTO içermesi durumunda, MapStruct bu dönüşümleri otomatik olarak gerçekleştirir.


Örnek:


java

Copy code

// AddressEntity ve AddressDTO sınıflarını düşünün

public class AddressEntity {

    private String street;

    // getters, setters ...

}


public class AddressDTO {

    private String street;

    // getters, setters ...

}


// UserEntity içinde AddressEntity'yi içersin

public class UserEntity {

    private Long id;

    private String name;

    private AddressEntity address;

    // getters, setters ...

}


public class UserDTO {

    private Long id;

    private String name;

    private AddressDTO address;

    // getters, setters ...

}


@Mapper

public interface UserMapper {

    UserDTO toDTO(UserEntity entity);

    UserEntity toEntity(UserDTO dto);

}

MapStruct, AddressEntity'yi AddressDTO'ya otomatik olarak dönüştürecektir.


4. Default Metotlar ve Özel Dönüşümler


Bazen özelleştirilmiş bir dönüşüm yapmak için daha fazla kontrol ihtiyacınız olabilir. Bu durumda, mapper interface'ine default metotlar ekleyebilirsiniz.


Örnek olarak, bir tarih biçimini değiştirmek istediğimizi düşünelim:


java

Copy code

public class UserEntity {

    private Date birthDate;

    // ... diğer alanlar, getters, setters

}


public class UserDTO {

    private String birthDate; // "yyyy-MM-dd" formatında

    // ... diğer alanlar, getters, setters

}


@Mapper

public interface UserMapper {


    @Mapping(source = "birthDate", target = "birthDate", qualifiedByName = "dateToString")

    UserDTO toDTO(UserEntity entity);


    @Named("dateToString")

    default String dateToString(Date date) {

        if (date == null) {

            return null;

        }

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        return format.format(date);

    }

}

Bu örnekte, bir Date nesnesini belirli bir string formatına dönüştürmek için bir default metot oluşturduk.


5. Birden Fazla Mapper Kullanımı


Bazen, bir nesneyi başka bir nesneye dönüştürmek için başka mapper'lar da gerekebilir. Bu durumda, bir mapper'dan başka bir mapper'a başvurabilirsiniz.


Örneğin, UserEntity'nin bir ProfileEntity'si olduğunu ve bu iki entity'nin kendi DTO sınıflarına dönüştürülmesi gerektiğini varsayalım:


java

Copy code

public class ProfileEntity {

    private String bio;

    // ... getters, setters

}


public class ProfileDTO {

    private String bio;

    // ... getters, setters

}


@Mapper

public interface ProfileMapper {

    ProfileDTO toDTO(ProfileEntity entity);

    ProfileEntity toEntity(ProfileDTO dto);

}


public class UserEntity {

    private ProfileEntity profile;

    // ... diğer alanlar, getters, setters

}


public class UserDTO {

    private ProfileDTO profile;

    // ... diğer alanlar, getters, setters

}


@Mapper(uses = ProfileMapper.class)

public interface UserMapper {

    UserDTO toDTO(UserEntity entity);

    UserEntity toEntity(UserDTO dto);

}

Bu örnekte, UserMapper sınıfı dönüşüm yaparken ProfileMapper'ı da kullanacak.


6. Iterable ve Map Dönüşümleri


MapStruct, listeler, setler ve diğer iterable tipler arasında otomatik dönüşüm yapabilir. Örneğin:


java

Copy code

@Mapper

public interface UserMapper {

    List<UserDTO> toDTOList(List<UserEntity> entities);

    Set<UserDTO> toDTOSet(Set<UserEntity> entities);

}

Bu, özellikle servis katmanında veritabanından alınan varlıkların DTO'lara dönüştürülmesi gerektiğinde oldukça kullanışlıdır.



7. Özellikleri Dönüştürmede Dönüşüm Stratejileri


MapStruct, farklı adlara sahip özellikler arasında dönüşüm yapma stratejisi için @Mapper anotasyonunda componentModel ve injectionStrategy gibi özellikler sunar. Örneğin, Spring ile kullanıyorsanız:


java

Copy code

@Mapper(componentModel = "spring", uses = OtherMapper.class)

public interface UserMapper {

    // dönüşüm metotları

}

Bu ayar sayesinde MapStruct, Spring için uyumlu bir bileşen oluşturur ve diğer Spring bileşenlerini otomatik olarak enjekte edebilir.


8. Dönüşümde Yaşam Döngüsü Metotları


Bazen bir nesnenin dönüştürülmesi sırasında önceden veya sonradan bazı özel işlemler yapmanız gerekebilir. @BeforeMapping ve @AfterMapping anotasyonları bu işlemleri destekler.


java

Copy code

@Mapper

public abstract class UserMapper {


    @BeforeMapping

    protected void enrichEntity(UserDTO dto, @MappingTarget UserEntity entity) {

        // DTO'dan alınan bazı değerleri kullanarak varlığı zenginleştirebilirsiniz.

    }


    @AfterMapping

    protected void performPostActions(UserEntity entity, @MappingTarget UserDTO dto) {

        // Dönüşüm sonrası bazı ek işlemler yapabilirsiniz.

    }


    public abstract UserDTO toDTO(UserEntity entity);

    public abstract UserEntity toEntity(UserDTO dto);

}

9. Dönüşüm İçin Özel Tip Dönüştürücüleri


Bazen özel bir dönüşüm işlemi tanımlamanız gerekebilir. Örneğin, bir Color enum'ınız varsa ve bu enum'ı bir string değerine dönüştürmek istiyorsanız:


java

Copy code

public enum Color {

    RED, GREEN, BLUE

}


public class ProductEntity {

    private Color color;

    // ... 

}


public class ProductDTO {

    private String color;

    // ...

}


@Mapper

public abstract class ProductMapper {


    public String colorToString(Color color) {

        return color == null ? null : color.name().toLowerCase();

    }


    public Color stringToColor(String color) {

        return color == null ? null : Color.valueOf(color.toUpperCase());

    }


    public abstract ProductDTO toDTO(ProductEntity entity);

    public abstract ProductEntity toEntity(ProductDTO dto);

}

Bu örnekte, Color enum'ını bir string'e dönüştürmek için özel metotlar tanımladık.


10. Update Metotları


Bir DTO'nun içeriğini zaten mevcut bir varlıkla güncellemek istediğinizde, @MappingTarget anotasyonunu kullanarak bu işlemi yapabilirsiniz:


java

Copy code

@Mapper

public interface UserMapper {

    void updateUserFromDTO(UserDTO dto, @MappingTarget UserEntity entity);

}

Bu özellik, bir REST API üzerinden gelen güncellemeleri varlıkla birleştirmek için oldukça kullanışlıdır.


11. İç içe dönüşümler ve @Context


Bazen dönüşüm yaparken ekstra bağlam bilgisi sağlamamız gerekebilir. Bu, @Context anotasyonuyla gerçekleştirilir.


Örneğin, dönüşüm sırasında bir servise erişmemiz gerektiğini düşünelim:


java

Copy code

public class MappingContext {

    private SomeService someService;


    public MappingContext(SomeService someService) {

        this.someService = someService;

    }


    public SomeService getSomeService() {

        return someService;

    }

}


@Mapper

public interface UserMapper {

    @Mapping(target = "specialValue", source = "name", qualifiedBy = SpecialValueMapper.class)

    UserDTO toDTO(UserEntity entity, @Context MappingContext context);

}


public class SpecialValueMapper {


    @Named("specialValueMapping")

    public String mapSpecialValue(String name, @Context MappingContext context) {

        return context.getSomeService().doSomeOperation(name);

    }

}

Bu yapı, dönüşüm sırasında ekstra bilgi veya servislerin nasıl enjekte edileceğini kontrol etmek için oldukça kullanışlıdır.


12. İleri Seviye @Mapping Kullanımları


@Mapping anotasyonu birçok ileri seviye özellik sunar:


defaultValue: Eğer kaynak değeri null ise kullanılacak varsayılan değeri belirtir.

ignore: Hedef özelliğin dönüştürme sırasında atlanmasını sağlar.

nullValuePropertyMappingStrategy: Kaynak özelliği null olduğunda hedef özelliğin nasıl dönüştürüleceğini belirtir.

13. Türevli Mapper'lar


Bir mapper interface veya abstract sınıfı başka bir mapper'ı miras alabilir. Bu, yaygın dönüşüm işlevselliğini bir temel mapper'da tanımlayıp, türev mapper'larla bu işlevselliği genişletebilmenizi sağlar.


14. Builder Pattern ile Kullanım


Bazı nesneler builder pattern kullanılarak oluşturulmuş olabilir. MapStruct, @Builder anotasyonunu kullanarak bu tür nesnelerle uyumludur:


java

Copy code

@Mapper(builder = @Builder(disableBuilder = true))

public interface UserMapper {

    UserDTO toDTO(UserEntity entity);

}

Bu, özellikle Lombok gibi kütüphanelerle çalışırken yararlı olabilir.


15. MapStruct Configurations


Dönüşüm işlemleri için genel yapılandırmaları tanımlamak istediğinizde, ortak bir yapılandırma arayüzü oluşturabilirsiniz. Bu arayüzü diğer mapper'larınızda kullanarak tekrar eden yapılandırmaları azaltabilirsiniz.


java

Copy code

@MapperConfig

public interface CommonMapperConfig {

    // ortak yapılandırmalar

}


@Mapper(config = CommonMapperConfig.class)

public interface UserMapper {

    // ...

}

Bu yapılandırma, projenizdeki tüm mapper'lar için ortak dönüşüm kurallarını ve stratejilerini tanımlamanızı sağlar.


Bu, MapStruct ile ilgili daha derinlemesine bilgileri ve önerileri içerir. MapStruct oldukça kapsamlı bir kütüphane olduğu için, belirli bir konuda daha fazla ayrıntı isterseniz veya başka bir konu üzerine odaklanmak isterseniz, lütfen bana bildirin!


Elbette, MapStruct'un daha derinlemesine bazı özelliklerine devam edelim.


16. Özelleştirilmiş Dönüşüm Yöntemleri ile Metod Seçimi


Eğer birden fazla özelleştirilmiş dönüşüm metodu varsa, MapStruct hangi metodun hangi özelliğin dönüşümü için kullanılacağını nasıl belirler? İşte bu sorunun cevabı: @Qualifier anotasyonu. Bu anotasyon, birden fazla dönüşüm metodunun aynı türdeki özellikler için kullanılmasını yönetmenizi sağlar.


Örnek:


java

Copy code

@Mapper

public interface BookMapper {


    @FullTitle

    default String fullTitle(String title, String subtitle) {

        return title + " - " + subtitle;

    }


    @ShortTitle

    default String shortTitle(String title) {

        return title;

    }


    @Mapping(source = "title", target = "displayTitle", qualifiedBy = FullTitle.class)

    BookDTO toDTO(Book book);

}

Bu örnekte, iki farklı özelleştirilmiş dönüşüm metodu tanımlandı ve bunlar @Qualifier anotasyonlarıyla işaretlendi.


17. Java 8 ve Sonrası Özelliklerinin Kullanılması


Java 8 ve sonrası sürümlerde tanıtılan bazı özellikler, dönüşüm süreçlerinde kullanılabilir. Özellikle Optional ve yeni tarih & saat API'leri (LocalDate, LocalDateTime vb.) bu kapsama girer.


java

Copy code

@Mapper

public interface DateMapper {

    @Mapping(target = "dateAsString", source = "localDate", dateFormat = "yyyy-MM-dd")

    DateDTO toDTO(DateEntity dateEntity);

}

Bu örnekte, LocalDate'i bir stringe dönüştürüyoruz.


18. Hata Yönetimi


Hatalı veya beklenmedik bir dönüşüm durumunda, özel bir hata yönetimi gerçekleştirmek için @Mapper anotasyonunda unmappedTargetPolicy ve typeConversionPolicy gibi özellikleri tanımlayabilirsiniz.


java

Copy code

@Mapper(unmappedTargetPolicy = ReportingPolicy.ERROR)

public interface UserMapper {

    UserDTO toDTO(UserEntity userEntity);

}

Bu örnekte, eğer dönüştürme sırasında eşlenmemiş bir hedef özellik bulunursa bir hata alacağız.


19. MapStruct ve İmmutability


Immutable nesnelerle çalışıyorsanız (örneğin, sadece final alanları olan sınıflar), MapStruct bu tür nesnelerle çalışabilir. Bu, özellikle constructor üzerinden değer atanması gereken durumlarda faydalıdır.


20. MapStruct ve Lombok


Lombok, Java'da boilerplate kodu azaltmak için yaygın olarak kullanılır. MapStruct, Lombok ile uyumludur. Ancak, dikkat etmeniz gereken şey, Lombok'un compile-time'da kodu oluşturduğudur. Bu nedenle, genellikle Maven veya Gradle gibi build araçlarıyla çalışırken doğru sıralamada eklentileri tanımlamanız gerekir.



21. Dönüşüm Haritaları (Maps)


MapStruct, Map türündeki alanların dönüştürülmesini de destekler. Örneğin, iki farklı Map türünü birbiriyle eşleştirmek mümkündür.


java

Copy code

@Mapper

public interface ConfigMapper {

    Map<String, String> convert(Map<Integer, String> source);

}

Bu örnekte, Integer anahtarları String olarak dönüştürülen bir haritayı dönüştürdük. Daha karmaşık harita dönüşümleri için özelleştirilmiş dönüşüm yöntemleri de tanımlanabilir.


22. Koleksiyonlar ve Listeler


Listeler ve diğer koleksiyonlar arasında dönüşüm yaparken, genellikle bu koleksiyonların içindeki nesneler arasında da dönüşüm yapılır. MapStruct, bu tür dönüşümleri otomatik olarak ele alır.


java

Copy code

@Mapper

public interface BookMapper {

    List<BookDTO> toDTOList(List<BookEntity> books);

}

Bu, BookEntity listesini BookDTO listesine dönüştürür. MapStruct, her bir BookEntity öğesini bir BookDTO'ya otomatik olarak dönüştürür.


23. Dönüşüm İçin Bean Parametreleri


Bazen, dönüşüm sırasında ekstra bilgi sağlamak için birden fazla kaynak nesneye ihtiyaç duyarız. @BeanMapping anotasyonunu kullanarak birden fazla kaynak belirtebilirsiniz.


java

Copy code

@Mapper

public interface OrderMapper {

    @BeanMapping(ignoreByDefault = true)

    @Mapping(source = "user.name", target = "customerName")

    @Mapping(source = "product.title", target = "productTitle")

    OrderDTO toDTO(Order order, User user, Product product);

}

Bu örnekte, hem User hem de Product nesnelerini dönüşüm için kaynak olarak kullanıyoruz.


24. İleri Enum Dönüşümleri


Bazen, Enum türleri arasında doğrudan eşlemelerden ziyade özelleştirilmiş dönüşümlere ihtiyaç duyabilirsiniz. Bu, özelleştirilmiş dönüşüm yöntemleri ile yapılabilir.


java

Copy code

@Mapper

public interface RoleMapper {

    default RoleDTO roleToDto(Role role) {

        if (role == null) {

            return null;

        }

        switch (role) {

            case ADMIN:

                return RoleDTO.SUPER_USER;

            case USER:

                return RoleDTO.REGULAR_USER;

            default:

                throw new IllegalArgumentException("Unexpected role: " + role);

        }

    }

}

Bu örnekte, Role Enum'undaki değerleri özelleştirilmiş bir yöntemle RoleDTO Enum'una dönüştürdük.


Please Select Embedded Mode To Show The Comment System.*

Daha yeni Daha eski

نموذج الاتصال