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
>
>