2

The objects in my resultset are being cast to 'Object' instead of what I specified in the @SQLResultSetMapping objects.

I'm trying to get a handle on ConstructorResult and have created a query which contains a simple join and am trying to get the result set and loop though it printing it out to make sure I have it right. However when I get to the loop what looks like it should be straight forward isn't.

When I declare the result list it is cast to be of type . I step through the query test class and it successfully runs the query and loads it into the result, but the items in the results list have typed as 'Object' rather than CommentInfoListItemDTO objects. So when I get to the loop, it hits a class cast exception. Why wouldn't the result be cast to CommentInfoListItemDTO objects? Especially when this is specificied in the @SQLResultSetMapping.

The code is posted below... I truncated some of the column names just to shorten them up. If it would help to add it back in let me know.

public List<CommentInfoListItemDTO> getCommentTitleListByPersonId(BigInteger personId) {
    String queryString = "select c.article_id, "
                        ***[columns removed for brevity]***
                        + "c.person_id as comment_person_id, "
                        + "a.party_id as aticle_party_id "
                        + "from article_comment c "
                        + "join article a "
                        + "on a.article_id = c.article_id "
                        + "where c.person_id = :personId";

    Query q = em.createNativeQuery(queryString, "CommentInfoListItemDTOMapping");
    q.setParameter("personId", personId);

    List<CommentInfoListItemDTO> commentInfoList = q.getResultList();

    ***[throws exception on the next line]***
    ***[java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com...CommentInfoListItemDTO]***

    for (CommentInfoListItemDTO listElement : commentInfoList){
            System.out.println("COMMENT TITLE LIST: " + listElement.toString());
        }
    return (commentInfoList);
}

@SqlResultSetMapping --

EDITED -- to show how this was placed in an existing entity class.

EDITED -- I tried adding the data types to the column listing in the mapping. It didn't help. Each record in the resultset is still being cast to java.lang.Object somewhere inside Hibernate and it won't let me cast it back to the DTO. The resultsetmapping is being bound by Hibernate:

INFO: Binding resultset mapping: CommentInfoListItemDTOMapping

@Entity
@SqlResultSetMapping(name = "CommentInfoListItemDTOMapping", classes = {
    @ConstructorResult(targetClass = CommentInfoListItemDTO.class,
            columns = {
            @ColumnResult(name = "article_id", type=BigInteger.class),
            @ColumnResult(name = "article_comment_id", type=BigInteger.class),
            @ColumnResult(name = "parent_comment_id", type=BigInteger.class),
            @ColumnResult(name = "article_title", type=String.class),
            @ColumnResult(name = "article_published", type=Boolean.class),
            @ColumnResult(name = "article_publish_date", type=Calendar.class),
            @ColumnResult(name = "article_availability_state", type=String.class),
            @ColumnResult(name = "article_enable_comments", type=Boolean.class),
            @ColumnResult(name = "comment_title", type=String.class),
            @ColumnResult(name = "comment_hide", type=Boolean.class),
            @ColumnResult(name = "comment_created_timestamp", type=Calendar.class),
            @ColumnResult(name = "comment_person_id", type=BigInteger.class),
            @ColumnResult(name = "aticle_party_id", type=BigInteger.class)
            })
})

@Table(name = "article_comment")
@NamedQueries({
    @NamedQuery(name = "ArticleComment.findAll", query = "SELECT e FROM ArticleComment e")})

public class ArticleComment implements Serializable {
...

POJO

public class CommentInfoListItemDTO implements Serializable {

    private Integer id;
    private BigInteger articleId;
    private BigInteger articleCommentId;
    private BigInteger parentCommentId;
    private String articleTitle;
    private Boolean articlePublished;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Calendar articlePublishDate;
    private String articleAvailabilityState;
    private Boolean articleEnableComments;
    private String commentTitle;
    private Boolean commentHide;
    @Temporal(javax.persistence.TemporalType.DATE)
    private Calendar commentCreatedTimestamp;
    private BigInteger commentPersonId;
    private BigInteger articlePartyId;

    public CommentInfoListItemDTO() {
    }

    public CommentInfoListItemDTO(BigInteger articleId, BigInteger articleCommentId, 
            BigInteger parentCommentId, String articleTitle, Boolean articlePublished, 
            Calendar articlePublishDate, String articleAvailabilityState, 
            Boolean articleEnableComments, String commentTitle, Boolean commentHide, 
            Calendar commentCreatedTimestamp, BigInteger commentPersonId, 
            BigInteger articlePartyId) {
        this.articleId = articleId;
        this.articleCommentId = articleCommentId;
        this.parentCommentId = parentCommentId;
        this.articleTitle = articleTitle;
        this.articlePublished = articlePublished;
        this.articlePublishDate = articlePublishDate;
        this.articleAvailabilityState = articleAvailabilityState;
        this.articleEnableComments = articleEnableComments;
        this.commentTitle = commentTitle;
        this.commentHide = commentHide;
        this.commentCreatedTimestamp = commentCreatedTimestamp;
        this.commentPersonId = commentPersonId;
        this.articlePartyId = articlePartyId;
    }

And finally a screengrab from the debugger showing the resultset as Objects rather than CommentInfoListItemDTO objects. The correct information is in the objects however.

And finally a screengrab from the debugger showing the resultset as Objects rather than CommentInfoListItemDTO objects.

Bill Rosmus
  • 2,941
  • 7
  • 40
  • 61
  • Does your `@SqlResultSetMapping` is put on `CommentInfoListItemDTO`? If yes, then put it on (any) `@Entity` class so the JPA provider can pick it up. – zbig Oct 15 '14 at 14:04
  • I didn't put the @SqlResultSetMapping on the CommentInfoListItemDTO . I edited my question to show that I had added it to an existing entity. In the meantime I will create a database view and make an entity on that. I just want lighter weight way to do a join to return information I need. I don't always want to bring back every bit of info from joined tables in order to present it to the user... just a few select columns. A simple query resultset into an object shouldn't be this hard to figure out. Just frustrated. Kind of curious to know if others feel the same way. – Bill Rosmus Oct 15 '14 at 17:40
  • Your justification for DTOs is perfectly valid. – zbig Oct 16 '14 at 08:11
  • What is your version of Eclipselink? – zbig Oct 16 '14 at 08:11
  • @BillR I feel your pain. I spent days trying to figure something out, but no luck yet. – jeff Mar 13 '15 at 17:46
  • I brought back the data using MyBatis. It was simple to use/set up. I have decided for quick look ups this is simpler to use than JPA. I'll continue to use JPA for the lion's share, but MyBatis for presentation data that JPA makes a pain in the ass to retrieve – Bill Rosmus Apr 08 '15 at 18:20

1 Answers1

0

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to YourDTO

is thrown when the EclipseLink can't find the name of YourDTO passed to the

em.createNativeQuery("SELECT...","YourDTO");

The exception thrown by Hibernate in similar situation is:

org.hibernate.MappingException: Unknown SqlResultSetMapping [someNonExistingMappingName]

You have to ensure that YourDTO is registered by your persistence provider. How? Observe your logs:

Hibernate:

DEBUG annotations.ResultsetMappingSecondPass - Binding result set mapping: YourDTO

EclipseLink: I didn't find any logs for that.

One additional remark to your mapping: Use @ColumnResult with type for ambiguous types:

@ColumnResult(name = "article_publish_date", type=Calendar.class)
@ColumnResult(name = "article_id", type=BigInteger.class)
zbig
  • 3,830
  • 2
  • 29
  • 37
  • Thanks I'll check the logs and explicitly casting the column result listing. Using Hibernate 4.3.6. I wanted to use Eclipselink when I started this thing a year or so ago, but I use PostgreSQL and Eclipselink didn't play as well with it as Hibernate. – Bill Rosmus Oct 16 '14 at 17:33
  • Set the variable types as you suggested, but still no luck. Also Hibernate found the POJO. "INFO: Binding resultset mapping: CommentInfoListItemDTOMapping" I entered this as a bug with Hibernate. In the meantime, I might just start using MyBatis for these types of queries. It is much more straight forward once the configuration is done. – Bill Rosmus Oct 16 '14 at 23:55
  • The bug I filed with Hibernate was linked by someone there to an existing bug. So it might just be that. Hibernate ORM HHH-9445 JPA 2.1 ConstructorResult Causing ClassCastException https://hibernate.atlassian.net/browse/HHH-9445 – Bill Rosmus Oct 17 '14 at 17:53