I have a number of JPA repositories classes and I want to create one common class where I will create a getter method of a respective repository and I will use that common class in the service layer.
So Can you please guide me with best practices that how can I achieve this?
Here I am sharing my idea by using sample code,
JPA repository
#Repository
public interface IConfigRepository extends JpaRepository<Config, Integer> {
}
public interface IBusinessRepository extends JpaRepository<Business, Integer> {
}
Repo Factory (Common Class for all repositories)
public class RepoFactory {
#Autowired
private IConfigRepository configRepo;
#Autowired
private IBusinessRepository businessRepo;
public IConfigRepository getConfigRepository() {
return configRepo;
}
public IBusinessRepository getBusinessRepository() {
return businessRepo;
}
}
Service Class
#Service
public class ServiceA {
public final RepoFactory repoFactory;
public ServiceA(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Config config) {
repoFactory.getConfigRepository().save(config);
}
}
#Service
public class ServiceB {
public final RepoFactory repoFactory;
public ServiceB(RepoFactory repoFactory) {
this.repoFactory = repoFactory
}
#Transactional(rollbackOn = Exception.class)
public void saveOrUpdate(Business reqBusiness) {
repoFactory.getBusinessRepository().save(reqBusiness);
}
}
Thanks, everyone for helping me in advance.
It looks like, you're trying to do something the #Profile annotation can help you with. If I were you, I would keep a common interface (not class) and make the IConfigRepository extend it. Then you can mark IConfigRepository with the #Profile annotation. If in the future, you have to write an analogue interface, you should also mark it with the #Profile annotation and you can switch between these interfaces anytime you want by setting the appropriate profile to active.
#Repository
#Profile("config")
public interface IConfigRepository extends CommonRepository, JpaRepository<Config,Integer> {
}
public interface CommonRepository {
}
#Service
public class ServiceA {
public final CommonRepository commonRepository;
public ServiceA(CommonRepository commonRepository) {
this.commonRepository = commonRepository
}
...
}
I have the following interface
public interface MTS{
public SrvResponse sendMessage(MTSModel msg);
public SrvResponse sendMessage(MTSModel msg, Type type);
}
the implementation
#Component
public class MTSImpl implements MTS {...}
Can I restrict user to autowire only interface private #Autowired MTS service; not MTSImpl in spring boot ?
Can I restrict user to autowire only interface private #Autowired MTS
service; not MTSImpl in spring boot ?
Spring doesn't provide such restrictions for injections.
As alternative you could "protected" your implementation class from clients by making it package private (the default access modifier) in a package that they don't use :
package foo.internal;
class MTSImpl implements MTS {
...
}
Or to hide it completely you could define it as an anonymous class :
#Bean
public MTS getMts() {
return new MTS() {
#Override
public SrvResponse sendMessage(MTSModel msg){
...
}
#Override
public SrvResponse sendMessage(MTSModel msg, Type type){
...
}
};
}
I want to refactor a method annotated with #PostContruct in a common class of all my controller.
public abstract class Controller {
#PostConstruct
protected void PostContruct() { ..}
}
public class AuthController extends Controller {}
public class CartController extends Controller {}
But spring doesn't seems to call my inherit method. What is the pattern to use in this situation ?
This works with Spring 4.2.0 and Spring Boot 1.2.5
public abstract class AbstractController {
#PostConstruct
protected void postConstruct() {
System.out.println("post construct");
}
}
#Controller
public class ConcreteController extends AbstractController {
}
It also works if you mark the method as abstract, keep the #PostConstruct in the parent and implement it in the child.
It does NOT work if #Controller is in the parent.
I have a basic question. I've been reading through some tutorials about spring and hibernate integration and in most of them there are DAO and Service layers like below:
public interface TeamDAO {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
Then the implementation of the DAO is provided using the SessionFactory. For example:
#Repository
public class TeamDAOImpl implements TeamDAO {
#Autowired
private SessionFactory sessionFactory;
//Implementation follows..
}
And then there's another service interface the same as the DAO interface like below:
public interface TeamService {
public void addTeam(Team team);
public void updateTeam(Team team);
public Team getTeam(int id);
public void deleteTeam(int id);
public List<Team> getTeams();
}
And the service implementation:
#Service
#Transactional
public class TeamServiceImpl implements TeamService {
//HERE IS MY QUESTION
#Autowired
private TeamDAO teamDAO;
//implementation follows
}
In the service implementation above where I marked "here is my question" I see that we inject only the interface TeamDAO which doesn't have the implementation of the TeamDAOImpl class. So how does the interface and its implementations get injected together in the service layer provided we only inject the interface TeamDAO and not TeamDAOImpl?
When you use #Autowired on an interface, Spring searches a bean instance whose class implements that interface. If it doesn't find any such bean, it fails. If it finds more than one class that implement the interface, it fails. Please refer to Spring #Autowired documentation for further details.
Spring injects TeamDAOImpl because it gets register as spring bean when you mark it as #Repository
So I have a number of generics in Spring 3.2 and ideally my architecture would look something like this.
class GenericDao<T>{}
class GenericService<T, T_DAO extends GenericDao<T>>
{
// FAILS
#Autowired
T_DAO;
}
#Component
class Foo{}
#Repository
class FooDao extends GenericDao<Foo>{}
#Service
FooService extends GenericService<Foo, FooDao>{}
Unfortunately with multiple implementations of the generics the autowiring throws an error about multiple matching bean definitions. I assume this is because #Autowired processes before type erasure. Every solution I've found or come up with looks ugly to me or just inexplicably refuses to work. What is the best way around this problem?
How about adding a constructor to the GenericService and move the autowiring to the extending class, e.g.
class GenericService<T, T_DAO extends GenericDao<T>> {
private final T_DAO tDao;
GenericService(T_DAO tDao) {
this.tDao = tDao;
}
}
#Service
FooService extends GenericService<Foo, FooDao> {
#Autowired
FooService(FooDao fooDao) {
super(fooDao);
}
}
Update:
As of Spring 4.0 RC1, it is possible to autowire based on generic type, which means that you can write a generic service like
class GenericService<T, T_DAO extends GenericDao<T>> {
#Autowired
private T_DAO tDao;
}
and create multiple different Spring beans of it like:
#Service
class FooService extends GenericService<Foo, FooDao> {
}
Here is a closest solution. The specialized DAOs are annotated at the business layer. As in the question from OP, the best effort would be having an annotated DAO in the EntityDAO generic template itself. Type erasure seems to be not allowing the specialized type information to get passed onto the spring factories [resulting in reporting matching beans from all the specialized DAOs]
The Generic Entity DAO template
public class EntityDAO<T>
{
#Autowired
SessionFactory factory;
public Session getCurrentSession()
{
return factory.getCurrentSession();
}
public void create(T record)
{
getCurrentSession().save(record);
}
public void update(T record)
{
getCurrentSession().update(record);
}
public void delete(T record)
{
getCurrentSession().delete(record);
}
public void persist(T record)
{
getCurrentSession().saveOrUpdate(record);
}
public T get(Class<T> clazz, Integer id)
{
return (T) getCurrentSession().get(clazz, id);
}
}
The Generic Entity Based Business Layer Template
public abstract class EntityBusinessService<T>
implements Serializable
{
public abstract EntityDAO<T> getDAO();
//Rest of code.
}
An Example Specialized Entity DAO
#Transactional
#Repository
public class UserDAO
extends EntityDAO<User>
{
}
An Example Specialized Entity Business Class
#Transactional
#Service
#Scope("prototype")
public class UserBusinessService
extends EntityBusinessService<User>
{
#Autowired
UserDAO dao;
#Override
public EntityDAO<User> getDAO()
{
return dao;
}
//Rest of code
}
You can remove the #autowire annotation and perform delayed “autowire” using #PostConstruct and ServiceLocatorFactoryBean.
Your GenericService will look similar to this
public class GenericService<T, T_DAO extends GenericDao<T>>{
#Autowired
private DaoLocator daoLocatorFactoryBean;
//No need to autowried, autowireDao() will do this for you
T_DAO dao;
#SuppressWarnings("unchecked")
#PostConstruct
protected void autowireDao(){
//Read the actual class at run time
final Type type;
type = ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[1];
//figure out the class of the fully qualified class name
//this way you can know the bean name to look for
final String typeClass = type.toString();
String daoName = typeClass.substring(typeClass.lastIndexOf('.')+1
,typeClass.length());
daoName = Character.toLowerCase(daoName.charAt(0)) + daoName.substring(1);
this.dao = (T_DAO) daoLocatorFactoryBean.lookup(daoName);
}
daoLocatorFactoryBean does the magic for you.
In order to use it you need to add an interface similar to the one below:
public interface DaoLocator {
public GenericDao<?> lookup(String serviceName);
}
You need to add the following snippet to your applicationContext.xml
<bean id="daoLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="org.haim.springframwork.stackoverflow.DaoLocator" />
</bean>
This is a nice trick and it will save you little boilerplate classes.
B.T.W I do not see this boilerplate code as a big issue and the project I working for uses matsev approach.
Why do you want a generic service ? Service classes are meant for specific units of work involving multple entities. You can just inject a repository straight into a controller.
Here is an example of generic repository with constructor argument, you could also make each method Generic instead and have no constructor argument. But each method call would require class as parameter:
public class DomainRepository<T> {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public DomainRepository(Class genericType) {
this.genericType = genericType;
}
#Transactional(readOnly = true)
public T get(final long id) {
return (T) sessionFactory.getCurrentSession().get(genericType, id);
}
Example of bean definition for the generic repository - you could have multple different beans, using different contstructor args.
<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>
Depdncy injection of bean using resource annotation
#Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;
And this allows the Domainreposiroty to be subclassed for specific entities/methods, which woul dallow autowiring :
public class PersonRepository extends DomainRepository<Person> {
public PersonRepository(){
super(Person.class);
}
...
You should use autowiring in classes which extends these generics
For this question one needs to understand about what autowire is. In common terms we can say that through autowire we create a object instance/bean at the time of deployment of the web app. So now going with the question if you are declaring autowiring in multiple places with the same name. Then this error comes. Autowiring can be done in multiple ways so if you are using multiple type of autowiring technique, then also one could get this error.
Complete Generic Solution using Spring 4:
Domain Class
#Component
class Foo{
}
#Component
class Bar{
}
DAO Layer
interface GenericDao<T>{
//list of methods
}
class GenericDaoImpl<T> implements GenericDao<T>{
#Autowired
SessionFactory factory;
private Class<T> domainClass; // Get Class Type of <T>
public Session getCurrentSession(){
return factory.getCurrentSession();
}
public DaoImpl() {
this.domainClass = (Class<T>) GenericTypeResolver.resolveTypeArgument(getClass(), DaoImpl.class);
}
//implementation of methods
}
interface FooDao extends GenericDao<Foo>{
//Define extra methods if required
}
interface BarDao extends GenericDao<Bar>{
//Define extra methods if required
}
#Repository
class FooDao extends GenericDaoImpl<Foo> implements FooDao{
//implementation of extra methods
}
#Repository
class BarDao extends GenericDaoImpl<Bar> implements BarDao{
//implementation of extra methods
}
Service Layer
interface GenericService<T>{
//List of methods
}
class GenericServiceImpl<T> implements GenericService<T>{
#Autowire
protected GenericDao<T> dao; //used to access DAO layer
}
class FooService extends GenericService<Foo>{
//Add extra methods of required
}
class BarService extends GenericService<Bar>{
//Add extra methods of required
}
#Service
class FooServiceImpl extends GenericServiceImpl<Foo> implements GenericService<Foo>{
//implementation of extra methods
}
#Service
class BarServiceImpl extends GenericServiceImpl<Bar> implements GenericService<Bar>{
//implementation of extra methods
}