In un’applicazione Java è frequente dover trasferire dati da un oggetto a un altro. Un caso tipico è la conversione di una entity proveniente dal database in un DTO destinato a una API REST, a un servizio esterno o al livello di presentazione.

Quando gli oggetti contengono molte proprietà, strutture annidate o tipi differenti, copiare manualmente ogni valore con una lunga sequenza di metodi get e set può rendere il codice ripetitivo, fragile e difficile da mantenere. Dozer nasce proprio per automatizzare il mapping tra Java Bean.

⚠️ Aggiornamento importante

Dozer può essere ancora presente in numerose applicazioni legacy, ma il progetto ufficiale non è più attivamente sviluppato. Per una nuova applicazione è consigliabile valutare alternative moderne come MapStruct o ModelMapper. Questa guida rimane utile per mantenere, aggiornare o comprendere progetti che utilizzano Dozer.

Che cos’è Dozer

Dozer è un framework Java per il mapping tra Java Bean. Il suo compito è leggere le proprietà di un oggetto sorgente e copiarle in un oggetto di destinazione, effettuando quando possibile anche la conversione automatica dei tipi.

Il framework può essere utilizzato, ad esempio, per convertire:

  • entity JPA in DTO;
  • DTO ricevuti da una API in oggetti di dominio;
  • modelli interni in oggetti richiesti da servizi esterni;
  • Java Bean con proprietà simili ma tipi differenti;
  • oggetti contenenti altri oggetti o collezioni;
  • modelli legacy in strutture più moderne.

Dozer supporta due modalità principali:

  • mapping implicito: associa automaticamente le proprietà che hanno lo stesso nome;
  • mapping esplicito: utilizza XML, API Java o converter personalizzati per indicare la corrispondenza tra proprietà differenti.

💡 Esempio: se sia ClienteEntity sia ClienteDTO contengono le proprietà nome ed email, Dozer può copiarle senza alcuna configurazione XML.

Quando utilizzare un Bean Mapper

Un mapper può essere utile quando l’applicazione è organizzata in diversi livelli e non si desidera utilizzare lo stesso oggetto in ogni punto del sistema.

Esporre direttamente una entity JPA attraverso una API REST, ad esempio, può provocare diversi problemi:

  • esposizione involontaria di proprietà riservate;
  • forte dipendenza tra database e API;
  • serializzazione di relazioni non necessarie;
  • problemi con proxy e caricamento lazy;
  • difficoltà nel modificare il modello interno;
  • risposte JSON più pesanti del necessario.

Un DTO permette invece di controllare con precisione quali dati rendere disponibili.

Esempio di conversione manuale

ClienteDTO dto = new ClienteDTO();

dto.setId(cliente.getId());
dto.setNome(cliente.getNome());
dto.setEmail(cliente.getEmail());
dto.setEta(cliente.getEta());
dto.setCitta(cliente.getIndirizzo().getCitta());

La stessa conversione con un mapper

ClienteDTO dto = mapper.map(cliente, ClienteDTO.class);

Il secondo approccio riduce il codice ripetitivo, ma non elimina la necessità di progettare correttamente DTO, entity e confini dell’applicazione.

Installazione di Dozer con Maven o Gradle

Le vecchie versioni di Dozer utilizzavano il gruppo Maven net.sf.dozer. Nelle versioni moderne la dipendenza principale è com.github.dozermapper:dozer-core.

Dipendenza Maven

<dependency>
    <groupId>com.github.dozermapper</groupId>
    <artifactId>dozer-core</artifactId>
    <version>7.0.0</version>
</dependency>

Dipendenza Gradle

dependencies {
    implementation 'com.github.dozermapper:dozer-core:7.0.0'
}

✅ Nota: è buona pratica centralizzare la versione della libreria nel blocco properties di Maven o nel catalogo delle versioni di Gradle.

Primo mapping automatico tra Java Bean

Vediamo un esempio completo basato su un oggetto ClienteEntity e un oggetto ClienteDTO.

Classe sorgente: ClienteEntity

public class ClienteEntity {

    private Long id;
    private String nome;
    private String email;
    private Integer eta;

    public ClienteEntity() {
    }

    public ClienteEntity(Long id, String nome, String email, Integer eta) {
        this.id = id;
        this.nome = nome;
        this.email = email;
        this.eta = eta;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getEta() {
        return eta;
    }

    public void setEta(Integer eta) {
        this.eta = eta;
    }
}

Classe di destinazione: ClienteDTO

public class ClienteDTO {

    private Long id;
    private String nome;
    private String email;
    private Integer eta;

    public ClienteDTO() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public Integer getEta() {
        return eta;
    }

    public void setEta(Integer eta) {
        this.eta = eta;
    }

    @Override
    public String toString() {
        return "ClienteDTO{" +
                "id=" + id +
                ", nome='" + nome + '\'' +
                ", email='" + email + '\'' +
                ", eta=" + eta +
                '}';
    }
}

Creazione del Mapper

Nelle versioni moderne di Dozer il mapper può essere creato attraverso DozerBeanMapperBuilder.

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;

public class DozerExample {

    public static void main(String[] args) {

        Mapper mapper = DozerBeanMapperBuilder.buildDefault();

        ClienteEntity cliente = new ClienteEntity(
                10L,
                "Mario Rossi",
                "mario.rossi@example.com",
                38
        );

        ClienteDTO dto = mapper.map(cliente, ClienteDTO.class);

        System.out.println(dto);
    }
}

Dozer crea una nuova istanza di ClienteDTO e copia automaticamente tutte le proprietà compatibili che hanno lo stesso nome.

Mapping su un oggetto già esistente

È possibile utilizzare anche un oggetto di destinazione precedentemente creato:

ClienteDTO dto = new ClienteDTO();

mapper.map(cliente, dto);

🚫 Da evitare

Non creare un nuovo Mapper per ogni conversione. L’inizializzazione ha un costo e l’istanza dovrebbe normalmente essere riutilizzata.

Conversione automatica dei tipi

Dozer può effettuare diverse conversioni tra tipi compatibili. Una proprietà rappresentata come String nell’oggetto sorgente, ad esempio, può essere convertita in Integer nell’oggetto di destinazione.

Oggetto sorgente

public class ProdottoRequest {

    private String codice;
    private String quantita;

    public ProdottoRequest() {
    }

    public String getCodice() {
        return codice;
    }

    public void setCodice(String codice) {
        this.codice = codice;
    }

    public String getQuantita() {
        return quantita;
    }

    public void setQuantita(String quantita) {
        this.quantita = quantita;
    }
}

Oggetto di destinazione

public class Prodotto {

    private String codice;
    private Integer quantita;

    public Prodotto() {
    }

    public String getCodice() {
        return codice;
    }

    public void setCodice(String codice) {
        this.codice = codice;
    }

    public Integer getQuantita() {
        return quantita;
    }

    public void setQuantita(Integer quantita) {
        this.quantita = quantita;
    }
}

Esecuzione della conversione

ProdottoRequest request = new ProdottoRequest();
request.setCodice("ABC-100");
request.setQuantita("15");

Prodotto prodotto = mapper.map(request, Prodotto.class);

System.out.println(prodotto.getQuantita()); // 15

Queste conversioni automatiche sono comode, ma l’input deve essere valido. Se quantita contenesse il valore "quindici", la conversione numerica potrebbe fallire.

🔎 Buona pratica: validare sempre i dati ricevuti dall’esterno prima di avviare il mapping.

Mapping XML con proprietà differenti

Il mapping implicito funziona quando le proprietà hanno lo stesso nome. Se una classe utilizza nomeCompleto e l’altra utilizza nominativo, occorre definire una regola esplicita.

Creiamo il file:

src/main/resources/dozer-mapping.xml

Configurazione XML aggiornata

<?xml version="1.0" encoding="UTF-8"?>

<mappings
    xmlns="http://dozermapper.github.io/schema/bean-mapping"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://dozermapper.github.io/schema/bean-mapping
        http://dozermapper.github.io/schema/bean-mapping.xsd">

    <mapping>
        <class-a>it.javaboss.model.ClienteEntity</class-a>
        <class-b>it.javaboss.dto.ClienteDTO</class-b>

        <field>
            <a>nomeCompleto</a>
            <b>nominativo</b>
        </field>
    </mapping>

</mappings>

Il mapper deve quindi essere inizializzato indicando il file XML:

Mapper mapper = DozerBeanMapperBuilder.create()
        .withMappingFiles("dozer-mapping.xml")
        .build();

Mapping implicito ed esplicito insieme

Per impostazione predefinita, l’attributo wildcard è attivo. Di conseguenza Dozer:

  • applica le corrispondenze dichiarate nel file XML;
  • continua a copiare automaticamente le altre proprietà con lo stesso nome.

Per copiare esclusivamente i campi dichiarati si può disattivare il comportamento automatico:

<mapping wildcard="false">
    <class-a>it.javaboss.model.ClienteEntity</class-a>
    <class-b>it.javaboss.dto.ClienteDTO</class-b>

    <field>
        <a>nomeCompleto</a>
        <b>nominativo</b>
    </field>
</mapping>

🔐 Caso d’uso: wildcard="false" è particolarmente utile quando si vuole impedire che nuove proprietà aggiunte all’entity vengano esposte automaticamente nel DTO.

Mapping di oggetti annidati

Dozer può accedere anche alle proprietà di oggetti annidati. Supponiamo che ClienteEntity contenga un oggetto Indirizzo, mentre il DTO esponga direttamente la città.

Classe Indirizzo

public class Indirizzo {

    private String via;
    private String citta;
    private String cap;

    public Indirizzo() {
    }

    public String getVia() {
        return via;
    }

    public void setVia(String via) {
        this.via = via;
    }

    public String getCitta() {
        return citta;
    }

    public void setCitta(String citta) {
        this.citta = citta;
    }

    public String getCap() {
        return cap;
    }

    public void setCap(String cap) {
        this.cap = cap;
    }
}

Proprietà nell’entity e nel DTO

// ClienteEntity
private Indirizzo indirizzo;

// ClienteDTO
private String citta;
private String codicePostale;

Mapping delle proprietà annidate

<mapping>
    <class-a>it.javaboss.model.ClienteEntity</class-a>
    <class-b>it.javaboss.dto.ClienteDTO</class-b>

    <field>
        <a>indirizzo.citta</a>
        <b>citta</b>
    </field>

    <field>
        <a>indirizzo.cap</a>
        <b>codicePostale</b>
    </field>
</mapping>

In questo modo il DTO può avere una struttura più semplice rispetto al modello di dominio.

Mapping di liste e collezioni

Dozer supporta il mapping di array, liste e set. Quando però si lavora con tipi generici, una soluzione semplice e facilmente leggibile consiste nel convertire esplicitamente ogni elemento della collezione.

Conversione di una lista con Stream

import java.util.List;

List<ClienteDTO> risultati = clienti.stream()
        .map(cliente -> mapper.map(cliente, ClienteDTO.class))
        .toList();

Su versioni di Java precedenti a Java 16 è possibile utilizzare Collectors.toList():

import java.util.List;
import java.util.stream.Collectors;

List<ClienteDTO> risultati = clienti.stream()
        .map(cliente -> mapper.map(cliente, ClienteDTO.class))
        .collect(Collectors.toList());

Collezioni annidate

Se entrambi gli oggetti contengono una proprietà generica compatibile, Dozer può determinare il tipo degli elementi:

public class OrdineEntity {

    private List<RigaOrdineEntity> righe;

    public OrdineEntity() {
    }

    public List<RigaOrdineEntity> getRighe() {
        return righe;
    }

    public void setRighe(List<RigaOrdineEntity> righe) {
        this.righe = righe;
    }
}
public class OrdineDTO {

    private List<RigaOrdineDTO> righe;

    public OrdineDTO() {
    }

    public List<RigaOrdineDTO> getRighe() {
        return righe;
    }

    public void setRighe(List<RigaOrdineDTO> righe) {
        this.righe = righe;
    }
}

È comunque indispensabile verificare il risultato con test automatici, soprattutto quando le collezioni contengono gerarchie, interfacce o tipi non facilmente deducibili.

Creare un Custom Converter

Le conversioni automatiche non possono coprire ogni possibile requisito. Quando è necessario applicare una logica personalizzata, Dozer permette di creare un converter.

Il seguente esempio converte un LocalDate in una data testuale nel formato italiano.

Implementazione del converter

import com.github.dozermapper.core.DozerConverter;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LocalDateStringConverter
        extends DozerConverter<LocalDate, String> {

    private static final DateTimeFormatter FORMATTER =
            DateTimeFormatter.ofPattern("dd/MM/yyyy");

    public LocalDateStringConverter() {
        super(LocalDate.class, String.class);
    }

    @Override
    public String convertTo(LocalDate source, String destination) {
        if (source == null) {
            return null;
        }

        return source.format(FORMATTER);
    }

    @Override
    public LocalDate convertFrom(String source, LocalDate destination) {
        if (source == null || source.isBlank()) {
            return null;
        }

        return LocalDate.parse(source, FORMATTER);
    }
}

Associazione del converter a un campo

<mapping>
    <class-a>it.javaboss.model.UtenteEntity</class-a>
    <class-b>it.javaboss.dto.UtenteDTO</class-b>

    <field
        custom-converter="it.javaboss.converter.LocalDateStringConverter">

        <a>dataNascita</a>
        <b>dataNascita</b>
    </field>
</mapping>

⚠️ Attenzione: un converter personalizzato deve gestire esplicitamente valori nulli, formati non validi e conversioni in entrambe le direzioni quando il mapping è bidirezionale.

Configurare Dozer con Spring Boot

In un’applicazione Spring Boot è consigliabile creare una sola istanza del mapper e registrarla come bean gestito dal container.

Configurazione Java

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DozerConfiguration {

    @Bean
    public Mapper dozerMapper() {
        return DozerBeanMapperBuilder.create()
                .withMappingFiles("dozer-mapping.xml")
                .build();
    }
}

Utilizzo in un service

import com.github.dozermapper.core.Mapper;
import org.springframework.stereotype.Service;

@Service
public class ClienteService {

    private final Mapper mapper;
    private final ClienteRepository clienteRepository;

    public ClienteService(
            Mapper mapper,
            ClienteRepository clienteRepository) {

        this.mapper = mapper;
        this.clienteRepository = clienteRepository;
    }

    public ClienteDTO trovaCliente(Long id) {

        ClienteEntity cliente = clienteRepository.findById(id)
                .orElseThrow(() ->
                        new ClienteNonTrovatoException(id));

        return mapper.map(cliente, ClienteDTO.class);
    }
}

Questa configurazione evita di inizializzare continuamente il mapper e rende più semplice sostituire Dozer in futuro con un’altra implementazione.

Testare il mapping con JUnit

Un mapping automatico deve essere trattato come qualsiasi altro componente applicativo: deve essere verificato con test.

Esempio con JUnit 5

import com.github.dozermapper.core.DozerBeanMapperBuilder;
import com.github.dozermapper.core.Mapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

class ClienteMappingTest {

    private Mapper mapper;

    @BeforeEach
    void setUp() {
        mapper = DozerBeanMapperBuilder.create()
                .withMappingFiles("dozer-mapping.xml")
                .build();
    }

    @Test
    void dovrebbeConvertireClienteInDto() {

        ClienteEntity cliente = new ClienteEntity(
                25L,
                "Anna Bianchi",
                "anna@example.com",
                41
        );

        ClienteDTO dto = mapper.map(
                cliente,
                ClienteDTO.class
        );

        assertEquals(25L, dto.getId());
        assertEquals("Anna Bianchi", dto.getNome());
        assertEquals("anna@example.com", dto.getEmail());
        assertEquals(41, dto.getEta());
    }

    @Test
    void dovrebbeGestireUnValoreNullo() {

        ClienteEntity cliente = new ClienteEntity(
                26L,
                "Luca Verdi",
                null,
                30
        );

        ClienteDTO dto = mapper.map(
                cliente,
                ClienteDTO.class
        );

        assertNull(dto.getEmail());
    }
}

I test dovrebbero verificare almeno:

  • proprietà con lo stesso nome;
  • proprietà rinominate;
  • oggetti annidati;
  • collezioni;
  • valori nulli;
  • converter personalizzati;
  • campi che non devono essere esposti;
  • conversioni non valide.

Errori comuni e relative soluzioni

1. Mancanza del costruttore senza argomenti

Dozer crea normalmente l’oggetto di destinazione tramite reflection. Una classe priva di costruttore accessibile senza parametri può provocare una MappingException.

public ClienteDTO() {
}

2. Il file XML non viene trovato

Verificare che il file sia presente nel classpath:

src/main/resources/dozer-mapping.xml

e che il nome utilizzato dal builder sia corretto:

.withMappingFiles("dozer-mapping.xml")

3. Proprietà non copiata

Controllare:

  • il nome dei getter e setter;
  • la visibilità dei metodi;
  • il tipo della proprietà;
  • il percorso dell’oggetto annidato;
  • la corrispondenza dichiarata nel file XML;
  • l’eventuale utilizzo di wildcard="false".

4. Conversione numerica non valida

Una stringa non numerica non può essere convertita automaticamente in Integer o Long. La validazione dovrebbe avvenire prima del mapping.

5. Mapping ricorsivo indesiderato

Le entity JPA possono contenere relazioni bidirezionali, come Cliente → Ordini → Cliente. È preferibile progettare DTO più semplici ed escludere le relazioni non necessarie.

6. Nuovi campi esposti automaticamente

Se la sicurezza o la stabilità del contratto API sono prioritarie, utilizzare mapping espliciti e wildcard="false".

Prestazioni e buone pratiche

Dozer esegue il mapping a runtime e utilizza reflection. Per questo motivo la configurazione e il contesto di utilizzo hanno un impatto importante.

🚀 Buone pratiche consigliate

  • creare una sola istanza del mapper;
  • registrarla come singleton o bean Spring;
  • eseguire il mapping ai confini dell’applicazione;
  • evitare conversioni inutili in cicli molto grandi;
  • non utilizzare il mapper per nascondere un modello mal progettato;
  • preferire mapping espliciti per dati sensibili;
  • aggiungere test per ogni conversione importante;
  • monitorare le prestazioni nei processi batch;
  • non affidarsi ciecamente alle conversioni automatiche;
  • documentare i file XML e i converter personalizzati.

In un normale endpoint REST la differenza potrebbe non essere significativa. In un processo che converte centinaia di migliaia di elementi, invece, un mapper basato su reflection può diventare un punto critico.

Migrare da Dozer 5 a Dozer 7

Le applicazioni legacy possono contenere configurazioni simili a questa:

Vecchia dipendenza

<dependency>
    <groupId>net.sf.dozer</groupId>
    <artifactId>dozer</artifactId>
    <version>5.4.0</version>
</dependency>

Nuova dipendenza

<dependency>
    <groupId>com.github.dozermapper</groupId>
    <artifactId>dozer-core</artifactId>
    <version>7.0.0</version>
</dependency>

Vecchia inizializzazione

Mapper mapper = new DozerBeanMapper();

Nuova inizializzazione

Mapper mapper = DozerBeanMapperBuilder.buildDefault();

Vecchio namespace XML

xmlns="http://dozer.sourceforge.net"

Namespace XML moderno

xmlns="http://dozermapper.github.io/schema/bean-mapping"

Controlli da effettuare durante la migrazione

  • aggiornare le coordinate Maven o Gradle;
  • modificare gli import da org.dozer a com.github.dozermapper.core;
  • sostituire l’inizializzazione diretta con il builder;
  • aggiornare namespace e schema dei file XML;
  • controllare eventuali converter personalizzati;
  • verificare l’integrazione con Spring;
  • eseguire nuovamente tutti i test di mapping;
  • controllare le conversioni di date, numeri ed enum;
  • valutare contestualmente la migrazione a un mapper più moderno.

Dozer, MapStruct o ModelMapper?

La scelta dipende dal tipo di progetto. Dozer può essere ragionevole per mantenere un’applicazione esistente, ma non rappresenta necessariamente la scelta migliore per un nuovo sviluppo.

Caratteristica Dozer MapStruct ModelMapper
Funzionamento Runtime e reflection Codice generato in compilazione Runtime e convenzioni
Controllo in compilazione Limitato Elevato Limitato
Prestazioni Inferiori al codice diretto Molto vicine al mapping manuale Dipendono dalla configurazione
Configurazione XML o API Interfacce e annotazioni API fluente e convenzioni
Uso consigliato Manutenzione di progetti esistenti Nuovi progetti con mapping stabile Mapping dinamico e prototipi

Perché valutare MapStruct

MapStruct genera in fase di compilazione normali metodi Java. Questo offre alcuni vantaggi:

  • assenza di reflection durante il mapping;
  • errori rilevati durante la compilazione;
  • codice generato facilmente ispezionabile;
  • buone prestazioni;
  • supporto per Java Bean e record;
  • integrazione con Spring.

Esempio equivalente con MapStruct

import org.mapstruct.Mapper;
import org.mapstruct.Mapping;

@Mapper(componentModel = "spring")
public interface ClienteMapper {

    @Mapping(
        target = "nominativo",
        source = "nomeCompleto"
    )
    ClienteDTO toDto(ClienteEntity cliente);
}

🧭 Quale scegliere?

Dozer è soprattutto una soluzione da conoscere per applicazioni legacy. Per un progetto nuovo e orientato alle prestazioni, MapStruct è generalmente una scelta più solida. ModelMapper può essere interessante quando si preferisce una configurazione dinamica a runtime.

Domande frequenti su Dozer

Dozer copia automaticamente tutte le proprietà?

In modalità implicita copia le proprietà compatibili che hanno lo stesso nome. Le proprietà con nomi differenti devono essere associate tramite XML, API Java o annotazioni.

Dozer esegue una copia profonda?

Dozer può mappare ricorsivamente oggetti annidati. Il risultato concreto dipende però dalla struttura delle classi, dalle regole configurate e dall’eventuale uso della copia per riferimento.

È possibile escludere una proprietà?

Sì. È possibile escludere campi specifici o utilizzare wildcard="false" per copiare soltanto le proprietà dichiarate esplicitamente.

Dozer può convertire una entity in un DTO?

Sì, ed è uno dei casi d’uso più comuni. È comunque consigliabile evitare di mappare indiscriminatamente tutte le relazioni JPA.

Dozer può mappare una lista?

Sì, supporta diverse conversioni tra array, liste e set. Per conversioni semplici è possibile anche utilizzare uno Stream e applicare il mapper a ogni elemento.

È necessario creare un mapper per ogni classe?

No. Una sola istanza di Mapper può gestire numerose coppie di classi e dovrebbe normalmente essere riutilizzata.

Dozer è thread-safe?

L’utilizzo previsto consiste normalmente nel configurare una singola istanza e riutilizzarla. La configurazione dovrebbe essere completata durante l’avvio dell’applicazione e non modificata durante le operazioni di mapping.

Dozer è ancora consigliato?

Può essere mantenuto in applicazioni esistenti, ma il progetto ufficiale non ne consiglia l’adozione per nuovi sviluppi. In questi casi è opportuno confrontarlo con MapStruct e ModelMapper.

Qual è la differenza tra Dozer e BeanUtils?

BeanUtils è principalmente una raccolta di utilità per lavorare con proprietà Java Bean. Dozer è invece progettato specificamente per definire mapping complessi tra tipi differenti, includendo conversioni, oggetti annidati e regole personalizzate.

Conclusioni

Dozer permette di ridurre il codice ripetitivo necessario per copiare dati tra Java Bean, entity e DTO. Il mapping implicito è semplice da utilizzare, mentre XML e converter personalizzati consentono di gestire nomi differenti, oggetti annidati e trasformazioni specifiche.

Quando si interviene su un’applicazione esistente, aggiornare le vecchie configurazioni a Dozer 7 può migliorare compatibilità e manutenzione. Per un progetto completamente nuovo, invece, è consigliabile valutare una soluzione attivamente mantenuta e capace di rilevare gli errori già durante la compilazione.

📌 In sintesi

Usa Dozer per comprendere o mantenere applicazioni legacy, riutilizza sempre la stessa istanza del mapper, proteggi i dati sensibili con mapping espliciti e valuta MapStruct prima di introdurre Dozer in un nuovo progetto.

Riferimenti tecnici:
repository ufficiale Dozer,
documentazione Dozer e
documentazione MapStruct.

Categorie: Java