I'm trying to map my entity to projection using the below query but i'm getting error as
Exception : could not extract ResultSet SQL [n/a]; nested exception is org.hibernate.exception.SQLGrammarException: could not extract ResultSet
here is the query
#Query("select rf.rfqID as rfqID,rf.creationDate as creationDate," +
"rf.deadLineDate as deadLineDate,rf.details as details," +
"rf.message as message, rf.rfqDoc as rfqDoc," +
"CASE WHEN (rf.creationDate > CURRENT_DATE) THEN 'open' ELSE 'closed' END as status," +
"rf.rfqMembers as rfqMembers " +
"from RFQ rf where rf.createdBy = ?1")
Page<RfqDto> loadAllRfq(String creator, Pageable pageable);
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
here is my projection interface
public interface RfqDto {
String rfqID();
Date creationDate();
Date deadLineDate();
String details();
String message();
String rfqDoc();
String status();
List<RfqMember> rfqMembers();
}
The root cause of your problem is here:
In my Dto I have an extra status column which I don't want to persist in db and would like to get the status via query
As it's explained in the documentation:
The important bit here is that the properties defined here exactly match properties in the aggregate root.
...
The query execution engine creates proxy instances of that interface at runtime for each element returned and forwards calls to the exposed methods to the target object.
So, you can not use spring data jpa projection for your case. You can not use hibernate/jpa projection as well, because it dose not support collections in row results.
You can try to use Blaze-Persistence Entity Views. See for example this answer.
Related
I am facing Second Order SQL Injection in the Spring-Hibernate application after scanning through the Checkmarx tool, I have gone through multiple questions in StackOverflow and in other platforms as well but did not get the right finding.
could you please look into the below code snip,
public String getOrderId(order_name){
String returnId= null;
Query query = entityManager.createNativeQuery("select order_id from order where order_name=?");
List<String> dataset = query.setParameter(1,order_name).getResultList();
if(dataset!=null){
returnId = dataset. Get(0);
}
return returnId;
}
In this above method, while calling getResultList(), getting a high vulnerability issue that, this method returns data flows through the code without being properly sanitized or validated, and eventually used in further database query in the method.
Earlier code was like this,
public String getOrderId(order_name){
String returnId= null;
String q = "select order_id from order where order_name="+order_name;
Query query = entityManager.createNativeQuery(q);
and directly it was used as a string append in query, which I have modified with set parameter,
Query query = entityManager.createNativeQuery("select order_id from order where order_name=?");
List<String> dataset = query.setParameter(1,order_name).getResultList();
but still after getting data from query.getResultSet(), it is asking for sanitizing and validating the data before use in further database query method.
and this return data is being used in further query like select * from return_Data where clause. (properly used in where clause to set parameter to avoid SQL injection).
and in the above query is used in another method where we pass return_Data as input to it.
could you please help here to know what checks and validation can be added to overcome this type of issue. Thanks in advance for prompt response.
I have a repository which request my database, but in a particular case, I would like it to get data from a JSON (which have the same structure than my entity).
I've tried :
AOP : before each repository methods, if we are in the particular case, I get the data from a JSON and I can cast it to the correct class (because with AOP i can get the return type of the method). So it's working for methods like :
#Query("SELECT e FROM entity e WHERE e.name = :name")
Entity getAllEntities(String name);
but not with methods like ...
#Query("SELECT n.attribute FROM entity e, nested n WHERE e.name = :name")
String getNestedAttribute(String name);
... because I can't figure out where I could find the data in JSON. Except if you know how I could get the path (for exemple : $['entity']['nested'][0]['attribute']) from an SQL query so I can use this library
Repository populator
On application startup, it replace the data in the database with the value I store in JSON. The problem with it is that I don't want to loose my data ...
I know this post is weird but I don't want to add those data in my database because it would affect to much application ...
I am using Spring Data JPA criteria builder greaterThan API for doing a comparison.
The database field rating is of type NUMBER(5,0). Entity class has a field rating which is of type Integer. And I am passing the value of type String for the comparison.
Even though I am not passing the Integer value for the comparison, still it is returning valid results. Please help me understand how this is possible.
Does it mean, I can pass the java String version of the database field to the greaterThan method when the actual data type of the field in the database is of a different type.
and my comparison block of code looks like this
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
Root<Customer> root = cq.from(Customer.class);
//you can see here , value 20 I am passing as String
Predicate comparisonPredicate = cb.greaterThan(root.get("rating"), "20");
cq.where(comparisonPredicate );
cq.select(root);
TypedQuery<Customer> query = entityManager.createQuery(cq);
This behavior is not documented.
Looking at the openJPA source code for Expressions.GreaterThan, and more specifically the toKernelExpression,
#Override
org.apache.openjpa.kernel.exps.Expression toKernelExpression(ExpressionFactory factory, CriteriaQueryImpl<?> q){
Value val1 = Expressions.toValue(e1, factory, q);
Value val2 = Expressions.toValue(e2, factory, q);
Expressions.setImplicitTypes(val1, val2, e1.getJavaType(), q);
return factory.greaterThan(val1, val2);
}
JPA uses the type of the first expression to build the query.
This behavior looks to be an accidental feature more than an intentional implementation. You should not rely on this and should explicitly cast the variable. You could also use a MetaModel to get a compiler error when trying to compare apples to oranges.
I've got a bit of a bizarre problem that I can't figure out why it's happening. I'm sure I did something wrong, because this is my first time using a data projection and I've never had such problems using DTOs.
Pretty much I have a SELECT statemen that is returning certain columns of various data types. And I have an interface that I'm passing to the JPA Repository so it can do the interface mapping. But instead of mapping the results based on the column name (eg. 'accountnum' -> getAccountnumber()), it's mapping the columns in alphabetical order. So if 'date_of_order' is the first in the SELECT statement, its value will be returned by getAccountnumber().
I have a projected interface that looks something like this:
public interface FlatSearchResult {
String getAccountnumber();
UUID getTrackingId;
Date getDateOfOrder;
}
My model has three tables something like this:
ACCOUNT
- account_id : uuid (pkey)
- accountnumber : string
ORDERS
- order_id : uuid (pkey)
- date_of_order : timestamp
- account_id : uuid (fkey)
TRACKING
- tracking_id : uuid (pkey)
- order_id : uuid (fkey)
There's other columns in each of those tables, but they're not relevant.
I have a repository defined with a simple query:
public interface OrderTrackingRepository extends JpaRepository<Account, UUID> {
#Query( nativeQuery = true,
value = "SELECT o.date_of_order, a.accountnumber, t.tracking_id " +
"FROM account as a " +
"INNER JOIN orders as o USING (account_id) " +
"INNER JOIN tracking as t USING (tracking_id) " +
"WHERE a.accountnumber = :acctnum")
<T> Collection<T> findOrderInfoForAccount(#Param("acctnum") acctNumber, Class<T> type);
}
When I call this method, the correct rows are returned by the query. But instead of mapping using the column name (eg. date_of_order to getDateOfOrder()), it is mapping based on the order of the columns in the SELECT statement to the alphabetically-ordered methods in the interface.
So:
SELECT date_of_order, accountnumber, tracking_id
Results in:
getAccountNumber() -> date_of_order
getDateOfOrder() -> accountnumber
getTrackingId() -> tracking_id
It will consistently return in this fashion, so it's not a transient issue.
As a temporary workaround, I've reordered the columns in my SELECT statement. But I would rather not have to do this since it's like iterating through a result set and relying on column position, which just makes me twitchy....
How can I get Spring JPA to map from the result set to my interface? Do I need to annotate my projection interface's methods with something to tell Spring what column name it's referring to?
My database is Postgres. I'm using Spring 5.0.2.RELEASE and Spring-Boot 2.0.0.M7. I can adjust either of those to newer versions if needed, but nothing older. I'm using C3P0 0.9.5.2 for my connection pooling, and postgres-9.2-1002.jdbc4. All my other dependencies (hibernate, etc) are what is pulled in by this version of Spring-Boot.
Not sure if this is the correct solution because it only fits 80% of the description. But it is too long for a comment. So here we go.
I think you misunderstood #osamayaccoub or the documentation. Your property name is fine. But the columns in your select should match the java convention.
So the first attempt to fix that would be
value = "SELECT o.date_of_order as dateOfOrder, a.accountnumber as accountNumber, t.tracking_id as trackingId "
Note: This might actually work, but might break later, so read on, even if it does work
But Postgres converts everything that isn't double quoted into lower case (Oracle and MySql do similar stuff though details vary, don't know about other DBs yet). So you really should use:
value = "SELECT o.date_of_order as \"dateOfOrder\", a.accountnumber as \"accountNumber\", t.tracking_id as \"trackingId\" "
This probably doesn't work, because the Hibernate version you are using has a bug in that it converted everything to lower case.
So you should upgrade to the latest Hibernate version 5.3.13 which has the issue fixed.
This bug fix interestingly might break the version without the double quotes.
But it should work again with this PR for this Spring Data JPA issue.
The part I don't understand is, why stuff gets assigned using the column order.
I had the same problem and i solved by odering the query columns alphabetically.
In you case:
public interface OrderTrackingRepository extends JpaRepository<Account, UUID> {
#Query( nativeQuery = true,
value = "SELECT a.accountnumber, o.date_of_order, t.tracking_id " +
"FROM account as a " +
"INNER JOIN orders as o USING (account_id) " +
"INNER JOIN tracking as t USING (tracking_id) " +
"WHERE a.accountnumber = :acctnum")
<T> Collection<T> findOrderInfoForAccount(#Param("acctnum") acctNumber, Class<T> type);
}
So you will get:
getAccountNumber() -> accountnumber
getDateOfOrder() -> date_of_order
getTrackingId() -> tracking_id
Hibernate sorts the query in alphabetic order so you have to change the select to: "SELECT a.accountnumber, o.date_of_order, t.tracking_id ..." and the interface's getters should follow the same alphabetic order.
I am getting this given exception
Exception in thread "Thread-2" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.freeGo.model.Pump at com.freeGo.util.HealthTask.run(HealthTask.java:33) at java.lang.Thread.run(Thread.java:745)
My code is :
#Query("SELECT p.id, p.timestamp FROM Pump p WHERE p.isActive = :isActive")
public List<Pump> findByIsActive(#Param("isActive") int isActive);
if i don't use Query annotation as
public List<Pump> findByIsActive(#Param("isActive") int isActive);
then it's run successfully, but it return's all table data but i want only 2 column.
My project in spring-3 and jpa.
There is nothing wrong with the query, if that's what you want. You will be getting a object[] (object array) from the query instead of a List<Pump>. So, make the return type List<Object[]> and get id in column 0 and time in column 1.
If you want to make it a little better code, you should probably get the query to return a custom DTO.
#Query("SELECT new MyDto(p.id, p.timestamp) FROM Pump p WHERE p.isActive = :isActive")
and return a List<MyDto>
Reference: Spring JPA selecting specific columns