I've tried many different ways to pass an array of JSON to a Spring Data Rest Repository, not sure how to do it. I have a custom respository interface that is extending Repository:
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
T save(T entity)
List<T> save(Iterable<T> entities)
}
I can save a single entity, but when I try to pass an array of JSON objects I get an error cannot deserialize instance...
Not sure how to pass the object so that I can do a batch insert.
Unfortunatly you don't post the code that uses your interface, bug if you are actually passing an array as you describe in the question, you are not calling List<T> save(Iterable<T> entities) but T save(T entity). Arrays are not Iterables so the compiler will interpret your array as T and since an array is not an entity you get the error.
Convert the array to an Iterable to fix this. Arrays.asList(someArray) does the trick.
I seemed to work around it by overriding the save method, I'm sure there is a better way, I am open to suggestions.
BaseRepository
#NoRepositoryBean
interface BaseRepository<T, ID extends Serializable> extends Repository<T, Long> {
#RestResource(path="byIdIn",rel="byIdIn")
#Query("select r from #{#entityName} r where r.id in :q")
Page<T> findByIdIn(#Param("q") List<Long> q, Pageable pageable)
Page<T> findAll(Pageable pageable)
T findOne(ID id)
T save(T entity)
T delete(ID id)
}
ContactRepository
#RepositoryRestResource(collectionResourceRel="contacts", path="contacts")
interface ContactRepository extends BaseRepository<Contact, Long>, ContactRepositoryCustom {
}
ContactRepositoryCustom
interface ContactRepositoryCustom {
public <S extends Contact> S save(S entity)
}
ContactRepositoryImpl
#NoRepositoryBean
class ContactRepositoryImpl implements ContactRepositoryCustom {
#PersistenceContext
private EntityManager em
#Transactional
#Override
public <S extends Contact> S save(S entity) {
Contact contact = entity as Contact
try {
em.persist(contact)
contact.getComment().each {
Comment comment = new Comment(contact, it)
em.persist(comment)
}
} catch (Exception e) {
println e
}
return contact
}
}
This is just a sample, it needs some cleaning up, but I have the save() method working as expected. I just don't want to over do it if there is a baked in way in Spring Data / Spring Data Rest to do this kind of thing with annotations without having to roll a solution like this. I searched through the docs and online, but did not find a solution. I may have overlooked something, not sure.
Related
I'd like to know if there's a way of overriding the delete method for some of my JpaRepository's without having to override the rest of the methods.
Currently I have something like
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
And I'd like to override the delete(T Entity) method in CrudRepository. To do so I've tried implementing the UserRepo but then I have to implement all the findByX and haven't really find anything around on how to properly do that.
Is there any annotation to add to a function in the Entity class so it runs when you call UserRepo.delete(myUser)?
Thanks in advance!
Not sure I understand you clear enough, but lets try:
... I have to implement all the findByX ...
You don't, spring will generate JPQL snippet if you name methods in your interface with suitable convection please take a look at this and this articles
... Is there any annotation to add to a function in the Entity class
so it runs when you call UserRepo.delete(myUser)? ...
You can use #PreRemove / #PostRemove annotation on method in your entity class:
#PreRemove / #PostRemove
public void someMethod() { ... }
In addition to Raheela Aslam post:
Spring-data documentation has an example of how you can override standard repository methods, for example:
interface CustomizedSave<T> {
<S extends T> S save(S entity);
}
class CustomizedSaveImpl<T> implements CustomizedSave<T> {
public <S extends T> S save(S entity) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedSave<User> {
}
You can read about it there:
https://docs.spring.io/spring-data/jpa/docs/2.1.2.RELEASE/reference/html/#repositories.custom-implementations
UPD:
Read it carefully, because there are some important things, e.g
The most important part of the class name that corresponds to the fragment interface is the Impl postfix.
Also the documentation says:
Custom implementations have a higher priority than the base implementation and repository aspects.
If you want to keep Spring's behavior for deletion, but want to have some logic to be executed either before or after, you may utilize java8's interface default methods, and try the following :
public interface UserRepo extends JpaRepository<User, Long> {
default void customDelete(User user) {
// before logic
// ..
delete(user); // actual call to deletion
// after logic
// ..
}
}
There are several ways to do this depending on what you're trying to do:
Use method naming, and let Spring derive the JPQL query from the naming (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-from-method-names/)
Use the Query annotation and add the desired JPQL query in the annotation (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-the-query-annotation/)
Use a named query (https://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-creating-database-queries-with-named-queries/)
I prefer to use method naming if possible, the method name gets long, but you know exactly what it does by looking at it.
In your case code will be like as below:
public interface UserRepo extends JpaRepository<User, Long>
{
findUserById(long id);
findUserByEmail(String email);
// etc...
}
public interface UserRepositoryCustom {
void deleteByEmail(String email);
}
public interface UserRepositoryImpl implements UserRepositoryCustom {
public void deleteByEmail(String email) {
//provide your custom implimentation
}
}
Hi you can write your own Interface write implementation with EntityManager and
extend in you interface here is the sample :
https://dzone.com/articles/accessing-the-entitymanager-from-spring-data-jpa
Actually one more way is writing by soemthing like :
User findByUsername(String username) // it will find the user by specific username
spring data will create you an implementation of this method
The same way you can create your own delete method
Here is useful links:
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.custom-implementations
In this link you can go to part 2.3 QueryMethods:
https://docs.spring.io/spring-data/jpa/docs/1.6.0.RELEASE/reference/html/jpa.repositories.html
You can also define #NameQuery in your entity class:
#Entity
#Table(name = "employee", schema="spring_data_jpa_example")
#NamedQuery(name = "Employee.yourMethodQueryName",
query = "yourQuery"
)
public class Employee {}
#Repository
public interface EmployeeRepository extends JpaRepository<Employee,Long> {
List<Employee> yourMethodQueryName(Your list of params);
}
Here is link with sample:
https://www.logicbig.com/tutorials/spring-framework/spring-data/jpa-named-queries.html
I think this is helpful for you
public interface UserRepo extends JpaRepository<User, Long> {
#Modifying
#Query("delete from User u where u.email = ?1")
void deleteByEmail(String email);
}
I'm working on a Java application(micro-services) using Spring 5, JDK 1.8, SpringBoot 2.0. I got a helper class where I'm loading a hashmap using the #PostConstruct like below :-
Helper class:-
private final Map<String, CommonData> empMap = new HashMap<>();
#PostConstruct
public void init() {
loadEmpMap();
}
private void loadEmpMap() {
List<EmpMap> employees = empRepo.getEmpInfo();
employees.forEach(p -> empMap
.put(p.getEmpId(),
new CommonData(p.getName(), p.getDesignation(), p.getContactNumber())));
}
Now during the application startup, #PostConstruct will be called and HashMap will be loaded with data using JPA Repository. This HashMap will be available through out this object to use. Now my requirement is to update (auto-refresh) this HashMap with new set of data (ofcourse entity refresh) whenever there is an update/save operation on entity. For this, I have written an Interface like below to Refresh the entity using the EntityManager :-
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
#NoRepositoryBean
public interface CustomRepository<T, ID extends Serializable> extends JpaRepository<T, ID> {
void refresh(T t);
}
public class CustomRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements CustomRepository<T, ID> {
private final EntityManager entityManager;
#Autowired
public CustomRepositoryImpl(JpaEntityInformation entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
#Override
#Transactional
public void refresh(T t) {
entityManager.refresh(t);
}
}
And then extending this custom repository to my application respository like below :-
#Repository
public interface EmpRepo extends CustomRepository<Employee, EmpKey> {
}
public final class CommonRepositoryDetails implements EmpRepo {
private EmpRepo empRepo;
constructor(){
}
XYZMethod(){
-------
---- some line of code for save/update operation using Jpa -----
-- then trying to refresh the entity as below -----
empRepo.refresh(value);
}
I'm not sure whether this will refresh my hashmap again with latest objects from entity to be used or Im missing something here. Please let me know as I want to refresh my HashMap again. Thanks
Since the HashMap belongs to the HelperClass it will be not updated.
I am assuming that you are going to use employee information for the HashMap in the application, because you don't want to request the database everytime to fetch the records. You can use Spring Cahche mechanism to save the information in the SpringDefault Cache(Concurrent HashMap).
You can use #Cacheable on get methods, it will hit the database when the information is not present in the cache. #CachePut annotation the update method will update the cache.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html
http://www.baeldung.com/spring-cache-tutorial
https://spring.io/guides/gs/caching/
The find methods not working for me but in other project work fine .
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entities.Contact;
public interface ContactRepository extends JpaRepository<Contact, Long>{
}
in my controller i call find one but give works.
#RequestMapping(value="/contact/{id}",method=RequestMethod.GET)
public Contact getContact(#PathVariable Long id){
return repo.findOne(id); //here give a error
}
Some CRUD Repository methods got renamed in Spring Data and
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
is one of them. Now you should use the
public interface CrudRepository<T, ID> extends Repository<T, ID> {
Optional<T> findById(ID id);
For more info which methods got renamed see this blog improved-naming-for-crud-repository-methods
There is still a findOne method around but this is from
public interface QueryByExampleExecutor<T> {
<S extends T> Optional<S> findOne(Example<S> example);
which is also an interface of the SimpleJpaRepository. So that is why you got your error, since this method awaits an Example as parameter.
How can I get access to the Entity Manager in the repository when using Spring Boot and Spring Data?
Otherwise, I will need to put my big query in an annotation. I would prefer to have something more clear than a long text.
You would define a CustomRepository to handle such scenarios. Consider you have CustomerRepository which extends the default spring data JPA interface JPARepository<Customer,Long>
Create a new interface CustomCustomerRepository with a custom method signature.
public interface CustomCustomerRepository {
public void customMethod();
}
Extend CustomerRepository interface using CustomCustomerRepository
public interface CustomerRepository extends JpaRepository<Customer, Long>, CustomCustomerRepository{
}
Create an implementation class named CustomerRepositoryImpl which implements CustomerRepository. Here you can inject the EntityManager using the #PersistentContext. Naming conventions matter here.
public class CustomCustomerRepositoryImpl implements CustomCustomerRepository {
#PersistenceContext
private EntityManager em;
#Override
public void customMethod() {
}
}
In case you have many repositories to deal with, and your need in EntityManager is not specific for any particular repository, it is possible to implement various EntityManager functionality in a single helper class, maybe something like that:
#Service
public class RepositoryHelper {
#PersistenceContext
private EntityManager em;
#Transactional
public <E, R> R refreshAndUse(
E entity,
Function<E, R> usageFunction) {
em.refresh(entity);
return usageFunction.apply(entity);
}
}
The refreshAndUse method here is a sample method to consume a detached entity instance, perform a refresh for it and return a result of a custom function to be applied to the refreshed entity in a declarative transaction context. And you can add other methods too, including query ones...
I'm playing with Xtend, and have hit a roadblock.
My class uses a Spring Data repository. Here's the interface:
public interface UserRepository extends GraphRepository<UserNode>, RelationshipOperationsRepository<UserNode> {
public UserNode findByEntityId(Long entityId);
}
the super interface of GraphRepository<T> (which is part of Spring Data, not my project) declares the following:
#Transactional
<U extends T> U save(U entity);
#Transactional
<U extends T> Iterable<U> save(Iterable<U> entities);
However, the following code fails for me:
// UpdateUserProcessorExample.xtend
class UpdateUserProcessorExample {
#Autowired
UserRepository repository
def updateUser()
{
var user = repository.findByEntityId(1L)
// The following line generates an error:
repository.save(user)
}
}
This generates:
Bounds mismatch: The type argument is not a valid substitute for
the bounded type parameter of the method
save(Iterable)
It appears as though Xtend is picking the wrong overloaded method.
I've tried adding type hints, ala:
var UserNode user = repository.findByEntityId(1L)
But this still generates the same error.
What am I doing wrong here?
On the Xtend mailing list, Sven advised he's raised a bug for this issue:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=413138
He also offered the following work-around:
A not so nice solution is to override the respective methods in
UserRepository and replace T by UserNode, like this :
public interface UserRepo extends GraphRepository<UserNode> {
UserNode findByEntityId(Long entityId);
#Override UserNode save(UserNode entity);
#Override <U extends UserNode> Iterable<? extends U> save(Iterable<? extends U> entities);
I don't understand why you have introduced additional type parameters on the methods, can't you you just use the one from the class level?
#Transactional
T save(T entity);
#Transactional
Iterable<? extends T> save(Iterable<? extends T> entities);
That should work.