0
votes

I have been using Spring data with hibernate and I would like to know what is the best class organizations avoiding waste of code. This is my actual structure:

    public interface FleetRepository extends JpaRepository<Fleet, Integer> {
}

then I use this interface

public interface FleetServices {

     //Create one row into Fleet table, if id already exists this method executes an update
     public Fleet create(Fleet fleet);
     //Check if a fleet with given id already exists
     public boolean exists(int id);
}

and therefore I implemented it

@Service
public class FleetServicesImpl implements FleetServices{

    @Resource
    private FleetRepository fleetRepository;

    @Override
    @Transactional
    public Fleet create(Fleet fleet) {
         return fleetRepository.save(fleet);
    }

    @Override
    @Transactional
    public boolean exists(int id){
        return fleetRepository.exists(id);
    }
}

Given that I have several classes that use the same method (e.g. save, create ...) I thought to create one class general to use for all these methods, like this

public interface GeneralRepository<T, Id extends Serializable> extends JpaRepository<T, Id> {
    }

then

public interface GeneralServices<T,Id> {
    //Create one row into T table, if id already exists this method executes an update
    public T create(T object);
    //Check if a row with given id already exists
    public boolean exists(Id id);
    //Find a row into T table by Id
    public T findById(Id id);
}

Finally

public class GeneralServicesImpl<T, Id extends Serializable > implements GeneralServices<T, Id> {

    @Resource
    private GeneralRepository<T,Id> generalRepository;

    @Override
    @Transactional
    public T create(T object) {
        return generalRepository.save(object);
    }

    @Override
    @Transactional
    public boolean exists(Id id) {
        return generalRepository.exists(id);
    }

    @Override
    @Transactional
    public T findById(Id id) {
        return generalRepository.getOne(id);
    }

}

so then I use this class into my FleetServicesImpl

@Service
public class FleetServicesImpl extends GeneralServicesImpl<Fleet, Integer> implements FleetServices  { 
}

so in databaseServicesImpl

@Service

public class DatabaseServicesImpl implements DatabaseServices {

@Autowired
private FleetServices fleetServices;
@Autowired
private EcuServicesImpl ecuServices;

public DatabaseServicesImpl() {
}

@Override
public void archiveAcquisition() {
    ecuServices.create(new Ecu("MM"));
    Ecu ecuId=ecuServices.findById("MM");
    Fleet fleet=new Fleet(ecuId,"334","2.9",170,"5+","Full","4x2","MT");
    System.out.println(ecuId.getIdEcu());
    fleetServices.create(fleet);
}

} but I obtain this exception

16:41:43.465 ERROR o.s.web.context.ContextLoader - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'databaseServicesImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mkyong.services.EcuServicesImpl com.mkyong.services.DatabaseServicesImpl.ecuServices; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ecuServicesImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generalRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:334) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446) ~[spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328) ~[spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) [spring-web-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4727) [catalina.jar:8.0.26] at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5167) [catalina.jar:8.0.26] at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) [catalina.jar:8.0.26] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408) [catalina.jar:8.0.26] at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398) [catalina.jar:8.0.26] at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_60] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_60] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_60] at java.lang.Thread.run(Thread.java:745) [na:1.8.0_60] Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mkyong.services.EcuServicesImpl com.mkyong.services.DatabaseServicesImpl.ecuServices; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ecuServicesImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generalRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:571) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:331) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] ... 22 common frames omitted Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'ecuServicesImpl': Injection of resource dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generalRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an managed type: class java.lang.Object at org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.postProcessPropertyValues(CommonAnnotationBeanPostProcessor.java:311) ~[spring-context-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1145) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1069) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:967) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:543) ~[spring-beans-4.2.1.RELEASE.jar:4.2.1.RELEASE] ... 24 common frames omitted Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'generalRepository': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Not an manageset 29, 2015 4:41:43 PM org.apache.catalina.core.StandardContext listenerStart

1
If you service is only a pass through service why bother writing one at all. The only valid implementation imho is the DatabaseService which should be @Transactional. The others toss them in the bin and work with the repositories in the DatabaseService.M. Deinum
I updated my code above. I think that type of the repository has to be known at bootstrap time,luca

1 Answers

0
votes

Quoting Oliver Gierke (Spring Data Project Lead):

The last exception you get actually indicates a problem with your JPA setup. "Not a managed bean" means not a type the JPA provider is aware of. If you're setting up a Spring based JPA application I'd recommend to configure the "packagesToScan" property on the LocalContainerEntityManagerFactory you have configured to the package that contains your JPA entities. Alternatively you can list all your entity classes in persistence.xml, but that's usually more cumbersome.

Make sure your Spring configuration is set up properly, it seems not all classes are being recognized by Spring.

To add to that, heres an answer by Oliver regarding generic repositories in Spring JPA since you seem to be using it.