users@jersey.java.net

Re: [Jersey] SOLVED: Jersey-Spring, _at_Context and InitializingBean

From: Patrick Dreyer <Patrick_at_Dreyer.name>
Date: Fri, 12 Feb 2010 11:31:39 +0100

Paul, thank you not only for the most welcome alternative and more
elegant solution but also for the fast and very comprehensive answer.
As you asked, the issue is logged
(https://jersey.dev.java.net/issues/show_bug.cgi?id=469).

For the archive, I decided to go with the setter method. Below how the
Bean and Jersey resource do look like now.

Regards, Patrick

Bean
====

@Component @Scope("prototype")
public final class TaskDO implements InitializingBean
{
  private static Logger logger = Logger.getLogger(TaskDO.class.getName());

                    private ResourceContext resourceContext;
  @FormParam("xml") private String xml;

  private TaskState state;

  @Context public void setResourceContext(final ResourceContext value) throws Exception {
    resourceContext = value;
    state = resourceContext.getResource(...);
  }
}

Jersey resource
===========

@Path("/tasks")
@Component @Scope("request")
public class TasksResource
{
  @POST
  @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
  @Produces(MediaType.APPLICATION_XHTML_XML)
  public Response createTaskXHtml(@Inject final TaskDO taskDO) {
      ...
      return ...
  }
}

Paul Sandoz schrieb:
> Hi Patrick,
>
> This is an issue with the Jersey/Spring integration.
>
> Jersey gets a reference to the Spring bean and then performs its own
> injection. It currently does not register a bean post process listener
> or something like that (i cannot remember the exact name) to perform
> injection at the appropriate stage in the spring bean construction
> process.
>
> Jersey does have framework support to integrate in such a manner as it
> uses that for integration with CDI and EJBs so i think it should be
> possible to support this properly with Spring. Gonna require a little
> experimentation as my Spring knowledge is rusty. Could you log an issue?
>
>
> A alternative work around may be to use setter methods:
>
> @Component @Scope("prototype")
> public final class TaskDO implements InitializingBean
> {
> private static Logger logger =
> Logger.getLogger(TaskDO.class.getName());
>
> @FormParam("xml") private String xml;
>
> private TaskState state;
>
> @Context
> public void setTask(ResourceContext resourceContext) {
> state = resourceContext.getResource(...);
> }
> }
>
> JAX-RS setter methods are called after injection onto fields is
> performed.
>
>
> If TasksResource, TaskDO and TaskState are spring-managed beans you
> may be able to use spring auto-wiring rather than use ResourceContext.
>
> If you need the TaskDO instance to be created only for the resource
> method "createTaskXHtml" rather than being created at class
> construction you can do:
>
> public Response createTaskXHtml(@com.sun.jersey.spi.inject.Inject
> TaskDO t) {
> ...
> }
>
>
> The @Inject essentially does the same thing as one can do
> programatically using ResourceContext. Also if using Jersey >= 1.1.4.1
> you can do:
>
> @Inject Injectable<TaskDO> it;
>
> public Response createTaskXHtml() {
> TaskDO t = it.get();
> }
>
> which also allows you to inject per-request or prototype scoped
> references onto singletons.
>
> Hth,
> Paul.
>
> On Feb 12, 2010, at 9:47 AM, Patrick Dreyer wrote:
>
>
>> Hi Jersey cracks
>>
>> Unfortunately, Spring is calling
>> InitializingBean.afterPropertiesSet() BEFORE Jersey had it's chance
>> to inject @Context fields, like "@Context private ResourceContext
>> resourceContext".
>> Thus, being in afterPropertiesSet(), the resourceContext field is
>> not set yet. As you'll see, as temporary workaround I'm currently
>> calling TaskDO.init() after creation through ResourceContext.
>> Is this behaviour by design or, what I hope, can you spot a
>> misunderstanding/misconfiguration on my side?
>> Below you'll find my Environment, Bean, Jersey Resource, web.xml and
>> applicationContext.xml
>>
>> Environment:
>> =========
>> * JRE 1.6.0_18-b07
>> * JDK 1.6.0_17
>> * Apache Tomcat/6.0.20
>> * Jersey 1.1.5
>> * Spring 3.0.0-RELEASE
>> * Jersey-Spring 1.1.5
>>
>> Bean implementing InitializingBean:
>> =======================
>> @Component @Scope("prototype")
>> public final class TaskDO implements InitializingBean
>> {
>> private static Logger logger =
>> Logger.getLogger(TaskDO.class.getName());
>>
>> @Context private ResourceContext resourceContext;
>> @FormParam("xml") private String xml;
>> private TaskState state;
>>
>> @Override public void afterPropertiesSet() {
>> int i = 0; // <-- ISSUE: resourceContext is not set yet; same
>> goes for xml
>> }
>>
>> public TaskDO init() throws Exception {
>> state = resourceContext.getResource(...); // <-- obviously
>> resourceContext is set now, same applies to xml
>> return this;
>> }
>> }
>>
>> Jersey resource instantiating the Bean:
>> =========================
>> @Path("/tasks")
>> @Component @Scope("request")
>> public class TasksResource
>> {
>> @Context private ResourceContext resourceContext;
>>
>> @POST
>> @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
>> @Produces(MediaType.APPLICATION_XHTML_XML)
>> public Response createTaskXHtml() throws Exception {
>> TaskDO task = resourceContext.getResource(TaskDO.class).init());
>> ...
>> return ...
>> }
>> }
>>
>> web.xml
>> ======
>> <?xml version="1.0" encoding="UTF-8"?>
>> <web-app
>> id="WebApp_ID"
>> version="2.5"
>> xmlns="http://java.sun.com/xml/ns/javaee"
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>> xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
>> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd
>> ">
>> <display-name>...</display-name>
>>
>> <context-param>
>> <param-name>contextConfigLocation</param-name>
>> <param-value>classpath:applicationContext.xml</param-value>
>> </context-param>
>>
>> <context-param>
>> <param-name>log4jConfigLocation</param-name>
>> <param-value>classpath:log4j.properties</param-value>
>> </context-param>
>>
>> <listener>
>> <listener-
>> class>org.springframework.web.util.Log4jConfigListener</listener-
>> class>
>> </listener>
>> <listener>
>> <listener-class>org.springframework.web.context.ContextLoaderListener
>> </listener-class>
>> </listener>
>> <listener> <listener-class>org.springframework.web.context.request.RequestContextListener
>> </listener-class>
>> </listener>
>> <welcome-file-list>
>> <welcome-file>index.jsp</welcome-file>
>> <welcome-file>index.html</welcome-file>
>> </welcome-file-list>
>>
>> <servlet>
>> <servlet-name>jersey</servlet-name>
>> <servlet-
>> class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</
>> servlet-class>
>> <init-param>
>> <param-
>> name>com.sun.jersey.config.property.JSPTemplatesBasePath</param-name>
>> <param-value>/WEB-INF</param-value>
>> </init-param>
>> <load-on-startup>1</load-on-startup>
>> </servlet>
>>
>> <servlet-mapping>
>> <servlet-name>jersey</servlet-name>
>> <url-pattern>/ws/*</url-pattern>
>> </servlet-mapping>
>> </web-app>
>>
>> applicationContext.xml
>> ================
>> <?xml version="1.0" encoding="UTF-8"?>
>> <beans
>> xmlns="http://www.springframework.org/schema/beans"
>> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>> xmlns:context="http://www.springframework.org/schema/context"
>> xsi:schemaLocation="
>> http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
>> http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
>> ">
>> <context:component-scan base-package="..."/>
>> </beans>
>>
>>
>> Regards
>> ---
>> Patrick Dreyer
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>
>