Spring data jpa repository property not found - spring

I am new to Spring Data JPA. I've tried to create a custom method for the repository but it does throw an exception. Here is my current implementation:
public interface EmployeeRepository extends
CrudRepository<Employee, Long>,EmployeeRepositoryCustom {
}
#Repository
public interface EmployeeRepositoryCustom {
public void updateEmployee(String field, String value,long id);
}
public class EmployeeRepositoryImpl implements EmployeeRepositoryCustom {
#PersistenceContext
private EntityManager entityManager;
#Override
public void updateEmployee(String field, String value, long id) {
// Implementation goes here
}
}
And this is the exception that occurs when I start the application (I am using Spring boot).
Caused by: org.springframework.data.mapping.PropertyReferenceException: No property updateEmployee found for type Employee!
at org.springframework.data.mapping.PropertyPath.<init>(PropertyPath.java:75)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:327)
at org.springframework.data.mapping.PropertyPath.create(PropertyPath.java:307)

Since you have tagged spring-boot, I assume you are using spring-boot. If so, you can try following method.
#Repository
public interface EmployeeRepositoryCustom {
#Modifying
#Query(value = "update Employee query", nativeQuery = true)
public void updateEmployee(String field, String value,long id);
}
You do not need to have an implementation and you can have named parameters in query above. Spring-boot will handle rest.

Related

JpaRepository mistakes custom interface as property

For general spring JpaRepository DAO (no spring-boot) , if the interface extends a custom interface , spring will mistake the interface methods as object's properties .
For example
interface ILocalDateTime {
fun getLocalDateTime() : LocalDateTime
}
interface UserDaoCustom : ILocalDateTime {
// query functions skipped
}
interface UserDao : JpaRepository<User, Long>, UserDaoCustom
class UserImpl : UserDaoCustom {
#PersistenceContext
private lateinit var em: EntityManager
override fun getLocalDateTime(): LocalDateTime {
return LocalDateTime.now()
}
// query functions skipped
}
This is a simplified UserDao. UserDaoCustom extends ILocalDateTime which contains a method getLocalDateTime .
Note : localDateTime is not a field of User.
At runtime, JpaRepository will mistake getLocalDateTime (or localDateTime ?) as User's field , and throws such exception :
Caused by: org.springframework.data.repository.query.QueryCreationException:
Could not create query for public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
Reason: Failed to create query for method public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
No property getLocalDateTime found for type User!;
nested exception is java.lang.IllegalArgumentException:
Failed to create query for method public abstract java.time.LocalDateTime foo.ILocalDateTime.getLocalDateTime()!
No property getLocalDateTime found for type User!
Environment :
Kotlin 1.6.20
Spring 5.3.19
spring-data-jpa 2.5.11
How to solve this problem ? (with able or unable to modify ILocalDateTime's code)
Thanks.
I think it is about naming and how Spring pick up implementations of repository extensions.
TLDR;
Change name of your implementation from UserImpl to UserDaoCustomImpl.
I have checked a similar setup and using your naming fails with the exact same error, but naming it "right" makes it work as expected
public interface ILocalDateTime {
LocalDateTime getLocalDateTime();
}
#Repository
public interface UserDao extends UserDaoCustom, JpaRepository<User, Long> {
}
public interface UserDaoCustom extends ILocalDateTime{
}
#Repository
public class UserDaoCustomImpl implements UserDaoCustom {
#Override
public LocalDateTime getLocalDateTime() {
return LocalDateTime.now();
}
}
and tests
#ExtendWith(SpringExtension.class)
#DataJpaTest
class UserRepositoryTest {
#Autowired
private UserDao userDao;
#Test
public void savesUser() {
userDao.save(new User());
}
#Test
public void bazzinga() {
assert userDao.getLocalDateTime() != null;
System.out.println("Bazzinga!"+userDao.getLocalDateTime());
}
}
yelds

required a bean of type 'java.lang.String' that could not be found

This the error iam when I tried start my spring boot application getting on console Action:
Consider defining a bean of type
'java.lang.String' in your
configuration.
My code
#Repository
public class ProductRepository {
#Autowired
JdbcTemplate jdbcTemplate;
#Bean
public void addProduct(String name) {
String sql = "INSERT INTO product VALUES (NULL, ?)";
jdbcTemplate.update(sql, name);
}
}
#Service
public class ProductService {
#Autowired
ProductRepository productRepository;
public void addProduct(String name) {
productRepository.addProduct(name);
}
}
#RestController
#RequestMapping(path="product")
public class ProductController {
#Autowired
ProductService productService;
#PostMapping(path="/add/{name}")
public void addProduct(#PathVariable
String name) {
productService.addProduct(name);
}
}
Here, you are trying to create bean with dependency object of type String in addProduct(). When Spring application starts, it tries to look for Bean of type String. It makes no sense.
So, no need of the #Bean annotation. The beans are usually created in classes annotated with #Configuration.
try removing #Bean over addproduct method

Creating custom functions in Spring Boot services

I am writing a simple Spring Boot Application.I'm creating a repository,then its service and then its implementation
The code works fine if I use inbuilt functions of the JPA repository.
However it throws error if I try to make a function in the service interface.
If I make that function in the repository it doesn't throw that error
Here is the code:
Repository:
#Transactional
public interface Local_Repository extends JpaRepository<LocalModel,Long> {
}
Service:
public interface Local_Service {
public List<LocalModel> findAll();
public LocalModel findById(Long id);
public LocalModel findBymo(String mo);//this is the function I added
}
Implementation:
#Service
public class Local_Impl implements Local_Service {
#Autowired
private Local_Repository repository;
#Override
public List<LocalModel> findAll() {
List<LocalModel> cities = (List<LocalModel>) repository.findAll();
return cities;
}
#Override
public LocalModel findById(Long id) {
LocalModel city = repository.findOne(id);
return city;
}
#Override //this throws error
public LocalModel findBymo(String mo) {
LocalModel city=repository.findBymo(mo);
return null;
}
}
In the service you are calling a function that doesn't exist in the repository layer. There is no method called findBymo in the repository. If LocalModel has a field called mo, you can just add a function in the repository interface like this
LocalModel findByMo(String mo);
and it will be implemented automatically.
If LocalModel doesn't have such field you should implement the query yourself in the repository like this
#Query("select ... query here")
LocalModel findByMo(String mo);

requestfactory complain about find method

I have a spring (3.1) application with a service and dao layer.
I try to use requestfactory (gwt 2.4) withi this spring layer.
Here some of my class
My domain class
public class Account {
Long id;
String username;
// get, set
}
The bridge between spring and gwt
public class SpringServiceLocator implements ServiceLocator {
#Override
public Object getInstance(Class<?> clazz) {
HttpServletRequest request = RequestFactoryServlet.getThreadLocalRequest();
ServletContext servletContext = request.getSession().getServletContext();
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext);
return context.getBean(clazz);
}
}
My account proxy
#ProxyFor(value=Account.class, locator = AccountLocator.class)
public interface AccountProxy extends EntityProxy{
public Long getId();
public String getUsername();
public void setUsername(String userName);
public void setId(Long id);
}
RequestContext class
#Service(locator = SpringServiceLocator.class, value =AccountService.class)
public interface AccountRequest extends RequestContext {
Request<List<AccountProxy>> loadAllAccounts();
}
My requestFactory class
public interface AccountRequestFactory extends RequestFactory {
AccountRequest accountRequest();
}
My spring service
public interface AccountService {
public List<Account> loadAllAccounts();
}
#Service
public class AccountServiceImpl implements AccountService{
#Autowired
private AccountDAO accountDAO;
}
Account locator to avoid to put method in the entity
public class AccountLocator extends Locator<Account, Long> {
#Autowired
private AccountDAO accountDAO;
#Override
public Account create(Class<? extends Account> clazz) {
return new Account();
}
}
applicationContext.xml
<context:annotation-config />
<context:component-scan base-package="com.calibra" />
<bean id="accountService" class="org.calibra.server.service.AccountServiceImpl"/>
<bean id="accountDAO" class="org.calibra.server.dao.AccountDAOImpl"/>
The demo work but i get this error:
com.google.web.bindery.requestfactory.server.UnexpectedException: Could not find static method with a single parameter of a key type
Also on my AccountProxy i get this complain (a warning)
The domain type org.calibra.domain.Account has no Account findAccount(java.lang.Long) method. Attempting to send a AccountProxy to the server will result in a server error.
I don't want to add a find methond in my domain class.
I tried to put this method in my spring service, but i get the same warning.
Edit with the Locator that work fine
Just strange i need to put bean in the applicationContext, context:annotation and context:component-scan seem useless
Any idea?
The domain type org.calibra.domain.Account has no Account findAccount(java.lang.Long) method.
If you don't provide a find method of some kind, RequestFactory has no way of reconstituting objects when they get to the server - it can only create brand new ones, which prevents it from merging with existing data. Take this away, and you might as well have RPC again.
If you don't want static methods, provide a Locator instance which is able to find objects. From https://developers.google.com/web-toolkit/doc/latest/DevGuideRequestFactory#locators:
What if you don't want to implement persistence code in an entity itself? To implement the required entity locator methods, create an entity locator class that extends Locator:
public class EmployeeLocator extends Locator<Employee, Long> {
#Override
public Employee create(Class<? extends Employee> clazz)
{
return new Employee();
}
...
}
Then associate it with the entity in the #ProxyFor annotation:
#ProxyFor(value = Employee.class, locator = EmployeeLocator.class)
public interface EmployeeProxy extends EntityProxy {
...
}
You'll need to implement all of the methods, not just create - and the main one you are interested in is find(Class, Long). It may be possible to use one single Locator type for all proxies - as of 2.4.0 and 2.5.0-rc1 it is safe to fail to implement getDomainType(), and all of the other methods that need to know the exact type are provided with it as an argument.
Here is an example of what this can look like with JPA and Guice, but I think the idea is clear enough that it can be implemented with Spring and whatever persistence mechanism you are using. Here, all entities are expected to implement HasVersionAndId, allowing the locator to generalize on how to invoke getVersion and getId - you might have your own base class for all persisted entities.
(from https://github.com/niloc132/tvguide-sample-parent/blob/master/tvguide-client/src/main/java/com/acme/gwt/server/InjectingLocator.java)
public class InjectingLocator<T extends HasVersionAndId> extends Locator<T, Long> {
#Inject
Provider<EntityManager> data;
#Inject
Injector injector;
#Override
public T create(Class<? extends T> clazz) {
return injector.getInstance(clazz);
}
#Override
public T find(Class<? extends T> clazz, Long id) {
return data.get().find(clazz, id);
}
#Override
public Class<T> getDomainType() {
throw new UnsupportedOperationException();//unused
}
#Override
public Long getId(T domainObject) {
return domainObject.getId();
}
#Override
public Class<Long> getIdType() {
return Long.class;
}
#Override
public Object getVersion(T domainObject) {
return domainObject.getVersion();
}
}

hibernate tools & hibernate template in DAO

I used Hibernate tools Eclipse plugin to generate the DAO implementation but it uses a "javax.persistence.EntityManager". I want to generate a DAO impl based on my mapped entity(using JPA annotations) that use a Hibernate Template provided by Spring Framework. How can I do this?
This is how we used to generated DAO objects based with generic implementation of DAO Impl by using Hibernate Template provided by Spring Framework.
Generating DAO java class with ftl,And sample looks like
#Repository("hrdb.UserDao")
public class UserDao extends WMGenericDaoImpl <User, Integer> {
#Autowired
#Qualifier("hrdbTemplate")
private HibernateTemplate template;
public HibernateTemplate getTemplate() {
return this.template;
}
}
And this is how our generic DAO impl looks like
public abstract class WMGenericDaoImpl<Entity extends Serializable, Identifier extends Serializable> implements WMGenericDao<Entity, Identifier> {
private Class<Entity> entityClass;
public abstract HibernateTemplate getTemplate();
#SuppressWarnings("unchecked")
#PostConstruct
public void init() {
if (getTemplate() == null)
throw new RuntimeException("hibernate template is not set.");
ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<Entity>) genericSuperclass.getActualTypeArguments()[0];
}
public Entity create(Entity entity) {
Identifier identifier = (Identifier) getTemplate().save(entity);
return findById(identifier);
}
public void update(Entity entity) {
getTemplate().update(entity);
getTemplate().flush();
}
public void delete(Entity entity) {
getTemplate().delete(entity);
}
public Entity findById(Identifier entityId) {
return getTemplate().get(entityClass, entityId);
}
}
Ofcourse here is WMGenericDao Interface,
public interface WMGenericDao<Entity, Identifier> {
Entity create(Entity entity);
void update(Entity entity);
void delete(Entity entity);
Entity findById(Identifier entityId);
}
And HibernateTemplate is declared in spring.xml.
With this kind of implementation we are able to generate All DAO class in the reverse engineering process by using hibernate template provided by spring.

Resources