getting class cast exception - java

i just want to pass sql query builder query in JPA like
public List<QueryBuilder[]> getQueryBuilder(String query) {
EntityManager em = getEntityManager();
try {
Query q = em.createNativeQuery(query);
List<QueryBuilder[]> queryBuilderList = (List<QueryBuilder[]>) q.getResultList();
return queryBuilderList;
} finally {
em.close();
}
}
the query
SELECT p.*,c.*,e.*,pmh.*,rk.*
FROM patient p, case1 c, episode e, personal_medical_history pmh, reproductive_history rh
WHERE c.Clinical_Stage = 'IA2'
AND c.Patient_Id = p.Patient_Id
AND e.Case_Id = c.Case_Id
AND pmh.Patient_Id = p.Patient_Id
AND rh.Patient_Id = p.Patient_Id
GROUP BY p.patient_Id
and on service i do somthing like
List<QueryBuilder[]> list = builderJpaController.getQueryBuilder(query);
for (QueryBuilder[] queryBuilders : list) {
for (QueryBuilder queryBuilder : queryBuilders) {
System.out.println("queryBuilder Value "+queryBuilder.getRace());
}
}
but i'm getting class cast exception by doing above code please help
below is the exception
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Lcom.medikm.entity.QueryBuilder;
at com.medikm.servlet.QueryBuilderServlet.getQueryJson(QueryBuilderServlet.java:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)

The problematic line is:
List<QueryBuilder[]> queryBuilderList = (List<QueryBuilder[]>) q.getResultList();
You are assuming that the untyped list returned by q.getResultList() is a list of QueryBuilder[]s. Actually it is an Object[]. However, this compiles because q.getResultList() has a raw return type, so the compiler can't tell that this is unsafe.
Then, when consuming the elements of the list, you attempt to cast an Object[] to a QueryBuilder[] - which can't be done.
It is very unlikely that the elements of rows returned by a query would themselves be QueryBuilder instances - they are much more likely to be "plain old" values, like Strings, numbers etc.
(I say "very unlikely" because I'm not familiar with JPA - I am just going off what I expect a persistence API to do)
You need to rethink your expectations of what you are trying to do here.
Note that even if the elements of the Object[] were instances of QueryBuilder, you can't cast a Superclass[] reference to a Subclass[] reference - there is no superclass/subclass relationship between array types.
You need to explicitly cast each of the individual elements:
Subclass[] castArray(Superclass[] arr) {
Subclass[] subclassArr = new Subclass[arr.length];
for (int i = 0; i < arr.length; ++i) {
subclassArr[i] = (Subclass) arr[i];
}
return subclassArr;
}

Related

Does the List<Object> returned by org.jooq.Query.getBindValues() contain type-safe objects - for each query parameter?

New to JOOQ.
Came across this post:
https://thoughts-on-java.org/hibernate-jooq-a-match-made-in-heaven/
`
SelectConditionStep<Record3<String, String, String>> jooqQuery =
ctx.select(AUTHOR.FIRSTNAME, AUTHOR.LASTNAME, BOOK.TITLE)
.from(AUTHOR)
.leftJoin(BOOK_AUTHOR).on(AUTHOR.ID.eq(BOOK_AUTHOR.AUTHORS_ID))
.leftJoin(BOOK).on(BOOK_AUTHOR.BOOKS_ID.eq(BOOK.ID))
.where(AUTHOR.FIRSTNAME.like("Thor%"));
Query q = em.createNativeQuery(jooqQuery.getSQL());
setBindParameterValues(q, jooqQuery);
private static void setBindParameterValues(javax.persistence.Query jpaQuery, org.jooq.Query jooqQuery) {
List<Object> values = jooqQuery.getBindValues();
for (int i = 0; i < values.size(); i++) {
jpaQuery.setParameter(i + 1, values.get(i));
}
}
`
The method jpaQuery.setParameter() itself is not-type-safe as it accepts 'Object'.
Question: Does jooqQuery.getBindValues() return List<Object> which are "type-safe for each-param"?
That method is the glue code the author of the blog post wrote to convert a jOOQ Query to a JPA Query. There is no type safety in this glue code. The type safety you are looking for was provided in other examples of the post, where the author constructed type safe queries using the jOOQ API, such as this:
// This stuff is type safe
var jooqQuery =
ctx.select(AUTHOR.FIRSTNAME, AUTHOR.LASTNAME, BOOK.TITLE)
.from(AUTHOR)
.leftJoin(BOOK_AUTHOR).on(AUTHOR.ID.eq(BOOK_AUTHOR.AUTHORS_ID))
.leftJoin(BOOK).on(BOOK_AUTHOR.BOOKS_ID.eq(BOOK.ID))
.where(AUTHOR.FIRSTNAME.like("Thor%"));
// This stuff isn't, and there is no need
Query q = em.createNativeQuery(jooqQuery.getSQL());
setBindParameterValues(q, jooqQuery);

Hibernate SQLQuery list method returns Object instead of object array

I have this strange behavior with Hibernate SQLQuery.list() method.
Following is the description of the issue:
I have a sql select query which retrieves only single column(group) from the database (i.e., select group from peopleGroup where groupid = 10)
And i'm recieving the result of the above list in List of Object array
i.e,
SQLQuery hQuery = session.createSQLQuery("select group from peopleGroup where groupid = 10");
List<Object[]> result = (List<Object[]>)hQuery.list();
Ideally, the result should contain a list of object arrays but when I inspect, 0'th index of the result contains String object instead of an Object array.
However if I use more than one column let's say 2 columns in the select clause of the query I was able to see that 0'th index of the result as Object array i.e., Object[2]={"group","groupid"};
How do I get the Object array even if I have only one column mentioned in the select clause of the query?
Docs states:
List list()
Return the query results as a List. If the query contains multiple
results per row, the results are returned in an instance of Object[].
Convert it by yourself, like so.
List<Object[]> l = new ArrayList<>();
for(Object o : query.list()) {
Object[] arr = {o};
l.add(arr);
}
you can create a object mapper like below code
public class QueryMapper {
private String group;
//setter and getter
}
And you have to change your code like below
SQLQuery hQuery = session.createSQLQuery("select group from peopleGroup where groupid = 10");
List<Object[]> result = (List<Object[]>)hQuery.list();
List<QueryMapper> list = new ArrayList<QueryMapper>();
for(Object[] object: result){
QueryMapper queryMapper = new QueryMapper();
if(object[0]!=null){
queryMapper.setGroup((String)object[2]);
}
list.add(queryMapper);
}
All i wanted is to fix the ClassCastException which was caught during the assignment of result.get(0) to the container i.e., container = result.get(0);
Since the value returned by mentioned list() method contains object in case of single column in the select clause of the query and i won't be allowed to cast from certain object to Object[](Object array).
Instead i have tried a work around like below
Already existing code
SQLQuery hQuery = session.createSQLQuery("select group from peopleGroup where groupid = 10");
List<Object[]> result = (List<Object[]>)hQuery.list();
Object[] container = result.get(0);
now i have put condition like below to decide how to assign value to the Object[]
SQLQuery hQuery = session.createSQLQuery("select group from peopleGroup where groupid = 10");
List<Object[]> result = (List<Object[]>)hQuery.list();
Object[] container = null;
if(result.get(0) instanceof Object[])
container = result.get(0);
else {
container = new Object[1];
container[0] = result.get(0);
}
The above solution seems working in my case !

Cannot be cast to [Ljava.lang.Object;

I wrote this code to set the a jTable to a model to suit the data that would be returned from my query. I am not sure why this is happening but I do have an example of the same code in use and it works perfectly.
Note: the query calls records from a table that is linked to another table.
Note: Some may say this is a duplicate question but I feel not becuase Ilooked at that question and non of the solutions helped me, I tried using the iterator instead but same error occurs.
Any suggestions.
This is the code
public void createModelsAndEquipmentTableModel(){
Query query = FinancialDBPUEntityManager.createQuery("SELECT t FROM Stocktbl t WHERE t.chemical = FALSE");
List<Object[]> results = query.getResultList();
String headings[] = {"Product ID", "Product Name", "Number In Stock", "Number Needs Replacing"};
Object data[][] = new Object[results.size()][headings.length];
int index = 0;
for(Object[] obj: results){// error occurs here.
data[index++] = obj;
}
DefaultTableModel model = new DefaultTableModel(data, headings);
tblquipment.setModel(model);
}
This is the Relevant portion of the stack trace:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException: GUIPac.Stocktbl cannot be cast to [Ljava.lang.Object;
at GUIPac.ViewStockInfo.createChemicalsTableModel(ViewStockInfo.java:53)
at GUIPac.ViewStockInfo.<init>(ViewStockInfo.java:30)
The query "SELECT t FROM Stocktbl t WHERE t.chemical = FALSE" will return Stocktbl objects.
When iterating over the ResultList this causes ClassCastExceptions.
I would recommend to use this createQuery-Method:
TypedQuery<Stocktbl> query = FinancialDBPUEntityManager.createQuery("SELECT t FROM Stocktbl t WHERE t.chemical = FALSE", Stocktbl.class);
and then resolve all compiler warnings and errors.
If you need an Object Array, you will have to produce it manually, when using JPA. Here is a pseudo-code for creating these Object Arrays:
for(Stocktbl stock : results){// no error occurs here anymore.
Object[] obj = new Object[] {stock.ProductId, stock.ProductName, stock.NumberInStock, stock.numberNeedsReplacing};
data[index++] = obj;
}
please change field names of Stocktbl stock to fit to your Stocktbl class
The getResultList()- method get back a List of List<Stocktbl> not of Object[].
In runtime there is no generic. But when you iterate over it the cast fails.

JPA query.getResultList()?

I use JPA 1.0:
Query query;
query = em.createNamedQuery("getThresholdParameters");
query.setParameter(1, Integer.parseInt(circleId));
List<Object[]> resultList = new ArrayList();
resultList = query.getResultList();
Here I get result as List<Object[]>, thus I have to type convert all the parameters of the row to their respective types which is cumbersome.
In JPA 2.0 there is TypedQuery which return an entity object of type one specifies.
But as I am using JPA 1 I can't use it.
How to get result as Entity object of type I want??
EDIT:
QUERY
#Entity
#Table(name="GMA_THRESHOLD_PARAMETERS")
#NamedQuery(
name = "getThresholdParameters",
query = "select gmaTh.minNumberOc, gmaTh.minDurationOc, gmaTh.maxNumberIc, gmaTh.maxDurationIc, gmaTh.maxNumberCellId,"
+ "gmaTh.distinctBnumberRatio, gmaTh.minPercentDistinctBnumber from GmaThresholdParameter gmaTh "
+ "where gmaTh.id.circleId=?1 AND gmaTh.id.tspId=?2 AND gmaTh.id.flag=?3 "
)
Your query selects many fields. Such a query always returns a list of Object arrays. If you want a list containing instances of your GmaThresholdParameter entity, then the query should be
select gmaTh from GmaThresholdParameter gmaTh
where gmaTh.id.circleId=?1 AND gmaTh.id.tspId=?2 AND gmaTh.id.flag=?3
The code to get the list of entities would then be
List<GmaThresholdParameter> resultList = query.getResultList();
You'll get a type safety warning from the compiler, that you can ignore.
I can't respond to this as a comment so I'll just go ahead and make it an answer.
List<Object[]> resultList = new ArrayList(); // CREATE an empty ArrayList object
resultList = query.getResultList(); // getResultList ALSO returns its own ArrayList object
And since you assign the list that getResultList() returns to the same variable as you used for your own empty ArrayList, your application loses any connection to your own empty ArrayList and Java will collect it as garbage. Essentially you created it for absolutely no purpose.
what JB Nizet posted is enough.
List<GmaThresholdParameter> resultList = query.getResultList();
I have done something similar since I was using JPA 1 at that time:
final Collection<YourType> typedResult = new ArrayList<YourType>
for(final Object result : query.getResultList())
{
typedResult.add((YourType) result);
}
return typedResult;
List<GmaThresholdParamerter> result= query.getResultList();
for( GmaThresholdParamerter res : result)
{
System.out.println("" +res.getMinNumberOc());
System.out.println("" +res.getMinDurationOc());
}

How to get attributes of an Object in Java?

I have a function that returns an Object
The toString() method shows that my object has two BigDecimal attributes. But I don't know how to get them in the code ?
My function uses hibernate to get results from a query is :
public Object executeQuery(final String sql) {
final Query query = getSessionFactory().getCurrentSession().createSQLQuery(sql);
return query.list().get(0);
}
Thank you.
-- Additional infos:
obj.getClass().getDeclaredFields(); // empty array []
obj.getClass().getName(); // [Ljava.lang.Object;
final BigDecimal b = (BigDecimal) obj[0]; //Compilation error: The type of the expression must be an array type but it resolved to Object
obj.getClass().getDeclaredFields() can help you. Generally learn reflection API. If you object bean you can also use Jackarta BeanUtils.
Judging from your comments, your Object is and Object array.
So you should first cast the result to an Object array:
Object[] obj = (Object[]) query.list().get(0);
Then, you should be able to access the first BigDecimal like that:
BigDecimal b = (BigDecimal) obj[0];
Probably, you want to add some exception handling.
It is not an Object, it is an Array of Objects.
BigDecimal firstColumn = (BigDecimal) ((Object[])query.list().get(0))[0];
BigDecimal secondColumn = (BigDecimal) ((Object[])query.list().get(0))[1];
That's all.
UPDATE:
You have a resultset with 2 columns.
Object[] result= query.list().get(0);
BigDecimal number1 = (BigDecimal) result[0];
BigDecimal number2 = (BigDecimal) result[1];
Get first what class name of that object by
System.out.println(obj.getClass());
Since you are running a sql query, result might be an Entity or Object[].
when you came to know retrieved object from query is an Object[] you can iterate like
if( obj instanceof Object[] ) {
Object[] objA = (Object[])obj;
for(Object atomicObj : objA ) {
System.out.println(atomicObj);
}
}
It works for all elements which presents in object array. This time you may get BigDecimal, next query might return a String and BigDecimal.

Categories