JSF 2.3 CDI with spring beans - spring

JSF 2.3, CDI, Tomcat 10, Spring bean.
I would like to use the latest JSF 2.3 capabilities from Jakarta with spring jdbc. Since JSF is now part of Jakarta and covered under CDI I am struggling how to initialise spring beans and connect it with JSF. My environment is
Tomcat 10.x with boss weld (weld-servlet-shaded 5.0.0) to support CDI
JSF (jakarta.faces from glass fish 4.0.0)
Spring core, context and jdbc (6.0.2), I am not using spring-web (i do not want to use as i have jsf as my web) and no spring boot.
**I have my jsf bean as below **
#Named
#RequestScoped
public class UserProfile {
#Inject
private UserService userService;
public String getMessage() {
return userService.getMessage();
}
}
Spring service as
#Service
public class UserService {
#Inject
private UserDao userDao;
public String getMessage() {
return userDao.getMessage();
}
}
**And Dao as **
#Repository
public class UserDao extends JdbcDaoSupport{
#Autowired
private DataSource dataSource;
#PostConstruct
public void init() {
setDataSource(dataSource);
}
public String getMessage(){
Integer empCount = getJdbcTemplate().queryForObject("SELECT COUNT(*) FROM EMPLOYEE", Integer.class) ;
return empCount.toString();
}
}
Datasource, Hikari configuration and jdbcTemplate is defined under applicationContext.xml
Unfortunately I am not getting my datasource initialised..
Any clue?
I have tried the traditional way of jsf spring integration but it did not work, my question is
Do i need spring web here ? as I have JSF i do not want to make it complex using spring web.
Do i Need Jboss weld here? or tomcat 10 support CDI 2.0 should i skip?
I want all spring beans to be initialised on tomcat start and ready for all request via JSF.

Related

EJB injected to #Controller

I am trying to inject EJB into spring #Controller (spring boot), each time I receive null pointer on stetelessBean.tt();
#Local
public interface IStetelessBean {
void tt();
}
#Stateless
public class StetelesBean implements IStetelessBean {
public void tt(){
System.out.println("ttt");
}
}
#Controller
public class PersonService {
#EJB
IStetelessBean stetelessBean;
#RequestMapping("/test")
public void test(){
stetelessBean.tt();
}
}
Any idea? I am not sure what is wrong.
Spring can only inject beans, it knows about. By default, EJBs are not registered as Spring Beans. Also the #EJB annotation is not recognised by Spring. The only examples in the Spring documentation use XML configuration, so far i could not find any example for Java configuration. You might be better off with changing your EJB into a Spring component, if that's possible.

Is it possible to construct an object partially with Spring DI and partially with Jersey DI?

I have a class JerseyWebService which uses Jersey DI to inject dependency
#Path("/baskets")
public class JerseyWebService {
#Inject
ExternalApiServiceInterface api;
...
}
The dependency is specified in the binder
public class CustomBinder extends AbstractBinder {
#Override
protected void configure() {
bind(ExternalApiService.class).to(ExternalApiServiceInterface.class);
...
}
But the problem here is that ExternalApiService has other dependencies and it uses Spring to inject them.
class ExternalApiService implements ExternalApiServiceInterface{
#Autowired
AnotherService aservice;
Is it possible to specify only some dependencies in binder which Jersey will Inject and other dependencies being injected by Spring ?
If not ,then if had been #Inject instead of #Autowired in ExternalApiService would it be mandatory to specify all bindings in the binder class?
Does Jersey DI has no Autowiring like feature or delegate injecting a dependency to Spring if it can't find any binding?
It should work. Given you have the required Spring-Jersey integration dependency[1] and have correctly configured the application[2]
1. See Spring DI support in Jersey
2. See official Jersey Spring example
What happens is HK2 (Jersey's DI framework) will look for an InjectionResolver for the #Autowired annotation, in order to resolve the dependency. The jersey-spring3 dependency has the AutowiredInjectionResolver, which holds a reference to Spring's ApplicationContext. From there it's just matter of looking it up in the application context, to resolve the dependency.

#Autowired service inside a #ManagedBean #Component class is null during JSF request [duplicate]

This question already has answers here:
Spring JSF integration: how to inject a Spring component/service in JSF managed bean?
(4 answers)
Closed 6 years ago.
I tried union Spring 3(MVC) with JSF 2. I have some experience in Spring and JSF, but never tried to join them before. In the end I have 2 files
#ManagedBean(name = "userBean")
#Scope
#Component
public class someBean {
#Autowired
private TestService testService;
public void printString() {
System.out.println(testService.getString());
}
}
and
#ManagedBean(name = "studentBean")
#Scope
#Component
public class StudentBean {
#Autowired
private TestService testService;
public void printString() {
System.out.println(testService.getString());
}
}
For these file I have right configuration for spring, jsf, and web.xml. And have .xhtml page where I start printString() for 'someBean' and for 'StudentBean'. I have the NPE in first case and 'some string' in the console in second case.
The reason is simple - different bean names in the Spring context and JSF. all problems finished after
#Component => #Component("userBean")
public class someBean {
In the debug I saw that
private TestService testService;
#Autowired
public void setTestService(TestService testservice) {
this.testService = testService;
}
When JSF bean is creating testService sets not null, but it is null during JSF lifecycle when
public void pringString() {
testService.blah();
}
testService is null. It is what I can't understand. Has someone deep knowledge the Spring and JSF to describe this situation in details?
Both JSF and Spring can act as bean containers. The #ManagedBean annotation instructs the JSF managed bean facility to create a new instance of the class, and manage it under the given name. The #Component annotation instructs the Spring ApplicationContext to create a new instance of the class, and manage it under the given name. That is, both JSF and Spring create an instance of that class, the JSF one is reachable through EL, but the Spring one gets its dependencies injected (because, being a spring annotation, #Autowired is not understood by the JSF managed bean facility).
So you have a choice: Use the JSF managed bean facility for everything (which I would not recommend, as it is rather limited), use CDI for everything (which is an option, but does not use Spring), or use Spring for everything (which I usually do), by removing the #ManagedBean annotation, and making Spring beans accessible through EL by registering a SpringBeanFacesELResolver in your faces-config.xml. The Spring reference manual describes this in section 19.3.1.
I had the same issue, it was due to the property name of #ManagedBean annotation.My backing bean looks like this
#Component
#ManagedBean(name="mainBean")
#SessionScoped
public class MainManagedBean{...}
As you can see, the name given to the bean (mainBean) is different to the default name (mainManagedBean) that the backing bean should have.
I have fixed the issue by setting the property name to "mainManagedBean". My bean becomes like this:
#Component
#ManagedBean(name="mainManagedBean")
#SessionScoped
public class MainManagedBean{...}
I wish this can help you
I believe the reason why testService is null is because testService has not been instantiated yet when managed bean is being constructed. So you can use #PostConstruct to inject Spring beans into a managed bean.
#ManagedBean(name = "userBean")
#Scope
#Component
public class someBean {
#Autowired
private TestService testService;
public void printString() {
System.out.println(testService.getString());
}
#PostConstruct
private void init() {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
ServletContext servletContext = (ServletContext) externalContext.getContext();
WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext).
getAutowireCapableBeanFactory().
autowireBean(this);
}
}
#Service
public class TestService {
......
}

Spring : autowiring inside non spring class

I have this HTTP listener subclass
public class MigificSessionListener implements HttpSessionListener {
#Autowired
#Qualifier("notificationThread")
private NotificationThread notificationThread;
#Override
public void sessionDestroyed(HttpSessionEvent hse) {
// here notificationThread value is null
}
}
Value of notificationThread inside sessionDestroyed() is null.
How can i autowire sessionDestroyed inside this class ?
Your MigificSessionListener in not in your spring conext, spring even do not know it exists.
You can use WebApplicationContextUtils to get your spring context from ServletContext
WebApplicationContextUtils.getWebApplicationContext(sessionEvent.getSession().getServletContext())
You can enable Spring AOP with #EnableSpringConfigured and annotate your class with #Configurable. This let spring manage instances which are created outside the spring context with new. You will also need to enable either load-time weaving or compile-time weaving. This is documented in 9.8.1 Using AspectJ to dependency inject domain objects with Spring.
#Configuration
#EnableSpringConfigured
public class AppConfig {
}
#Configurable
public class MigificSessionListener implements HttpSessionListener {
#Autowired
#Qualifier("notificationThread")
private NotificationThread notificationThread;
//...
}
Convert your non-Spring managed class MigificSessionListener into a Spring-managed one by annotating it with #Configurable.
For this annotation to be recognised you need <context:spring-configured/> in your Spring XML config or #EnableSpringConfigured if you are using Spring Java config.
The #Autowired or injection of other dependencies will then succeed.

Injecting JSF bean into Spring bean - impossible?

I have a JSF 2.0 bean:
#ManagedBean
#SessionScoped
public class LoginBean implements Serializable
{
protected String name;
public String getName()
{
return name;
}
//....
}
I have a Spring 3.0 bean:
#Repository
public class Logins
{
#ManagedProperty(value="#{loginBean}")
protected LoginBean loginBean;
public void recordLogin()
{
//... record in db that loginBean.getName() just logged in
}
}
This code doesn't work, Logins.loginBean is never set.
Alternatively (its the same question, simplified) - would the following code ever work?
#Repository
public class SpringBean
{
#ManagedProperty(value="#{session.id}")
protected String id;
//....
}
The ContextLoaderListener and RequestLoaderListener are declared in web.xml.
Is it possible at all to inject a JSF bean into a Spring bean? (Without using yet another extra framework)
Or should I rather convert my JSF bean into a Spring bean and use the DelegatingVariableResolver trick in faces-config.xml? I have already tested this with a test Spring bean, and it works.
Using JSF annotations in spring-managed beans doesn't work. And it shouldn't - you should not inject things from the web layer in the other layers. It should be the other way around - inject spring services (or repositories) into web components (jsf managed beans), and invoke methods on them, passing the managed bean properties as arguments

Resources