jeff
jeff

Reputation: 3742

JPA/Hibernate returning BigDecimal not Long

I'm computing a SUM grouped by months

Query q = entityManager.createNativeQuery(qlString);
q.setParameter("program", program);
@SuppressWarnings("unchecked")
List<Long> resultList = (List<Long>) q.getResultList();
long tend = System.currentTimeMillis();

When I pass in two resultsLists (closed:ResultsList of Closed items, closedLate: ResultsList of items Closed late) into a method that computes percentages, I get

 javax.servlet.ServletException: java.lang.ClassCastException: java.math.BigDecimal cannot be cast to java.lang.Long

.

private List<Long> computeOTR(List<Long> closed, List<Long> closedLate) {
    List<Long> monthlyOTR = new ArrayList<Long>();
    long numerator;
    Long denominator;
    for (int i = 0; i <11; i++) {
        numerator = closed.get(i) - closedLate.get(i); <----java.lang.ClassCastException
        denominator = closed.get(i);
        long percentage = (int)(numerator * 100.0 / denominator + 0.5);
        monthlyOTR.add(i, percentage);
    }
    return monthlyOTR;

}

In Eclipse debug mode closed is showing as BigDecimal. Why is this when I decalre

List<Long> resultList = (List<Long>) q.getResultList();

EDIT-Hibernate Query:

public List<Long> findClosedLateByProgram(String program) {

    long tstart = System.currentTimeMillis();
    //@formatter:off
    String qlString = "with PRJ as ( " +
            "select  trunc(END_DATE) as END_DATE,  " +
            "trunc(NEED_DATE) as NEED_DATE   " +
            "from (SELECT UNIQUE * FROM TEST where PROGRAM_NAME = :program " +
            "AND ACTION_BY_ORG = 'AAA') " +
            "),  " +
            "DATES as ( select add_months(trunc(last_day(SYSDATE)), level-7) as thedate  " +
            "from dual connect by level <= 12  )   " +
            "SELECT nvl(sum(case when NEED_DATE <  trunc(thedate,'mm') AND END_DATE between trunc(thedate,'mm') and thedate then 1 end), 0 ) as CLOSED_LATE  " +
            "FROM  DATES, PRJ  " +
            "GROUP BY thedate ORDER BY thedate";
    //@formatter:on

    Query q = entityManager.createNativeQuery(qlString);
    q.setParameter("program", program);
    // q.setParameter("today",date, TemporalType.DATE);

    @SuppressWarnings("unchecked")
    List<Long> resultList =  q.getResultList();
    long tend = System.currentTimeMillis();
    long elapsed = tend-tstart;
    System.out.println("Elapsed Time For Closed But Late: " + elapsed);
    return resultList;
}

EDIT 2

I think I am stuck with a BigDecimal? http://weblogs.java.net/blog/mb124283/archive/2007/04/java_persistenc.html

Upvotes: 12

Views: 26381

Answers (3)

LaurentM
LaurentM

Reputation: 71

I just faced the same problem.

One solution is to add scalar (https://stackoverflow.com/a/29479658).

But in my case (Spring data jpa with @Query annotation), I couldn't add it. One workaround is to get result list as a List <? extends Number> (superclass of Long and BigInteger)

Then you can call the Number's method longValue().

In java 8, your sample could become:

List<? extends Number> resultListAsNumber =  q.getResultList();
List<Long> resultList = resultListAsNumber.stream().map(i -> i.longValue()).collect(Collectors.toList());

This solution avoids String convertion and will work if one day hibernate returns Long.

Upvotes: 4

You should iterate over the results and convert the objects from String:

    Query query = createSQLQuery(sql);
    List<Long> ids = new java.util.ArrayList<Long>();
    java.util.Iterator res = query.list().iterator();

    try {
        while(res.hasNext()){
            ids.add(new Long(res.next().toString()));
        }
    } catch(Exception ex) {
        ex.printStackTrace();
    }

Upvotes: 0

Jon Skeet
Jon Skeet

Reputation: 1500635

You should already be getting a warning showing that your cast isn't really checking things fully. Type erasure means that at execution time, there's no difference between a List<Long> and a List<BigDecimal>. So the cast succeeds, and it's only the later implicit cast to Long which fails.

Basically you need to change your query to make sure it creates Long values instead.

Upvotes: 4

Related Questions