Solving NotYetImplementedException with Native Queries in Spring Boot JPA/Hibernate

If you have ever tried to project only a subset of columns from a native SQL query in Spring Boot with Hibernate, you may have encountered this cryptic error: org.hibernate.query.sqm.internal.SqmUtil$NotYetImplementedException or Pure native scalar queries are not yet supported. It is one of the more confusing Hibernate error messages because the fix is not obvious from the stack trace. This post explains exactly what causes it, shows you three clean solutions, and recommends the right approach for each scenario.

Root Cause

When you write a native query that returns only some columns — not a full entity row — and try to map it to a non-entity class (like a DTO or an interface projection), Hibernate’s native query engine cannot automatically match scalar columns to a custom type. Starting from Hibernate 6 / Spring Boot 3, this scenario throws a NotYetImplementedException or similar error if your mapping strategy is not explicit.

// THIS CAUSES THE ERROR in Hibernate 6+
@Query(value = "SELECT id, name, email FROM users WHERE active = true",
       nativeQuery = true)
List<UserSummary> findActiveSummaries();  // UserSummary is a DTO, not an entity

Solution 1 — Interface-Based Projection (Recommended)

Define a Java interface with getter methods matching the query column aliases. Spring Data JPA / Hibernate maps scalar values to the interface automatically:

// 1. Define the projection interface
public interface UserSummary {
    Long   getId();
    String getName();
    String getEmail();
}

// 2. Use it in the repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Query(value = "SELECT id, name, email FROM users WHERE active = :active",
           nativeQuery = true)
    List<UserSummary> findActiveSummaries(@Param("active") boolean active);
}

// 3. Call from service
@Service
public class UserService {
    @Autowired UserRepository repo;

    public List<UserSummary> getActiveSummaries() {
        return repo.findActiveSummaries(true);
    }
}

Column aliases must match the getter names. If your getter is getName() the SQL alias must be name (case-insensitive). Rename columns with AS if they differ:

@Query(value = "SELECT u.id, u.first_name AS name, u.email_address AS email " +
               "FROM users u WHERE u.active = true",
       nativeQuery = true)
List<UserSummary> findActiveSummaries();

Solution 2 — @SqlResultSetMapping + @NamedNativeQuery

For complex result mappings, use JPA’s @SqlResultSetMapping annotation on your entity to tell Hibernate exactly how to map each column to a constructor argument:

// 1. DTO with an all-args constructor
public class UserSummaryDto {
    private final Long   id;
    private final String name;
    private final String email;

    public UserSummaryDto(Long id, String name, String email) {
        this.id    = id;
        this.name  = name;
        this.email = email;
    }
    // getters...
}

// 2. Declare the mapping on the entity
@Entity
@Table(name = "users")
@SqlResultSetMapping(
    name  = "UserSummaryMapping",
    classes = @ConstructorResult(
        targetClass = UserSummaryDto.class,
        columns = {
            @ColumnResult(name = "id",    type = Long.class),
            @ColumnResult(name = "name",  type = String.class),
            @ColumnResult(name = "email", type = String.class)
        }
    )
)
@NamedNativeQuery(
    name            = "User.findActiveSummaries",
    query           = "SELECT id, name, email FROM users WHERE active = true",
    resultSetMapping = "UserSummaryMapping"
)
public class User { /* fields */ }

// 3. Call via EntityManager
@Repository
public class UserDao {
    @PersistenceContext EntityManager em;

    @SuppressWarnings("unchecked")
    public List<UserSummaryDto> findActiveSummaries() {
        return em.createNamedQuery("User.findActiveSummaries").getResultList();
    }
}

Solution 3 — JPQL Constructor Expression (Avoid Native Query Entirely)

If you don’t truly need native SQL, a JPQL constructor expression avoids the issue completely and is fully portable across databases:

// DTO constructor
public record UserSummaryDto(Long id, String name, String email) {}

// Repository with JPQL constructor expression
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT new com.ankurm.dto.UserSummaryDto(u.id, u.name, u.email) " +
           "FROM User u WHERE u.active = :active")
    List<UserSummaryDto> findActiveSummaries(@Param("active") boolean active);
}

Solution Comparison

ApproachNative SQL?BoilerplateBest For
Interface projectionYesMinimalMost native query projections
@SqlResultSetMappingYesHighComplex multi-join native results
JPQL constructor expressionNoLowStandard projections, portable SQL

See Also

Conclusion

The NotYetImplementedException or “pure native scalar queries are not yet supported” error means Hibernate does not know how to map your native query’s scalar result columns to the target type. The fastest fix is switching to an interface-based projection — just define an interface with matching getters and Spring Data will handle the rest. For complex cases use @SqlResultSetMapping with @ConstructorResult. When native SQL is not strictly necessary, a JPQL constructor expression is the cleanest and most portable solution.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.