0

I'm trying to map the results of a NativeQuery to a non-entity pojo, using SqlResultSetMapping and ConstructorResult

I'm using this StreetCity class, with result mapping:

@Data
@SqlResultSetMapping(name = "StreetCityResult", classes = {
        @ConstructorResult(targetClass = StreetCity.class, columns = {
                @ColumnResult(name = "street", type = String.class),
                @ColumnResult(name = "city", type = String.class) }) })
public class StreetCity {
    public String street;
    public String city;

    public StreetCity(String street, String city) {
        this.street = street;
        this.city = city;
    }
}

this is the function that performs the NativeQuery

public List<StreetCity> retrieveStreetCity(String zipCode, int houseNumber) {
        Query query = em.createNativeQuery(getLocationQuery(zipCode, houseNumber), "StreetCityResult");
        List<StreetCity> streetCityList = query.getResultList();
        return streetCityList;
    }

this is the query that should be excuted

public String getLocationQuery(String zipCode, int houseNumber) {
        String query = 
            "select straat.straatnaam as street, plaats.plaatsnaam as city " 
            + " from pcreeks "
            + " left join plaats on plaats.plaatsid = pcreeks.plaatsid "
            + " left join straat on straat.straatid = pcreeks.straatid "
            + " where (...) ";
        return query;
    }

but i'm still getting an Exception

2017-03-05T16:35:57.736+0100|Warning: javax.ejb.EJBException
Caused by: java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to nl.xxx.service.business.locations.entity.StreetCity

Edit: the error comes from the 2nd line of this code:

List<StreetCity> streetCityList = storage.retrieveStreetCity(zipCode, houseNumber);
streetCityList.get(0).getStreet();

Oracle has the exact same example in the javadoc, so what am i doing wrong?

Joost
  • 3,169
  • 2
  • 22
  • 40

1 Answers1

1

found two solutions, in both cases, StreetCity MUST be an @Entity

using @ConstructorResult, it also needs constructors.

solution 1, using @EntityResult instead of @ConstructorResult

@Data
@Entity
@SqlResultSetMapping(name = "StreetCityMapping", entities = @EntityResult(entityClass = StreetCity.class, fields = {
        @FieldResult(name = "street", column = "street"), @FieldResult(name = "city", column = "city") }))
public class StreetCity {
    @Id
    public String street;
    public String city;
}

solution 2, using @ConstructorResult, with constructors:

@Data
@Entity
@SqlResultSetMapping(name = "StreetCityMapping", classes = {
@ConstructorResult(targetClass =
 StreetCity.class, columns = {
 @ColumnResult(name = "street", type = String.class),
 @ColumnResult(name = "city", type = String.class) }) })
public class StreetCity {
    @Id
    public String street;
    public String city;

    public StreetCity() {
    }

    public StreetCity(String street, String city) {
      this.street = street;
      this.city = city;
    }
}

no other code changes needed, i guess solution 1 is the cleanest one