Unsatisfied dependencies for injecting EJB service into web (war) - ejb

My beans.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="annotated">
</beans>
My service (backend - type EJB) looks like this:
import javax.inject.Inject;
import javax.transaction.Transactional;
#Default
#Transactional(Transactional.TxType.REQUIRED)
public class UserServiceImpl implements UserService {
#Inject
private UserDao userDao;
#Inject
private UserMapper mapper;
and #Named annotated bean uses this (web):
import javax.inject.Inject;
import javax.inject.Named;
import org.omnifaces.cdi.ViewScoped;
#ViewScoped
#Named("indexMBean")
public class IndexMBean extends AbstractViewBean {
#Inject
private UserService userService;
Build was success, but deploy gives me this exception:
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type UserService with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject private hu.food.bean.IndexMBean.userService
how can I set the Default injection for UserService?
the log says:
2018-11-12 11:28:25,706 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-2) MSC000001: Failed to start service jboss.deployment.unit."kaJava-ear-0.0.1-SNAPSHOT.ear".WeldStartService: org.jboss.msc.service.StartException in service jboss.deployment.unit."kaJava-ear-0.0.1-SNAPSHOT.ear".WeldStartService: Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.execute(ServiceControllerImpl.java:1728)
at org.jboss.msc.service.ServiceControllerImpl$ControllerTask.run(ServiceControllerImpl.java:1556)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1985)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1487)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1378)
at java.lang.Thread.run(Thread.java:748)
Caused by: org.jboss.weld.exceptions.DeploymentException: WELD-001408: Unsatisfied dependencies for type UserService with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject private hu.food.bean.IndexMBean.userService
at hu.food.bean.IndexMBean.userService(IndexMBean.java:0)

You set bean-discovery mode to annotated. so only beans annotated with a scope type will be detected
bean-discovery-mode="annotated">
please add a scope type annotation like #dependent to your bean
#Default
#Transactional(Transactional.TxType.REQUIRED)
#Dependent
public class UserServiceImpl implements UserService {
http://docs.jboss.org/cdi/spec/1.2/cdi-spec.html#bean_defining_annotations says:
The set of bean defining annotations contains:
#ApplicationScoped, #SessionScoped, #ConversationScoped and
#RequestScoped annotations,
all other normal scope types,
#Interceptor and #Decorator annotations,
all stereotype annotations (i.e. annotations annotated with
#Stereotype),
and the #Dependent scope annotation.

You are using annotated discovery mode in your beans.xml this means that only beans with so called Bean defining annotations are discovered and registered as beans. Consult CDI spec for all the annotations that belong there; for your use case, you are missing bean scope.
If you remove #Default qualifier from UserServiceImpl (it is useless, it is added there anyway; spec link) and add a scope to the bean, it should work.
Based on how your bean should behave (from the lifecycle point of view), you can make it #ApplicationScoped, #SessionScoped, #RequestScoped, #ConversationScoped, #Dependent (, #Singleton).

Related

Please help to explain a strange combination of Lombok's #AllArgsConstructor and spring's #RestController

I'm working on a spring project from our customer.
Below is the code for controller
#Log4j2
#RestController
#AllArgsConstructor
#RequestMapping(path = "/api/theapi")
#Api(value = "Description for the API")
public class TheAPIController {
private final ModelMapper modelMapper;
private final ObjectMapper objectMapper;
private final TheDemoService demoService;
...other code for controller
}
Below is the code for Service:
#Service
public class TheDemoService{ ... }
I was so surprise about 2 things:
Question 1: Why we need to use #AllArgsConstructor from project Lombok?
As per my understanding, Spring provide #RestController that Spring runtime container will initialize an Instance for our Controller. So that, having a constructor for our Controller seems like an invalid approach for using Spring Inversion of Control, is this correct?
Question 2. Because of using #AllArgsConstructor, somehow, the instance for demoService is to be injected
But again, I surprise because the code of Controller does not have #Autowired in combine with demoService.
In the actual code, there is no #Autowired for "private final TheDemoService demoService".
Hence, I could think of a possibility there, is that because of Lombok's #AllArgsConstructor would inject an instance of our TheDemoService via a constructor of
TheAPIController, I could not reason anything about this logic.
It's Invalid approach, no need for defining constructor for RestController
It's implicitly auto wiring the service
if a class, which is configured as a Spring bean, has only one constructor, the Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
To sum up #AllArgsConstructor can/should be removed

JHipster RestController WebMvcTest fails to load

I'm using JHipster 6.2.0 and I want to create a WebMvcTest for a RestController. When I run the test, the application context does not load and I get:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.mytest.security.jwt.TokenProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
I'm using junit5 and spring boot 2.1.7
I tried adding #MockBean TokenProvider tokenProvider, and then the next missing dependency is CorsFilter. Mocked that but then I get a IllegalArgumentException because the mocked CorsFilter does not have a filter name defined. I thought about disabling the security filters, but I would like to keep the test configurations as vanilla as possible, utilizing the WebMvcTest default configurations.
I reproduced the issue with this simple example.
package com.example.mytest.web.rest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
#RequestMapping("/api")
public class MyController {
#GetMapping("/my")
public MyResponse get() {
MyResponse myResponse = new MyResponse();
myResponse.text = "test";
return myResponse;
}
static class MyResponse {
String text;
}
}
package com.example.mytest.web.rest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.junit.jupiter.api.Assertions.*;
#WebMvcTest(MyController.class)
class MyControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void get() {
// doesn't run, due to NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.mytest.security.jwt.TokenProvider' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
}
}
I expect that I should be able to run a GET mockMvc test without having to mock a CorsFilter name. This mocking would need to be done in every WebMvcTest and is very repetitive. I don't want to run a full #SpringBootTest for every RestController. All the generated RestController tests are #SpringBootTests and run in a full application context.
Some similar questions:
Spring Boot 2.1 - #WebMvcTest without Spring Security Auto-Configuration
Security configuration on Spring Boot 2.1 - How to keep the default instead of my custom for tests?

How do I inject an EJB in Spring MVC using annotations?

My dispatcher-servlet.xml has basically:
<context:component-scan base package="package.ejb" />
<mvc:annotation-driven />
In the #Controller class I have:
#Controller
public class ApplicationController {
#EJB(lookup="java:global/MyEarName/MyWebModuleName/BeanImplementation!package.ejb.morepackages.BeanImplementation")
private MyBeanInterface myBean;
This didn't work, it looks like Spring doesn't see the #EJB annotation and it gives an error at deploy time saying it doesn't find any Autowire candidate. So I added the following code:
#Autowired
#Qualifier("BeanImplementation")
public void setMyBean(MyBeanInterface myBean) {
this.myBean = myBean;
}
And on my bean implementation:
#Component("BeanImplementation")
#Stateless(mappedName = "BeanImplementation", name = "BeanImplementation")
#LocalBean
public class BeanImplementation implements MyBeanInterface {
It worked, but I need to use the lookup string of the EJB and I can't since Spring doesn't see #EJB. I was forced to revert to a non-Spring application to use #EJB(lookup="...").
So, to clarify the question: how do I inject an EJB in Spring MVC using annotations and using the EJB lookup string? Thanks.

spring boot test unable to inject TestRestTemplate and MockMvc

I am using spring boot 1.4.0.RELEASE. I am writing tests for my controller class. I get the following exception.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.concur.cognos.authentication.service.ServiceControllerITTest': Unsatisfied dependency expressed through field 'restTemplate': No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.boot.test.web.client.TestRestTemplate] found for dependency [org.springframework.boot.test.web.client.TestRestTemplate]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here is my test class
public class ServiceControllerITTest extends ApplicationTests {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private MockMvc mvc;
#Test
public void exampleTest() throws Exception {
// test
}
}
ApplicationTests.java
#RunWith(SpringRunner.class)
#SpringBootTest
#WebAppConfiguration
//#DirtiesContext
public class ApplicationTests {
#Autowired
Environment env;
#Test
public void contextLoads() {
}
}
TestRestTemplate is only auto-configured when #SpringBootTest has been configured with a webEnvironment that means it starts the web container and listens for HTTP requests. For example:
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
If you read the java doc of SpringBootTest annotation, it says that annotation provides below features (not listing all of them here, but only what are relevant to the question.)
Provides support for different webEnvironment modes, including the ability to start a fully running web server listening on a defined or random port.
Registers a TestRestTemplate and/or WebTestClient bean for use in web tests that are using a fully running web server listening on a defined or random port.
So #SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT) provides the ability to autowire TestRestTemplate because it starts a fully running web server [as mentioned in #AndyWilkinson' answer as well].
But if you want to autowire MockMvc as well in same TestClass then use
#AutoConfigureMockMvc annotation over TestClass.
This is how a Test class may look like:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class SBTest {
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private MockMvc mvc;
// tests
}
To work with that, don't use a deprecated TestRestTemplate.
Deprecated:
import org.springframework.boot.test.TestRestTemplate;
Correct:
import org.springframework.boot.test.web.client.TestRestTemplate;
Then you can use the #Autowired annotation in your class:
#Autowired
private TestRestTemplate restTemplate;
And don't use:
#Autowired
private MockMvc mvc;
Both together doesn't work.
According to Spring boot documentation :
You can also auto-configure MockMvc in a non-#WebMvcTest (e.g. SpringBootTest) by annotating it with #AutoConfigureMockMvc.

Spring #EventListener annotation doesn't work with #Service annotation

Here are two objects I want to receive ContextRefreshedEvent
#Component
public class InitDB {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
//
}
}
InitDB works as expected, but in this case not:
#Service
public class MyService implements IMyService{
#Autowired
private MyDao _dao; // Autowired WORKs
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
// DOESN'T WORK
}
[...]
}
Any Idea what I'm doing wrong?
Here are my maven properties
<properties>
<java-version>1.7</java-version>
<org.springframework-version>4.2.2.RELEASE</org.springframework-version>
<spring-security-web-version>3.2.5.RELEASE</spring-security-web-version>
<org.aspectj-version>1.7.2</org.aspectj-version>
<org.slf4j-version>1.5.10</org.slf4j-version>
<hibernate-version>4.3.6.Final</hibernate-version>
<json-jackson-version>2.4.1</json-jackson-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skipTests>true</skipTests>
</properties>
I had the same problem and for me, it proved my listener bean wasn't loaded in the dependencies by Spring.
If you use Spring Boot Actuator, you can check the loaded beans at https://localhost:8443/beans.
The bean wasn't detected by Spring because I had a namespace typo. My main namespace was com.foo (with packages like com.foo.security and com.foo.controllers), and when I added a new package logging, I introduced a typo in the namespace: com.ffoo.logging.
Because of this, Spring could not find the new Components/Services I was adding.
For this particular question, it doesn't matter if it's annotated with #Service, because #Service is a sub-class of #Component (see post)

Resources