Which Entity‑to‑DTO Mapping Is Fastest? Benchmark of 3 Approaches

By benchmarking manual mapping, MapStruct, and JPQL projection across simple and relational scenarios, the article shows that JPQL is slightly faster in raw tests, but the real performance impact stems from N+1 queries, making query strategy the key factor rather than the mapping technique itself.

LuTiao Programming
LuTiao Programming
LuTiao Programming
Which Entity‑to‑DTO Mapping Is Fastest? Benchmark of 3 Approaches

In modern Spring Boot projects, DTOs are commonly used to expose data, control API fields, decouple database and API structures, improve semantics, and optimize serialization. However, each query then requires a conversion between Entity and DTO, raising the question of which conversion method offers the best performance.

Three Main Mapping Strategies

Manual Mapping : Create DTOs with new in Java code.

MapStruct : Compile‑time generated mapper interfaces.

JPQL Projection : Construct DTOs directly in the query using SELECT new ….

Simple Scenario (No Relationships)

Entities: Book with fields id, name, author, releaseDate, numberOfPages, language. DTO: BookDTO with matching fields.

Implementation snippets:

public List<BookDTO> getBooksManual() {
    return repository.findAll()
        .stream()
        .map(book -> new BookDTO(book.getId(), book.getName(), book.getAuthor(),
                book.getReleaseDate(), book.getNumberOfPages(), book.getLanguage()))
        .toList(); // Java 16+
}
@Mapper(componentModel = "spring")
public interface BookMapper {
    List<BookDTO> booksToBookDTOs(List<Book> books);
}

public List<BookDTO> getBooksMapStruct() {
    return mapper.booksToBookDTOs(repository.findAll());
}
@Query("""
    SELECT new com.icoderoad.dto.BookDTO(
        b.id, b.name, b.author, b.releaseDate, b.numberOfPages, b.language)
    FROM Book b
""")
List<BookDTO> findAllAsDTO();

public List<BookDTO> getBooksJpql() {
    return repository.findAllAsDTO();
}

Performance after 100 requests (average time):

Manual: 11 ms

MapStruct: 10 ms

JPQL: 8 ms

Conclusion: The gap is tiny; JPQL is marginally faster but the difference is negligible.

Complex Scenario (With Publisher Relationship)

Added a Publisher entity (Many‑To‑One) and extended BookDTO with a nested PublisherDTO. Manual and JPQL implementations were updated to map the nested object.

First test (N+1 present) – 1000 books:

Manual: 472 ms

MapStruct: 494 ms

JPQL: 19 ms

The huge gap is caused by the N+1 problem: the lazy @ManyToOne triggers one query for the books and an additional query for each publisher, resulting in 1001 SQL statements. JPQL performs a single join‑fetch, avoiding N+1.

Eliminating N+1

Repository optimized with a join fetch:

@Query("SELECT b FROM Book b JOIN FETCH b.publisher")
List<Book> findAllWithPublisher();

Re‑tested performance (average over 100 requests):

Manual: 24 ms

MapStruct: 23 ms

JPQL: 19 ms

Now the differences are again minimal.

In‑Depth Analysis

The dominant factor is not the mapping technique but whether N+1 queries are triggered.

Key considerations: avoiding lazy loading that causes extra queries, loading full entities only when needed, and using JOIN FETCH appropriately.

JPQL advantages: direct projection reduces object creation and persistence‑context overhead.

JPQL drawbacks: tighter coupling to the repository layer and the need to update constructor signatures in queries.

MapStruct offers compile‑time safety and maintainability comparable to hand‑written code.

Final Recommendations

Simple CRUD: prefer MapStruct for clean, maintainable code.

Complex aggregation queries: JPQL projection gives the best raw performance.

Small projects: manual mapping is acceptable.

Large projects: combine MapStruct with JOIN FETCH to avoid N+1 while keeping maintainability.

Bottom line: If you chase ultimate speed, JPQL projection is slightly ahead; if you value maintainability, MapStruct is the optimal choice. However, without first addressing N+1 queries, any discussion about mapping speed is moot.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

PerformanceDTOSpring BootMapStructEntity MappingjpqlN+1
LuTiao Programming
Written by

LuTiao Programming

LuTiao Programming is a friendly community offering free programming lessons. We inspire learners to explore new ideas and technologies and quickly acquire job-ready skills.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.