how to inject bean into own implementation SimpleJpaRepository - spring

Follow this tutorial Extending the JPA specification executor i wrote my own implementation of JpaRepository<T, ID>:
public class SimpleFilterableJpaRepository<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements
FilterExecutor<T> {
//How to inject object here
#Autowired
public JpaFilterSpecificationResolver specificationResolver;
public SimpleFilterableJpaRepository(JpaEntityInformation<T, ?> entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
}
public SimpleFilterableJpaRepository(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
..........
}
I have no idea how to deliver JpaFilterSpecificationResolver ? Any idea
This class have two constructor. First constructor is called in org.springframework.data.repository.core.support.RepositoryFactorySupport and second is using by JpaRepositoryFactoryBean.JpaRepositoryFactoryBean.
So for second one there is no problem to deliver 'specificationResolver'? but first is called via proxy :/

Related

Object not initialized with autowire

I use spring boot 3
I created a object manually, FormGenerator, because everytime I use is in my advance search, some field need to be reset.
So I think the scope prototype is ok for that
#Repository
public class SchoolRepositoryCustomImpl extends SimpleJpaRepository<School, Long> implements SchoolRepositoryCustom {
#Override
public List<School> advanceSearch(SchoolSearch search) {
FormGenerator qg = new FormGenerator();
}
...
}
#Scope("prototype")
public class FormGenerator {
private int fieldCounter=0;
#Autowired
private EntityManager entityManager;
...
}
When I run application, entityManager is null?
It is null because you created the object manually by calling the constructor. You need to obtain it from the ApplicationContext. Something like this:
#Repository
public class SchoolRepositoryCustomImpl extends SimpleJpaRepository<School, Long> implements SchoolRepositoryCustom {
#Autowired
private ApplicationContext applicationContext;
#Override
public List<School> advanceSearch(SchoolSearch search) {
FormGenerator qg = applicationContext.getBean(FormGenerator.class);
}
...
}

How to inject a Spring bean into JpaRepositoryFactoryBean

I have my own custom Spring Data common repository in order to provide common behavior to all Spring Data repositories. And all I need is to modify EntityManager when repository is being created. But I can't inject a Spring bean into JpaRepositoryFactoryBean due to the bean is created via new operator.
public class BasicJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends JpaRepositoryFactoryBean<T, S, ID> {
#Autowired
private SomeService service; // - it does not work
#Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
// do some logic here
service.doSmth();
return new CommonRepositoryFactory<>(em);
}
private static class CommonRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private final EntityManager em;
public CommonRepositoryFactory(EntityManager em) {
super(em);
this.em = em;
}
#SuppressWarnings("unchecked")
protected Object getTargetRepository(RepositoryMetadata metadata) {
JpaEntityInformation entityInformation = getEntityInformation(metadata.getDomainType());
return new CommonRepositoryImpl(entityInformation, em);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return CommonRepositoryImpl.class;
}
}
}
Implement a setter in that class or one that extends from it.

Spring Boot JPA with REST Service

I know that such questions were asked (Did not find handler method ), but after trying multiple solutions I'm still stucked.
So my problem is: I can't use both REST and JPA in my project.
com.db.ruf: WRepository.class:
#NoRepositoryBean
#Component
public interface WRepository <T, ID extends Serializable>
extends JpaRepository<T, ID> {
}
com.db.ruf: WRepositoryImpl.class:
public class WRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements WRepository<T, ID> {
private EntityManager entityManager;
// There are two constructors to choose from, either can be used.
public WRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
// This is the recommended method for accessing inherited class dependencies.
this.entityManager = entityManager;
}
}
com.db: MyRepositoryFactoryBean.class
public class MyRepositoryFactoryBean <R extends JpaRepository<T, I>, T, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
/**
* Creates a new {#link JpaRepositoryFactoryBean} for the given repository interface.
*
* #param repositoryInterface must not be {#literal null}.
*/
public MyRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
super(repositoryInterface);
}
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MyRepositoryFactory(entityManager);
}
private static class MyRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory {
private EntityManager entityManager;
public MyRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new WRepositoryImpl<T, I>((Class<T>) metadata.getDomainType(), entityManager);
}
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the JpaRepositoryFactory
//to check for QueryDslJpaRepository's which is out of scope.
return WRepository.class;
}
}
}
com.rest.: WebadminRESTController.class
#RestController
#Component
public class WebadminRESTController {
#Autowired
WRepository<ExternalLink, Long> wRepositoryImpl;
#RequestMapping(value = "/allExternalLinks", method = RequestMethod.GET)
public ResponseEntity<?> allExternalLinks() {
...
}
}
com:
#SpringBootApplication
#EnableAutoConfiguration
#EnableJpaRepositories(basePackages = "com.db.ruf", repositoryFactoryBeanClass = MyRepositoryFactoryBean.class)
#ComponentScan(basePackages = "com", resourcePattern = "com.*")
#EntityScan({"com.db"})
public class WebadminApplication {
public static void main(String[] args) {
SpringApplication.run(WebadminApplication.class, args);
}
}
In this case I get:
Did not find handler method for [/allExternalLinks]
If I change
#ComponentScan(basePackages = "com", resourcePattern = "com.*") to #ComponentScan(basePackages = "com") or #ComponentScan I get:
Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type
'com.db.ruf.WRepository' available: expected at least 1 bean which qualifies
as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
I really don't know what's wrong.
Could anyone be so kind to explain it?
Thank you in advance
Use #Repository on WRepositoryImpl.java. And edit WebadminRESTController.java:
#Autowired
WRepositoryImpl<ExternalLink, Long> wRepositoryImpl;
Accidentally I found solution (don't think that it is the best one, but at least it works):
public interface ExternalLinksRepo extends CrudRepository<ExternalLink, Long> {
...
}
and:
public class WebadminRESTController {
#Autowired
ExternalLinksRepo wRepositoryImpl;
...}
Then wRepositoryImpl is automatically created as instance of WRepositoryImpl
Thanks to all, especially to Cepr0

Best practise when using Querydsl with Spring Data

Using Spring Data nad Querydsl we can just declare repository interface and skip the implementation class. Some methods with a specific name or using #Query annotation and that's all.
But sometimes I'd like to use JPAQuery and define method's body by myself, let's say
#Repository
public class MyRepositoryImpl implements MyRepository {
#PersistenceContext
private EntityManager em;
#Override
public List<Tuple> someMethod(String arg) {
JPAQuery query = new JPAQuery(em);
...
}
but this way I would have to implement other MyRepository interface methods, which ruins all Spring Data's advantages!
I can see two options:
Declare another interface per each repository and then normally implement it (which doubles number of interfaces)
Inject EntityManager into #Service class and implement my custom methods there
I like option #2 more, but as far I as know, in #Service class we should only call repository methods, so it's not a perfect solution as well.
So how does programmers deal with it?
You should not implement the actual Spring Data repository, instead you have to declare another custom interface where you can put your custom methods.
Let's say you have a MyRepository, defined as
#Repository
public interface MyRepository extends JpaRepository<Tuple, Long> {}
Now you want to add your custom findTuplesByMyArg(), for a sake of purpose you need to create custom repository interface
public interface MyRepositoryCustom {
List<Tuple> findTuplesByMyArg(String myArg);
}
Afterwards comes the implementation of custom interface
public class MyRepositoryImpl implements MyRepositoryCustom {
#PersistenceContext
private EntityManager em;
#Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = new JPAQuery(em);
...
}
}
And we need to change MyRepository declaration, so it extends custom repository, so that
#Repository
public interface MyRepository extends JpaRepository<Tuple, Long>, MyRepositoryCustom {}
And you can easily access your findTuplesByMyArg() by injecting MyRepository, e.g.
#Service
public class MyService {
#Autowired
private MyRepository myRepository;
public List<Tuple> retrieveTuples(String myArg) {
return myRepository.findTuplesByMyArg(myArg);
}
}
Pay attention that names are important here (you need to have Impl postfix by default configs in repo implementation).
You can find all needed information here
I would suggest a minor rectification to the answer above, which tries to use JPAQueryFactory. It is good to make use of the provided factory class.
public class MyRepositoryImpl implements MyRepositoryCustom {
#Autowired
private JPAQueryFactory factory;
#Override
public List<Tuple> findTuplesByMyArg(String myArg) {
JPAQuery query = factory.query();
...
}}
#Configuration
public class Config {
#Autowired
private EntityManager em;
#Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(em);
}
}

Spring Data JPA Custom Generic Repository Pattern issue

I have the following configuration in Spring but Autowiring fails due to lack of an init method in the Impl class of the repository. Spring shouldn't be attempting to init the bean by a constructor, but it should be using the Factory ... I've missed some simple configuration... or I have ran into a bug.
I am trying to achieve a single generic repository where all repositories can share methods and specific ones that are particular to my mapped domain classes...
Here is my error:
Error creating bean with name 'auditRepositoryImpl' defined in file AuditRepositoryImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.domain.biz.dao.impl.AuditRepositoryImpl]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.domain.biz.dao.impl.AuditRepositoryImpl.<init>()
On another side note, it looks like my CustomFactory isn't being picked up.
2014-07-05 08:16:48,343 DEBUG org.springframework.data.repository.config.RepositoryComponentProvider Identified candidate component class: file [InventoryRepository.class]
...
2014-07-05 08:16:48,366 DEBUG org.springframework.data.repository.config.RepositoryBeanDefinitionBuilder Registering custom repository implementation: auditRepositoryImpl AuditRepositoryImpl
2014-07-05 08:16:48,367 DEBUG org.springframework.data.repository.config.RepositoryConfigurationDelegate Registering repository: auditRepository - Interface: AuditRepository - Factory: org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
//Spring Java config
#Configuration
#EnableScheduling
#EnableSpringConfigured
#Import(EnvConfiguration.class)
#EnableAspectJAutoProxy
#EnableJpaRepositories(repositoryFactoryBeanClass = DefaultRepositoryFactoryBean.class, basePackages = { "com.domain.biz.dao" }, repositoryImplementationPostfix = "Impl")
#EnableCaching
#EnableTransactionManagement(proxyTargetClass = true)
#ComponentScan(basePackages = { "com.domain.biz" })
#Order(2)
public class AppConfiguration extends CachingConfigurerSupport implements LoadTimeWeavingConfigurer
...
#NoRepositoryBean
public interface GenericRepository<T extends Serializable, I extends Serializable>
extends JpaRepository<T, I> {
...
#NoRepositoryBean
public abstract class AbstractRepositoryImpl<T extends Serializable, I extends Serializable>
extends SimpleJpaRepository<T, I> implements GenericRepository<T, I> {
private static Logger log = LoggerFactory
.getLogger(AbstractRepositoryImpl.class);
private Class<T> clazz;
#Autowired
EntityManager entityManager;
#Autowired
SessionFactory sessionFactory;
public AbstractRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
public AbstractRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
...
#NoRepositoryBean
// #Scope( BeanDefinition.SCOPE_PROTOTYPE )
public class GenericRepositoryImpl<T extends Serializable, I extends Serializable>
extends AbstractRepositoryImpl<T, I> implements GenericRepository<T, I> {
...
public interface AuditRepositoryCustom {
public Audit audit(Audit audit);
public interface AuditRepository extends GenericRepository<Audit, Long>, AuditRepositoryCustom {
public class DefaultRepositoryFactoryBean<R extends JpaRepository<T, I>, T extends Serializable, I extends Serializable>
extends JpaRepositoryFactoryBean<R, T, I> {
private static class RepositoryFactory<T extends Serializable, I extends Serializable>
extends JpaRepositoryFactory {
private EntityManager entityManager;
public RepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
#Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
// The RepositoryMetadata can be safely ignored, it is used by the
// JpaRepositoryFactory
// to check for QueryDslJpaRepository's which is out of scope.
return GenericRepository.class;
}
#Override
protected Object getTargetRepository(RepositoryMetadata metadata) {
return new GenericRepositoryImpl<T, I>(
(Class<T>) metadata.getDomainType(), this.entityManager);
}
}
#Override
protected RepositoryFactorySupport createRepositoryFactory(
EntityManager entityManager) {
return new RepositoryFactory(entityManager);
}
The exception is pretty clear about the root cause. Your AuditRepositoryImpl does not have either a no-arg constructor or a constructor annotated with #Inject/#Autowired.
Here is the corrected code in case anyone needs it.
#NoRepositoryBean
public interface GenericRepository<T extends Serializable, I extends Serializable>
extends JpaRepository<T, I> {
Result truncate();
...
#NoRepositoryBean
public abstract class AbstractRepositoryImpl<T extends Serializable, I extends Serializable>
extends SimpleJpaRepository<T, I> implements GenericRepository<T, I> {
public AbstractRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
public AbstractRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
#Override
public Result truncate() {
...
public class GenericRepositoryImpl<T extends Serializable, I extends Serializable>
extends AbstractRepositoryImpl<T, I> implements GenericRepository<T, I> {
public GenericRepositoryImpl(Class<T> domainClass, EntityManager em) {
super(domainClass, em);
}
public GenericRepositoryImpl(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
}
...
public interface AuditRepositoryCustom {
public Audit audit(Audit audit);
....
public interface AuditRepository extends GenericRepository<Audit, Long>,
AuditRepositoryCustom {
...
#NoRepositoryBean
public class AuditRepositoryImpl extends GenericRepositoryImpl<Audit, Long>
implements AuditRepositoryCustom {
private static Logger log = LoggerFactory.getLogger(AuditService.class);
public AuditRepositoryImpl(Class<Audit> domainClass, EntityManager em) {
super(domainClass, em);
log.debug("AuditDAO Created...");
// TODO Auto-generated constructor stub
}
#Autowired
public AuditRepositoryImpl(EntityManager em) {
super(Audit.class, em);
}
public AuditRepositoryImpl(
JpaEntityInformation<Audit, ?> entityInformation,
EntityManager entityManager) {
super(entityInformation, entityManager);
log.debug("AuditDAO Created...");
// TODO Auto-generated constructor stub
}
#Override
public Audit audit(Audit audit) {
return super.save(audit);
}

Resources