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
| Approach | Native SQL? | Boilerplate | Best For |
|---|---|---|---|
| Interface projection | Yes | Minimal | Most native query projections |
| @SqlResultSetMapping | Yes | High | Complex multi-join native results |
| JPQL constructor expression | No | Low | Standard projections, portable SQL |
See Also
- Building a REST API with Spring Boot
- Hibernate 7 Hello World Example
- Mastering Hibernate 7 JPA Persistence Annotations
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.