Repository autowired returning null - spring-data-jpa

I want to make a application with Spring boot on back-end and Swing on front-end. I need to use a repository autowired on my service class, how to make it when i need to instantiate the service class?
I already tried change the repository to BeanFactory, tried to change the location of the files but i can't escape! I need to instantiate the Service class and autowired doesn't work with this.
I have a Model called Permission.
Repository (PermissionRepository.java):
#Repository
public interface PermissionRepository extends JpaRepository<Permission, Long>{
Optional<Permission> findByDescription(String description);
}
Service (PermissionService.java):
#Autowired
BeanFactory beanFactory;
public List<Permission> loadAll() {
return this.beanFactory.getBean(PermissionRepository.class).findAll();
}
Use (BasicOperations.java):
public static void initialPermission() {
try {
if (new PermissionService().loadAll().isEmpty()) {
//logics
}
} catch(Exception e) {
...
}
}
I expect a List, java.util.List but, the error is a nullPointer on my autowired repository
Stack:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.riTrap.service.PermissionService.loadAll(PermissionService.java:20)

You should use autowired instead of new PermissionService. You use loadAll to check if the database contains elements. If the database is big, this approach can damage your application. Suggestion : use count instead
#Service
public class PermissionService {
#Autowired
PermissionRepository permissionRepository;
public List<Permission> loadAll() {
return permissionRepository.findAll();
}
public boolean isEmpty() {
return permissionRepository.count() == 0L;
}
}
If you need to initialize the bean before usage, you can use the constructor :
#Service
public class BasicOperations {
#Autowired
public BasicOperations(PermissionService permissionService){
if(permissionService.isEmpty()){
//DO STUFF
}
}
}

Related

Spring Boot Hibernate Postgresql #Transactional does not rollback [duplicate]

I want to read text data fixtures (CSV files) at the start on my application and put it in my database.
For that, I have created a PopulationService with an initialization method (#PostConstruct annotation).
I also want them to be executed in a single transaction, and hence I added #Transactional on the same method.
However, the #Transactional seems to be ignored :
The transaction is started / stopped at my low level DAO methods.
Do I need to manage the transaction manually then ?
Quote from legacy (closed) Spring forum:
In the #PostConstruct (as with the afterPropertiesSet from the InitializingBean interface) there is no way to ensure that all the post processing is already done, so (indeed) there can be no Transactions. The only way to ensure that that is working is by using a TransactionTemplate.
So if you would like something in your #PostConstruct to be executed within transaction you have to do something like this:
#Service("something")
public class Something {
#Autowired
#Qualifier("transactionManager")
protected PlatformTransactionManager txManager;
#PostConstruct
private void init(){
TransactionTemplate tmpl = new TransactionTemplate(txManager);
tmpl.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
//PUT YOUR CALL TO SERVICE HERE
}
});
}
}
I think #PostConstruct only ensures the preprocessing/injection of your current class is finished. It does not mean that the initialization of the whole application context is finished.
However you can use the spring event system to receive an event when the initialization of the application context is finished:
public class MyApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
public void onApplicationEvent(ContextRefreshedEvent event) {
// do startup code ..
}
}
See the documentation section Standard and Custom Events for more details.
As an update, from Spring 4.2 the #EventListener annotation allows a cleaner implementation:
#Service
public class InitService {
#Autowired
MyDAO myDAO;
#EventListener(ContextRefreshedEvent.class)
public void onApplicationEvent(ContextRefreshedEvent event) {
event.getApplicationContext().getBean(InitService.class).initialize();
}
#Transactional
public void initialize() {
// use the DAO
}
}
Inject self and call through it the #Transactional method
public class AccountService {
#Autowired
private AccountService self;
#Transactional
public void resetAllAccounts(){
//...
}
#PostConstruct
private void init(){
self.resetAllAccounts();
}
}
For older Spring versions which do not support self-injection, inject BeanFactory and get self as beanFactory.getBean(AccountService.class)
EDIT
It looks like that since this solution has been posted 1.5 years ago developers are still under impression that if a method,
annotated with #Transactional, is called from a #PostContruct-annotated method invoked upon the Bean initialization, it won't be actually executed inside of Spring Transaction, and awkward (obsolete?) solutions get discussed and accepted instead of this very simple and straightforward one and the latter even gets downvoted.
The Doubting Thomases :) are welcome to check out an example Spring Boot application at GitHub which implements the described above solution.
What actually causes, IMHO, the confusion: the call to #Transactional method should be done through a proxied version of a Bean where such method is defined.
When a #Transactional method is called from another Bean, that another Bean usually injects this one and invokes its proxied (e.g. through #Autowired) version of it, and everything is fine.
When a #Transactional method is called from the same Bean directly, through usual Java call, the Spring AOP/Proxy machinery is not involved and the method is not executed inside of Transaction.
When, as in the suggested solution, a #Transactional method is called from the same Bean through self-injected proxy (self field), the situation is basically equivalent to a case 1.
#Platon Serbin's answer didn't work for me. So I kept searching and found the following answer that saved my life. :D
The answer is here No Session Hibernate in #PostConstruct, which I took the liberty to transcribe:
#Service("myService")
#Transactional(readOnly = true)
public class MyServiceImpl implements MyService {
#Autowired
private MyDao myDao;
private CacheList cacheList;
#Autowired
public void MyServiceImpl(PlatformTransactionManager transactionManager) {
this.cacheList = (CacheList) new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
#Override
public Object doInTransaction(TransactionStatus transactionStatus) {
CacheList cacheList = new CacheList();
cacheList.reloadCache(MyServiceImpl.this.myDao.getAllFromServer());
return cacheList;
}
});
}
The transaction part of spring might not be initialized completely at #PostConstruct.
Use a listener to the ContextRefreshedEvent event to ensure, that transactions are available:
#Component
public class YourService
implements ApplicationListener<ContextRefreshedEvent> // <= ensure correct timing!
{
private final YourRepo repo;
public YourService (YourRepo repo) {this.repo = repo;}
#Transactional // <= ensure transaction!
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
repo.doSomethingWithinTransaction();
}
}
Using transactionOperations.execute() in #PostConstruct or in #NoTransaction method both works
#Service
public class ConfigurationService implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationService.class);
private ConfigDAO dao;
private TransactionOperations transactionOperations;
#Autowired
public void setTransactionOperations(TransactionOperations transactionOperations) {
this.transactionOperations = transactionOperations;
}
#Autowired
public void setConfigurationDAO(ConfigDAO dao) {
this.dao = dao;
}
#PostConstruct
public void postConstruct() {
try { transactionOperations.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(final TransactionStatus status) {
ResultSet<Config> configs = dao.queryAll();
}
});
}
catch (Exception ex)
{
LOG.trace(ex.getMessage(), ex);
}
}
#NoTransaction
public void saveConfiguration(final Configuration configuration, final boolean applicationSpecific) {
String name = configuration.getName();
Configuration original = transactionOperations.execute((TransactionCallback<Configuration>) status ->
getConfiguration(configuration.getName(), applicationSpecific, null));
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
}
}

EJB not initializing in Wildfly 9.0.0 using #EJB

I'm trying to migrate from EJB2.x to EJB3.x and i'm using Wildfly 9.0.0.
The old EJB2.x is working in JBoss 4.2.2 and this is how it looks like:
public interface WUFFacadeRemote extends EJBObject {
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
public interface WUFFacadeHome extends EJBHome {
public WUFFacadeRemote create();
}
public class WUFFacade {
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
}
public class WUFAction extends HttpServlet implements IAction {
public void doPost(HttpServletRequest request, HttpServletResponse response) {
...
Object objRef = ic.lookup("java:comp/env/wUF");
com.wuf.WUFFacadeHome home = (com.wuf.WUFFacadeHome) PortableRemoteObject.narrow(objRef, com.wuf.WUFFacadeHome.class);
engine = home.create();
//engine gets the reference, and I can use it normally.
...
}
}
I also have the ejb-jar.xml and it's working. Now, the solution I was thinking to EJB3.x and Wildfly 9.0.0 is as below:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet implements IAction {
#EJB
private WUFFacadeRemote engine;
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Here I should be able to use my engine.
//Wildfly starts and I call the page, engine is not null at this moment,
//but after I call the page again, it becomes null and remains null.
}
}
#Stateless
#Remote(WUFFacadeRemote.class)
public class WUFFacade extends RootFacade implements WUFFacadeRemote, Serializable {
public WUFFacade() { }
#EJB
FUFHome home;
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
private Col load(ClientData data,InitialContext ic) {
//here i'm calling home.
// but home is always null. It was supposed to have the #EJB reference initialized.
//But instead I get a null pointer...
home.findByFilter(loader);
}
}
#Remote(FUFHome.class)
public interface FUFHome {
FUF create(FUFValue fUFValue);
FUF findByPrimaryKey(FUFPK pk);
Collection findByFilter(FacadeLoader loader);
}
public interface WUFFacadeRemote{
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
I don't have ejb-jar.xml anymore, the deploy is sucessfully done and Wildfly starts with no errors. Then the first time I call the page in question, it seems that #EJB is working (Debug is "Proxy for remote EJB StatelessEJBLocator for "bus-facade/WUFFacade", view is interface com.wuf.WUFFacadeRemote, affinity is None"), the value is not null, but for all subsequent calls, my variable is null and I got a NullPointerException.
I really don't know what i'm doing wrong (maybe i'm completely lost), but to me, #EJB should be working correctly like that. What am I missing? Thanks.
As i'm using EJB3.x i'm just using annotations now, (this seems to be ok).
JNDIs:
JNDI bindings for session bean named FUF in deployment
java:global/fumo/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:app/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:module/FUF!apyon.components.fumo.fuf.FUF
java:global/fumo/bus-entities-fumo/FUF
java:app/bus-entities-fumo/FUF
java:module/FUF
JNDI bindings for session bean named WUFFacade
java:global/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:app/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:module/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:jboss/exported/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:global/fumo/bus-facade-fumo/WUFFacade
java:app/bus-facade-fumo/WUFFacade
java:module/WUFFacade
I think I found a possible solution to the problem. I'll still try to find another one, but this is good so far.
After changing to a .war and keeping my other projects in .ears it's working. Maybe the problem was because I have a RootController servlet im my main.ear, which is the starting point of the aplication. The context starts there and then it redirects to fumo.ear (now fumo.war).
For some reason, I always was getting a null in my EJB after entering a page. It was always hapening when I first entered a JSP and tried to call the page again. My solution to this is:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet {
private WUFFacadeRemote engine;
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
doPost(req, resp);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
if(engine == null) {
InitialContext ic;
try {
ic = new InitialContext();
engine = (WUFFacadeRemote) ic.lookup("java:global/fumo/WUFFacade!fumo.wuf.WUFFacadeRemote");
} catch (NamingException e) {
e.printStackTrace();
}
}
//here I always have the context now.
}
}
And as a .war my structure now looks like this:
So other annotations like #Inject and #EJB are now working. Always when i'm being redirect from a JSP calling a Servlet or some action, I first check if the context is not null, otherwise I lookup it. My #Stateless are working and the #PersistenceContext and #Remote are working too.
#Stateless
public class WUFFacade implements WUFFacadeRemote {
#Inject
private FUFRules rules;
#EJB
private FUFHome home;
private Col load(ClientData data, InitialContext ic) throws InterfaceException {
try {
// home here is nor null anymore.
Collection res = (Collection) home.findByFilter(loader);
...
} catch (InterfaceException e) {
e.printStackTrace();
}
...
return data;
}
}
So I'd like to thank everyone who helped in the thread. It was a good way to understand and see the problem or to find a workaround. As I said, I'll still try the .ear in the future, but as a simplified packaging it definitely works.

ApplicationContext Exception in Test with #WebMvcTest

I Have an Spring Boot Application (1.5.10.RELEASE) which contains a main (SpringBootApplication) like this:
#SpringBootApplication
#Configuration
#EntityScan(basePackages = { "db.modell", "db.modell.base" })
#ComponentScan(basePackages = { "de.gui.test" })
public class SpringBootConsoleApplication {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
}
and two REST controllers like the following:
#RestController
#RequestMapping("/as")
public class AController {
#Autowired
private ARepository aRepository;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Collection<A>> getAs() {
return new ResponseEntity<>(orgtFarbeRepository.findAll(), HttpStatus.OK);
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public ResponseEntity<A> getA(#PathVariable long id) {
A a = ARepository.findOne(id);
if (party != null) {
return new ResponseEntity<>(ARepository.findOne(id), HttpStatus.OK);
} else {
return new ResponseEntity<>(null, HttpStatus.NOT_FOUND);
}
}
}
Furthermore I have a single test like this:
#RunWith(SpringRunner.class)
#WebMvcTest(AController.class)
public class AControllerTest {
#Autowired
private MockMvc mvc;
#MockBean
private ARepository ARepository;
#Test
public void firstTest() throws Exception {
A a = new aFarbe();
a.set....
when(ARepository.findAll()).thenReturn(Collections.singleton(a));
mvc.perform(
get("/as")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
)
.andExpect(status().isOk());
}
}
The repositories look like this:
public interface ARepository extends CrudRepository<A, Long>
{
Collection<A> findAll();
}
public interface BRepository extends CrudRepository<B, Long>
{
Collection<B> findAll();
}
A and B them self are JPA annotated classes. The whole application contains access to a database..
Furthermore I have a Service like this:
#Service
public class XService {
private static final Logger LOGGER = LoggerFactory.getLogger(XService.class);
#Autowired
private ARepository aRepository;
#Autowired
private BRepository bRepository;
...
}
The XService is not used via #Autowire or so (Just need to remove that):
So I try to run the AControllerTest I get the following error:
java.lang.IllegalStateException: Failed to load ApplicationContext at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
.. .. at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:206)
Caused by:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'XService': Unsatisfied dependency
expressed through field 'BRepository'; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
.. .. at
org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at
org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 26 more Caused by:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No
qualifying bean of type 'BRepository' available: expected at least 1
bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1493)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1104)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
... 44 more
My assumption is that during the test more context is started than it should. The question is how can I prevent that? Which means only to start the context for the AControler and nothing more? I thought that based on the #WebMvcTest(AController.class) it should be limited already which looks like that it was not the case...
The referenced answer does not really answered my question but a in the context a hint gave me the solution. This means in consequence to add the following to my test:
so I have to add #OverrideAutoConfiguration(enabled=true):
#RunWith(SpringRunner.class)
#WebMvcTest(OrgtFarbenController.class)
#OverrideAutoConfiguration(enabled=true)
public class AControllerTest {
...
}

How to inject dynamic EntityManager into a Third Party Library

I have a library with some functionality that I want to reuse in other projects. My issue is that my service requires writing to the database. I would like for my library to use the datasource of the project that is inject my service.
Here is the minimal setup of my service
#Stateless
public class CustomService {
//to be added in producer
private EntityManager em;
private Principal principal;
//default constructor
public CustomService() {}
//custom constructor called in provider
public CustomService(Principal p, EntityManager e) {
principal = p;
em = e;
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Transactional
public CustomJPAObject createObject(...params...) {
//create JPA Object
em.persist(customObject);
em.flush();
return customObject;
}
}
I created a Custom Annotation for overriding the datasource
#Qualifier
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE,ElementType.FIELD, ElementType.METHOD})
public #interface DynamicDS {
#Nonbinding String value() default "";
}
I also created a Singleton to be an EntityManager Producer
#Singleton
public class CustomEMProducer {
private Map<String, EntityManagerFactory> emfMap = new HashMap<>();
#Produces #Dependent #DynamicDS
public EntityManager produceEntityManager(InjectionPoint injectionPoint) {
String dataSourceName = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof DynamicDS) {
DynamicDS dds = (DynamicDS) qualifier;
dataSourceName = dds.value();
break;
}
}
EntityManagerFactory emf = emfMap.get(dataSourceName);
if (emf == null) {
emf = Persistence.createEntityManagerFactory(dataSourceName);
emfMap.put(dataSourceName, emf);
}
return emf.createEntityManager();
}
#PostConstruct
public void cleanup() {
emfMap.entrySet().stream().forEach(entry -> entry.getValue().close());
}
}
Here is the code for my Service Producer
#Stateless
public class CustomServiceProvider {
#Inject private Principal principal;
#Produces #Dependent #DynamicDS
public BackgroundJobService getBackgroundJobService(InjectionPoint injectionPoint) throws EntityManagerNotCreatedException {
Annotation dsAnnotation = null;
for(Annotation qualifier: injectionPoint.getQualifiers()) {
if(qualifier instanceof BackgroundJobDS) {
dsAnnotation = qualifier;
break;
}
}
if (dsAnnotation != null) {
EntityManager em = CDI.current().select(EntityManager.class, dsAnnotation).get();
CustomService service = new CustomService(principal, em);
return service;
}
throw new EntityManagerNotCreatedException("Could not Produce CustomService");
}
}
The following is where I try to inject my new service
#Stateless
public class ProjectService {
#Inject #DynamicDS("project-ds") CustomerService service;
public CustomObject create(...params...) {
return service.createObject(...params...);
}
}
When I deploy my code and attempt to call the injected service I get the following error:
Caused by: javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1171)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1332)
...
It looks like all of the different levels of providers are preventing the #Transactional on the CustomService.createObject() method call from propagating the transaction. Does anyone have insight into why this is or an alternate way of accomplishing my goal of injecting a dynamic EntityManager?
After much experimenting, I was unable to get dynamically generate an EntityManager through the above code. After much research, I gave up on trying to pass in the name from outside the 3rd part library. I would up creating the following interface:
public interface CustomEntityManager {
EntityManager getEntityManager();
}
This meant that inside the project that uses the 3rd party service I can do the create the following implementation to inject the EntityManager
public ProjectSpecificEntityManager implements CustomEntityManager {
#PersistenceContext(unitname = "project-ds")
private EntityManager em;
public EntityManager getEntityManager() {
return em;
}
}
I had to update my CustomService to the following
#Stateless
public class CustomService {
//Ignore warning about no bean eligible because it is intended
//that the project that uses this library will provide the
//implementation
#SuppressWarnings("cdi-ambiguous-dependency")
#Inject
CustomEntityManager cem;
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Transactional
public CustomJPAObject createObject(...params...) {
//create JPA Object
cem.getEntityManager().persist(customObject);
return customObject;
}
}

WickeTester - IllegalStateException: No CDI context bound to application

I have Wicket Form and ProjectNameValidator class:
#Inject
ProjectDao dao;
public ProjectNameValidator() {
CdiContainer.get().getNonContextualManager().inject(this);
}
the injection here is because the #Inject annotation works only in Wicket components or Behavior, here is null without the CdiContainer.get().getNonContextualManager().inject(this);
But when I have WicketTester, TestCreateprojectPage:
public class TestCreateProject {
private WicketTester tester;
#Before
public void setUp() throws Exception {
tester = new WicketTester();
}
#Test
public void createProjectPageRendersSuccessfully() {
tester.startPage(CreateProject.class);
tester.assertRenderedPage(CreateProject.class);
}
}
I'm getting exception on the Form in the CreateProject.java in ProjectNameValidator on this row:
CdiContainer.get().getNonContextualManager().inject(this);
IllegalStateException: No DCI Context bound to application.
You have a singleton CdiContainer in your application, that is not initialized in a test scope. So CdiContainer.get() is really null. Find out how to initialize CdiContainer test context, it depends on your implementation, and add it to test setUp().