Spring Data JPA: How can Query return Non- Entities Objects or List of Objects?

We can also parse using JSON help.

Class level declaration.

@Autowired
private EntityManager em;
private ObjectMapper mapper = new ObjectMapper(); 

Main Code.

Query query = em.createNativeQuery(argQueryString);
NativeQueryImpl nativeQuery = (NativeQueryImpl) query;
nativeQuery.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);
List<Map<String,Object>> result = nativeQuery.getResultList();
List<CustomStudent> resultList = result.stream()
   .map(o -> {
         try {
              return 
            mapper.readValue(mapper.writeValueAsString(o),CustomStudent.class);
       } catch (Exception e) {
           ApplicationLogger.logger.error(e.getMessage(),e);
       }
     return null;
    }).collect(Collectors.toList());

I was deeply surprised when I came accross this for the first time but, yes, you can map query results using @SqlResultSetMapping only to scalars and managed entities.

The best you can do, I guess, is to skip automatic mapping. Query without mapping would return List<Object[]> and you can map it the way you need.

Another approach would be to use @MappedSuperclass. The class denoted as @MappedSuperclass (CustomStudent in your case) can be (not sure 100%, though) used in @SqlResultSetMapping. but you need to introduce inheritance hierarchy, that is your Student entity must extend CustomStudent. That would suck most of the time from the proper OO design, because inheritance would be a little bit artificial...


How about JPA 2.1 ConstructorResult ?

@SqlResultSetMapping(
    name="studentPercentile",
    classes={
        @ConstructorResult(
            targetClass=CustomStudent.class,
            columns={
                @ColumnResult(name="ID"),
                @ColumnResult(name="FIRST_NAME"),
                @ColumnResult(name="LAST_NAME")
            }
        )
    }
)

@NamedNativeQuery(name="findStudentPercentile", query="SELECT * FROM STUDENT", resultSetMapping="studentPercentile")

You can do something like

@NamedQuery(name="findWhatever", query="SELECT new path.to.dto.MyDto(e.id, e.otherProperty) FROM Student e WHERE e.id = ?1")

Then the MyDto object would just need a constructor defined with the correct fields i.e.

public MyDto(String id, String otherProperty) { this.id = id; this.otherProperty = otherProperty; }