JSF 2.3 (CDI) + Spring 4 integration - spring

I have created a new web project from scratch using JSF 2.3 and Weld as CDI implementation running on Tomcat 9. This works all fine.
Now I would like to add a dependency to a service library (Spring 4 + Hibernate 5) which implements e.g. the user authentication against a database. This is all existing code, so it cannot be modified.
I have already read many articles, but unfortunately no one really helped me. I am facing the issue that I do not know how to inject the Spring-Bean (4.3.12.RELEASE) into a JSF-CDI managed bean.
#Named
#RequestScoped
public class AuthenticationController extends AbstractBean {
#Inject
transient private IUserService _springUserService;
#PostConstruct
public void postConstruct() {
// _springUserService is null
}
}
The service implementation class is annotated as
#Repository(IUserService.BEAN_NAME)
public class UserService implements IUserService {
//...
}
In web.xmlI have configured the spring context loader:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:spring-config-domain.xml
</param-value>
</context-param>
And in faces-config.xml I have configured the Spring-EL-Resolver
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
</application>
So which annotation do I need to have the Spring Bean injected?
Am I missing any additional configuration for CDI in order to have it finding the Spring bean?
Thanks in advance and best regards!

Related

Spring+Jersey transactional annotation

Created boilerplate project to expose RESTful API to JPA enabled database. It's using the following versions:
- Spring 3.2.6
- Hibernate 4.3.0
- Jersey 2.5.1
I finally was able to get them playing together, but still some question remains. Here's one of the most puzzling things (see excerpt from REST service class)
#Service
#Path("resources")
#Produces({ MediaType.APPLICATION_JSON })
#Consumes({ MediaType.APPLICATION_JSON })
#Transactional
public class ResourceServices extends AbstractServices<Resource> {
...
}
if class is annotated with #Service, #Transactional annotation is ignored and transaction for the methods is not started. However, when changed to #Component, everything works fine. Couldn't figure out, why.
The entire project can be seen here
I got puzzled by this as well, but finally figured this out.
The jersey-spring module will only import #Component beans from your context. There literally is a beanClass.isAnnotationPresent(Component.class) check in SpringComponentProvider.
Otherwise it appears to only create half-baked request-scoped instances of the bean (I traced this with Thread.dumpStack in service constructor). They seem to have dependency injection, but not AOP.
There's a number of JIRA items already in Jersey's issue tracker: JERSEY-2495, JERSEY-2059, JERSEY-2301
UPDATE: My pull request for these has been merged, this should be fixed in Jersey 2.11.
As mentioned in another answer SpringComponentProvider gets a bean created by Jersey and registers it in the Spring context, but in this case you don't get Spring AOP.
I managed to get it working with AOP the other way around: the bean is created by Spring (so in fact it is a proxy because of AOP) and then is registered in Jersey.
But I had to fix a bug in Jersey's ModelHelper class: https://github.com/jersey/jersey/pull/90
Without this fix Jersey was not able to find the #Path annotation in the Spring proxy.
This is the basic structure:
public class MyApplication extends ResourceConfig {
#Inject
public MyApplication(ServletContext servletContext) {
super(JSONController.class, XSSSecurityFilter.class, JacksonFeature.class);
WebApplicationContext springFactory = WebApplicationContextUtils.getWebApplicationContext(servletContext);
// TODO: scan entire Spring factory for beans annotated with #Path and register them, so we don't need to do this manually.
// Letting Jersey register the beans does not work because in this case Spring will not intercept the calls.
register(springFactory.getBean(UserServiceFacade.class));
}
}
The reason is your Spring has a different container for its annotations and jersey has a different container for its annotations , in order to access your beans in spring container you can refer to the below code ;
I beg to differ from the version your using, I haven't tried with the latest version of jersey:
load spring through web.xml like shown below as normal spring confifuration:
<servlet>
<servlet-name>project-spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:project-spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>project-spring</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Now load your jersey Resources through Application as shown below:
#ApplicationPath("/rest")
public class ResourceLoader extends Application
{
/* (non-Javadoc)
* #see javax.ws.rs.core.Application#getClasses()
*/
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
loadResourceClasses(classes);
return classes;
}
private void loadResourceClasses(Set<Class<?>> classes)
{
classes.add(StudentResource.class);
}
}
Then in your resource:
#Path("student")
class StudentResource
{
private StudentService studentService;
StudentResource(#Context ServletContext servletContext)
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
this.studentService= applicationContext.getBean(StudentService .class);
}
}
You can get your ApplicationContext where all the beans have been initailized using WebApplicationContextUtils of spring pass the servlet context, and get your bean

Strange behaviour of #Configuration with #Configurable in Spring

I've been using XML based configuration for a while - we've got a Vaadin application with Spring used as DI, but we are not interested in DispacherServlet - only root context, which we use to inject global (not user owned dependencies).
The way it works
I've defined root-context.xml file with content:
<context:annotation-config />
<context:spring-configured />
<context:load-time-weaver />
<context:component-scan base-package="com.example" />
And my web.xml has in it:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Then, some of my classes are defined with #Component annotation and others with #Configurable (the latter mostly belong to user session, so require DI for each instance created with new keyword).
I've got context.xml file with line:
<Loader delegate="false" loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader" />
And spring-instrument-tomcat-3.2.1.RELEASE.jar in Tomcat's lib directory.
All the dependencies are injected (with #Autowire) to my #Configurable classes correctly.
The way it doesn't work
Recently I've tried to get rid of root-context.xml and move context initialisation to Java #Configuration class.
I've created a class as follows:
#Configuration
#EnableSpringConfigured
#EnableLoadTimeWeaving
#ComponentScan("com.example")
public class BeansConfiguration
{
}
In addition I changed web.xml entries:
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>com.example.spring.BeansConfiguration</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Unfortunately, strange things started to happen. Let me show you an example. Simplifying my class structure looks as follows:
#Component
public class ComponentA
{
}
#Configurable
public class BeanB
{
#Autowired
private ComponentA componentA;
}
#Configurable
public class BeanC
{
#Autowired
private ComponentA componentA;
private BeanB beanB;
public BeanC(BeanB beanB)
{
this.beanB = beanB;
}
}
#Configurable
public class Application
{
#Autowired
private ComponentA componentA;
public Application()
{
}
public void init()
{
BeanC beanC = new BeanC(new BeanB());
}
}
With the XML setup, when it does work, ComponentA is correctly injected by Spring into all my #Configurable objects.
Strangely, with annotation-only configuration BeanC doesn't get the ComponentA injected (it's always null), howewer BeanB and Application do get that!
Have you got any ideas why would it happen? As soon as I comment out lines in web.xml to go back to my previous (XML-based) configuration all starts to work.
My happy guess is that XML Spring entries register something more under the cover than their annotation based counterparts. I've spend half a day trying to find out, what could that be, but I gave up. I would appreciate any suggestions.

Jersey-Spring #Autowired not working

I'm using Jersey-Spring integration to expose business layer services.
In my web.xml I'm using the SpringServlet:
com.sun.jersey.spi.spring.container.servlet.SpringServlet
My business layer is #Component annotated, so I have #Service's using #Repository's provided via Spring's annotation config.
Repository's are provided to service's via #Autowired annotation.
If I use a repository through a service using my front end MVC classes everithig goes well, but if I use it through Jersey I get a NullPointerException on the repository object.
The version I'm using (through Maven) are:
Spring (and extensions): 3.1.3.RELEASE
Jersey (and extensions): 1.17
There is way to solve this problem using the same version mentioned in your question,
If needed ill mention the second way , the first way is to load sring through web.xml
like shown below as normal spring confifuration:
<servlet>
<servlet-name>project-spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:project-spring-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>project-spring</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>
Now load your jersey Resources through Application as shown below:
#ApplicationPath("/rest")
public class ResourceLoader extends Application
{
/* (non-Javadoc)
* #see javax.ws.rs.core.Application#getClasses()
*/
#Override
public Set<Class<?>> getClasses()
{
Set<Class<?>> classes = new HashSet<Class<?>>();
loadResourceClasses(classes);
return classes;
}
private void loadResourceClasses(Set<Class<?>> classes)
{
classes.add(StudentResource.class);
}
}
Then in your resource:
#Path("student")
class StudentResource
{
private StudentService studentService;
StudentResource(#Context ServletContext servletContext)
{
ApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
this.transactionService = applicationContext.getBean(StudentService .class);
}
}
There'r you go Spring has been configured with all dependency injections with Jersey!!!
You should try using #InjectParam

RestEasy with Spring renders no answer

I can see that the FilterDispatcher is called (by debugger), but it doesn't seem to find the service to call. I've got trouble grasping how RestEasy actually maps between resources defined in Spring and RestEasy.
Main story: Getting http://my.local.no:8087/rest/typeaheads/h only renders 404
web.xml:
...
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>restFilterDispatcher</filter-name>
<filter-class>org.jboss.resteasy.plugins.server.servlet.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>restFilterDispatcher</filter-name>
<url-pattern>/rest/*</url-pattern>
</filter-mapping>
...
resteasy resource is set up by bean:
#Configuration
#ComponentScan(basePackageClasses = TypeaheadsRestService.class)
public class SpringConfig {
}
TypeaheadsRestService.java:
#Resource
#Path("/typeaheads")
public class TypeaheadsRestService {
#GET
#Path("/{search}")
#Produces(MediaType.APPLICATION_JSON)
public List<NameUrl> get(#PathParam("search") String search) {
...
}
}
The RestEasy SpringContextLoaderListener seem to be the missing part. I created a stripped down problem from RestEasy example and used it. For my somewhat more complex application however it would not work. That is probably because it overrides the deprecated createContextLoader-method. In Spring 3 ContextLoaderListener is an instance of ContextLoader. So I reimplemented it like this:
public class MyContextLoaderListener extends ContextLoaderListener {
private SpringContextLoaderSupport springContextLoaderSupport = new SpringContextLoaderSupport();
#Override
protected void customizeContext(ServletContext servletContext, ConfigurableWebApplicationContext applicationContext) {
super.customizeContext(servletContext, applicationContext);
this.springContextLoaderSupport.customizeContext(servletContext, applicationContext);
}
}
I originally tried to do the customizeContext(...) in a bean initialisation. That worked in RestEasy 2.2.1.GA, but not in 2.3.4.FINAL.

SimpleJdbcTemplate not serializable

I use JSF and Spring. The JSF beans must be serializable by design. The JSF beans get injected with Spring beans that handle the db access. Thus these beans must be serializable as well. However simpleJdbcTemplate is not serializable so I get stack traces when restarting the servlet and sessions are lost. If I declare simpleJdbcTemplate to be transient, I don't get stack traces about "not serializable" but then simpleJdbcTemplate is sometimes NULL after a restart, which is even worse.
So what can I do so that the spring beans get injected with a "fresh" simpleJdbcTemplate when the servlet is restarted?
The classes look like this:
#Repository
public class Users implements Serializable
{
#Autowired
private SimpleJdbcTemplate simpleJdbcTemplate;
// ...
}
#ManagedBean
#SessionScoped
public class ThisBean implements Serializable
{
#ManagedProperty(value = "#{users}")
private Users users;
public void setUsers(Users users)
{
this.users = users;
}
// ...
}
Now some config files, just so that you see I didn't miss something standard.
The web.xml has this:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
<listener>
<listener-class>Listeners.SessionListener</listener-class>
</listener>
The applicationContext.xml has this:
<context:annotation-config />
<context:component-scan base-package="SpringDB"/>
<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/mysql"/>
<bean id="simpleJdbcTemplate" class="org.springframework.jdbc.core.simple.SimpleJdbcTemplate">
<constructor-arg>
<ref bean="dataSource"/>
</constructor-arg>
</bean>
faces-config.xml has this:
<application>
<variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
<application>
<message-bundle>jsf</message-bundle>
</application>
</application>
Why don't you try to pass in the DataSource reference instead of the JdbcTemplate. The common practice is to inject the data source and create the JdbcTemplate within the setter for the data source. You'll find the following example in the spring documentation:
public class JdbcCorporateEventDao implements CorporateEventDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of the methods on the CorporateEventDao follow...
}
You can also use #Autowired on the setDataSource method if you don't want to set up your beans with XML. For further details have a look at the JdbcTemplate best practices section of the excellent spring documentation.
Add scope="prototype" definition for simpleJDBCTemplate bean. Then Spring Framework will create new instance for every servlet instance. More info about bean scopes: http://static.springsource.org/spring/docs/2.5.x/reference/beans.html#beans-factory-scopes

Resources