I have an exception like invalidDataAccessApiUsageException - spring

Here is the exception:
org.springframework.dao.InvalidDataAccessApiUsageException: Encountered array-valued parameter binding, but was expecting [java.lang.String (n/a)];
nested exception is java.lang.IllegalArgumentException: Encountered array-valued parameter binding, but was expecting [java.lang.String (n/a)]
Here is my Repository:
#Repository
public interface FirmRepository extends JpaRepository<Firm, Integer> {
Page<Firm> findAll(Pageable page);
List<Firm> findByParentFirm(Firm firm);
#Query(value = "FROM Firm WHERE name = :name")
Firm findByName(#Param("name") final String[] name);
}
Here is my Service:
/**
* Gets the Application type by name
*/
public Firm getFirmByName(final String[] name) throws ResourceNotFoundException, ForbiddenOperationException {
//LOGGER.debug("Getting the firm with name=[{}]", strings);
return firmRepository.findByName(name);
}
}

The following should work
#Query( "FROM Firm WHERE name in :names" )
List<Firm> findByName(#Param("names") List<String> firmNames);
You can convert the array to list as List<String> firmNames = Arrays.asList(names);

Related

How to assign a numeric value to a specific field in the JPA method name?

Let's say I have an entity Products that has an int number field:
#Entity
#Table(name = "products")
public class Product {
#Id
#GeneratedValue(generator = "inc")
#GenericGenerator(name = "inc", strategy = "increment")
private int id;
private int number;
public int getId() {
return id;
}
void setId(int id) {
this.id = id;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
And there is a repository extending JpaRepository:
#Repository
interface SqlProductRepository extends JpaRepository<Product, Integer> {
Optional<List<Product>> findProductsByNumberIs0(); //compile error
}
Here is the error I get when I start the app:
nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlProductRepository' defined in com.example.demo.adapter.SqlProductRepository defined in #EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.Optional com.example.demo.product.ProductRepository.findProductsByNumberIs0()! Reason: Failed to create query for method public abstract java.util.Optional com.example.demo.product.ProductRepository.findProductsByNumberIs0()! No property numberIs0 found for type Product!; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.Optional com.example.demo.product.ProductRepository.findProductsByNumberIs0()! No property numberIs0 found for type Product!
What can I do to get a list of products that has number field equal to 0 ?
This is not supported by query derivation, so you have to put in a little more work. The simplest variant is to provide a JPQL query in an annotation.
#Repository
interface SqlProductRepository extends JpaRepository<Product, Integer> {
#Query("select p from Product p where number = 0")
List<Product> someMethodName();
}
I removed the Optional wrapper since List already has a perfect representation of nothing: The empty list.
Try a slight variation on your method name and signature. You should be able to define your repository like this:
#Repository
interface SqlProductRepository extends JpaRepository<Product, Integer> {
List<Product> findProductsByNumber(int number);
}
And then if you want those products where number == 0, then you can call your repository's method, passing in 0 as the argument:
List<Product> products = sqlProductRepository.findProductsByNumber(0);
This also allows you the flexibility to call findProductsByNumber() with any arbitrary number for any other use case.
EDIT: the repository's method should return a List, but if no products matching your criteria are found, you will just end up with an empty list.

Spring Data: Query By Example and Converter

I have an entity:
import javax.persistence.Convert;
#Entity(name = "my_entity")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Convert(converter = StringListConverter.class)
private List<String> emails;
// next fields omitted...
}
Converter which is used by emails field in entity (typical implementation like LocalDateTimeConverter):
import javax.persistence.Converter;
#Converter
public class StringListConverter implements AttributeConverter<List<String>, String> {
private static final String SPLIT_CHAR = ";";
#Override
public String convertToDatabaseColumn(List<String> stringList) {
if (CollectionUtils.isNotEmpty(stringList)) {
return String.join(SPLIT_CHAR, stringList);
} else {
return null;
}
}
#Override
public List<String> convertToEntityAttribute(String string) {
if (StringUtils.isNotBlank(string)) {
return Arrays.asList(string.split(SPLIT_CHAR));
} else {
return Collections.emptyList();
}
}
}
(I store emails separated by semicolons in one column. StringListConverter do that conversion.)
And Spring Data repository:
import org.springframework.data.domain.Example;
public interface MyRepository extends JpaRepository<MyEntity, Long> {
default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
Example<MyEntity> example = Example.of(myEntity);
return findAll(example);
}
}
I use Query by Example mechanism from Spring Data. When I have fields without #Convert (like String name) it works. But when I have field with #Convert (AttributeConverter) like List<String> emails it causes InvalidDataAccessApiUsageException.
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc#company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc#company.com] did not match expected type [java.util.List (n/a)]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61) ~[spring-tx-5.2.1.RELEASE.jar:5.2.1.RELEASE]
...
Caused by: java.lang.IllegalArgumentException: Parameter value [abc#company.com] did not match expected type [java.util.List (n/a)]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.internal.QueryParameterBindingImpl.validate(QueryParameterBindingImpl.java:90) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
... 146 common frames omitted
(message is weird because I've tried search with that list: ["abc#company.com", "def#company.com"], but in message is only one email)
I've tried to implement transform in ExampleMatcher:
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
public interface MyRepository extends JpaRepository<MyEntity, Long> {
default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("emails",
match -> match.transform(emailsOptional -> {
if (emailsOptional.isPresent()) {
List<String> emails = (List<String>) emailsOptional.get();
return Optional.ofNullable(new StringListConverter().convertToDatabaseColumn(emails));
}
return emailsOptional;
}));
Example<MyEntity> example = Example.of(myEntity, matcher);
return findAll(example);
}
}
But is causes InvalidDataAccessApiUsageException too, but with different message than previous one (there are two emails that I've set):
org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [abc#company.com;def#company.com] did not match expected type [java.util.List (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [abc#company.com;def#company.com] did not match expected type [java.util.List (n/a)]
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:374) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:257) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:528) ~[spring-orm-5.2.1.RELEASE.jar:5.2.1.RELEASE]
Caused by: java.lang.IllegalArgumentException: Parameter value [abc#company.com;def#company.com] did not match expected type [java.util.List (n/a)]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:54) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
at org.hibernate.query.spi.QueryParameterBindingValidator.validate(QueryParameterBindingValidator.java:27) ~[hibernate-core-5.4.8.Final.jar:5.4.8.Final]
... 146 common frames omitted
It seems that for some reason Hibernate is trying to split the array of emails into multiple conditions just like in IN query in SQL using expandListValuedParameters method.
Note - with your solution doing query like findAllByEmailsIn(List<String> emailsList) also won't work.
Method expandListValuedParameters is deprecated since Hibernate 5.2, so it may contains some problems and for sure will be implemented differently in Hibernate 6.0.
I haven't found a fix for your problem, but there are some workarounds:
Wrap your List<String> emails in another class
Wrapper class:
public class EmailList {
private List<String> emails;
// getters, setters, constructors ommited
}
Updated model class:
import javax.persistence.Convert;
#Entity(name = "my_entity")
public class MyEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#Convert(converter = StringEmailListConverter.class)
private EmailList emailList;
// next fields omitted...
}
Updated converter class:
import javax.persistence.Converter;
#Converter
public class StringEmailListConverter implements AttributeConverter<EmailList, String> {
private static final String SPLIT_CHAR = ";";
#Override
public String convertToDatabaseColumn(EmailList emailList) {
if (emailList != null && CollectionUtils.isNotEmpty(emailList.getEmails())) {
return String.join(SPLIT_CHAR, emailList.getEmails());
} else {
return null;
}
}
#Override
public EmailList convertToEntityAttribute(String string) {
if (StringUtils.isNotBlank(string)) {
return new EmailList(Arrays.asList(string.split(SPLIT_CHAR)));
} else {
return new EmailList(Collections.emptyList());
}
}
}
And Spring Data repository will work fine with this code - no need for using transform:
import org.springframework.data.domain.Example;
public interface MyRepository extends JpaRepository<MyEntity, Long> {
default List<MyEntity> findMatchingMyEntity(MyEntity myEntity) {
Example<MyEntity> example = Example.of(myEntity);
return findAll(example);
}
}
Use String[] emails instead of List<String> emails
You need to change MyEntity and Converter respectively to use String[]. Of course using String[] sometimes is not an option because you specifically need a List.

How to take Object[] as return type in Spring DataJpa #Query methods?

I want to fetch one row only by taking Object[] as return type in the #Query method of Repo interface. But while accessing the values it's showing
java.lang.ArrayIndexOutOfBoundsException: 1
If i will take Object (not Object[])as return type in the #Query method and while calling it again i have to cast return type to Object[] to get the values. But I don't understand why i can't take Object[] as return type directly.
Repo interface
public interface EmployeeRepository extends JpaRepository<Employee, Integer>{
#Query("select e.empName,e.empSal from org.st.model.Employee e where e.empId= ?1")
Object[] getData2(Integer eid);
}
Runner class
#Component
public class ConsoleRunner implements CommandLineRunner{
#Autowired
private EmployeeRepository repo;
public void run(String...strings) throws Exception{
Object[] obj = repo.getData2(106);//
System.out.println(obj[]);//No Exception no result but [Ljava.lang.Object;#68b366
System.out.println(obj[1]);//AIOBException
}
}
I should get name(String) and sal(Double) value as result.
#Query("select e.empName,e.empSal from org.st.model.Employee e where e.empId= ?1 ")
Object getData2(Integer eid);
Object[] obj = (Object[]) repo.getData2(106);
System.out.println(obj[1]);
It's working fine. cause i have taken Object as return type. But i dont understand why Object[] as Return type is showing AIOBE.
Java array indexes starts with 0. If your Object[] obj has length 1, you need to retrieve it like this: obj[0]
Try this:
public void run(String...strings) throws Exception{
Object[] obj = repo.getData2(106);
System.out.println(obj[]);
System.out.println(obj[0]);
}
}
java.lang.ArrayIndexOutOfBoundsException means you are trying to
access a array index that doesn't exist
Object[] results = repo.getData2(106);
for(Employee emp : results){
System.out.println(emp.getName() + " " + emp.getSal());
}
Employee class must have getters.
But using the List<Employee> makes type safety,
public interface EmployeeRepository extends JpaRepository<Employee, Integer>{
#Query("select e.empName,e.empSal from Employee e where e.empId= ?1")
List<Employee> getData2(Integer eid);
}
and you can easily access
List<Employee> results = repo.getData2(106);
for(Employee emp : results){
System.out.println(emp.getName() + " " + emp.getSal());
}
Returning Object[] means that the query returns an array of records. Each record is itself an Object[]. Therefore access the first column of the first record you need to use (Object[]) o[0]).
You probably want to use use a projection instead:
interface EmployeeView {
String getEmpName();
String getEmpSal();
}
#Query("select e.empName as empName, e.empSal as empSal from org.st.model.Employee e where e.empId= ?1")
EmployeeView getData2(Integer eid);
EmployeeView emp = repo.getData2(106);

Spring Boot JPA repositories custom query

http://spring.io/guides/gs/accessing-data-jpa/
Referred the above link to define a custom query.
We have a developed a Spring boot web service CRUD application but we are facing the following exception when we add a custom query.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeController': Unsatisfied dependency expressed through field 'EmployeeService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeServiceImpl': Unsatisfied dependency expressed through field 'EmployeeRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'EmployeeServiceImpl': Unsatisfied dependency expressed through field 'EmployeeRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:588) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'EmployeeRepository': Invocation of init method failed; nested exception is org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property name found for type Employee!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:77) ~[spring-data-commons-1.13.4.RELEASE.jar:naat org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:309) ~[spring-data-commons-1.13.4.RELEASE.jar:na]
at org.springframework.data.mapping.PropertyPath.from(PropertyPath.java:272) ~[spring-data-commons-1.13.4.RELEASE.jar:na]
This was the repository interface that I have defined. Defined a custom query.
package com.example.rest.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.example.rest.model.Employee;
#Repository
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
Employee findByName(String employeeName);}
This is my service interface
package com.example.rest.service;
import java.util.List;
import com.example.rest.model.Employee;
public interface EmployeeService {
Employee save(Employee employee);
Employee getById(Long employeeId);
void delete(Long employeeId);
List<Employee> findAll();
Employee findByName(String employeeName); }
This is my Service Implementation class
package com.example.rest.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.example.rest.model.Employee;
import com.example.rest.repository.EmployeeRepository;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
EmployeeRepository employeeRepository;
#Override
public Employee save(Employee employee) {
// TODO Auto-generated method stub
return employeeRepository.save(employee);
}
#Override
public Employee getById(Long employeeId) {
// TODO Auto-generated method stub
return employeeRepository.getOne(employeeId);
}
#Override
public void delete(Long employeeId) {
// TODO Auto-generated method stub
employeeRepository.delete(employeeId);
}
#Override
public List<Employee> findAll() {
// TODO Auto-generated method stub
return employeeRepository.findAll();
}
#Override
public Employee findByName(String employeeName) {
// TODO Auto-generated method stub
return employeeRepository.findByName(employeeName);
}}
Without custom query my application works fine.
Let me know where I have made a mistake.
I have added the model class
package com.example.rest.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="testF")
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(nullable=false, unique=true)
private Long employeeId;
#Column(nullable=false, unique=true)
private String employeeName;
#Column(nullable=false)
private String emailId;
#Column(nullable=false)
private Long salary;
public Employee() {
}
public Employee(Long employeeId, String employeeName, String emailId, Long salary) {
this.employeeId = employeeId;
this.employeeName = employeeName;
this.emailId = emailId;
this.salary = salary;
}
public Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public String getEmployeeName() {
return employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
public Long getSalary() {
return salary;
}
public void setSalary(Long salary) {
this.salary = salary;
}
#Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", employeeName=" + employeeName + ", emailId=" + emailId
+ ", salary=" + salary + "]";
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((employeeId == null) ? 0 : employeeId.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (employeeId == null) {
if (other.employeeId != null)
return false;
} else if (!employeeId.equals(other.employeeId))
return false;
return true;
}}
you don't have field 'name' in class Employee.
spring data try created query for search Employee with field name.
Employee findByName(String employeeName);}
Your model doesn't have name property, you have employeeName, so your query should look like this:
Employee findByEmployeeName(String employeeName);
Please see reference for more info on how to build Spring Data queries. In short, when you want to create a query you have to specify full field name how it is written in your Entity.
u can't write findByName in your custom query because u don't have a name field however u can write EmployeeName

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

I am trying to access list of friends of given username using hibernate. Here is my Service class in which fetchListOfFriends function is used to convert the generic list to an Arraylist of type of FriendsDetails.
#Service
#Transactional
public class DetailsServiceImpl implements DetailsService {
#Autowired
private DetailsDao detailsDao;
#Override
public List<FriendsDetails> fetchListOfFriends(String name) {
#SuppressWarnings("rawtypes")
List listOfFriends=detailsDao.fetchListOfFriends(name);
List<FriendsDetails> friendList= fetchListOfFriendss(listOfFriends);
if(listOfFriends==null){
System.out.println("Empty and null list");
}
System.out.println("size of friendList" + listOfFriends.size());
return friendList;
}
private List<FriendsDetails> fetchListOfFriendss(#SuppressWarnings("rawtypes") List genericList) {
#SuppressWarnings("unchecked")
List<Object> result = (List<Object>) genericList;
Iterator<Object> itr = result.iterator();
List<FriendsDetails> listOfFriend= new ArrayList<FriendsDetails>();
while(itr.hasNext()){
Object[] obj = (Object[]) itr.next();
System.out.println(obj.toString());
String userName = String.valueOf(obj[0]);
FriendsDetails obj1= new FriendsDetails();
obj1.setFriendName(userName);
listOfFriend.add(obj1);
}
return listOfFriend;
}
DetailsDaoImpl.java
#Autowired
private SessionFactory sessionFactory;
#SuppressWarnings("rawtypes")
#Override
public List fetchListOfFriends(String name) {
Session session=sessionFactory.getCurrentSession();
String queryToFetchFriends="Select name,presenceStatus from UserPresence where name in (Select friendName from Friends where name='"+name+"')";
List listOfFriends=session.createSQLQuery(queryToFetchFriends).list();
return listOfFriends;
}
Logs.txt
May 22, 2016 1:24:11 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [springmvc] in context with path [/Testing] threw exception [Request processing failed; nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;] with root cause
java.lang.ClassCastException: java.lang.String cannot be cast to [Ljava.lang.Object;
at com.tcs.Service.FriendServiceImpl.searchFriend(FriendServiceImpl.java:61)
at com.tcs.Service.FriendServiceImpl.searchFriend(FriendServiceImpl.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
Everything should work correctly.
The problem, obviously, that List listOfFriends is List<String>, not List<Object[]>. It is strange, because of Select name,presenceStatus from UserPresence should return List<Object[]>.
Maybe Spring set an incorrect implementation of #Autowired
private DetailsDao detailsDao;.
Try this code. This should work for List<String>
private List<FriendsDetails> fetchListOfFriendss(List<?> genericList) {
Iterator<?> itr = genericList.iterator();
List<FriendsDetails> listOfFriend = new ArrayList<FriendsDetails>();
while (itr.hasNext()) {
Object obj = itr.next();
String userName = String.valueOf(obj);
System.out.println(userName);
FriendsDetails obj1 = new FriendsDetails();
obj1.setFriendName(userName);
listOfFriend.add(obj1);
}
return listOfFriend;
}

Resources