We have a web application with both a root application context (applicationContext.xml) and a dispatcher servlet (dispatcher-servlet.xml) defined in our web.xml like so:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
...
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
Due to the access restrictions, we obviously cannot access any of the DispatcherServlet beans from the root parent context.
But, what we'd like to be able to do is access the sibling beans. For example, in our dispatcher-servlet.xml we have:
<bean id="firstController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
...
</bean>
<bean id="secondController" class="org.springframework.web.servlet.mvc.multiaction.MultiActionController">
...
</bean>
How can we access the secondController from inside firstController, without requiring that it be passed in as a constructor-arg, or set as a property?
We're using WebApplicationContextUtils.getWebApplicationContext(...) to access siblings in the root applicationContext.xml, but we'd like to do the same thing in the child context. (From within one of the children.)
you can get an ApplicationContext object using
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("dispatcher-servlet.xml")
This is assuming dispatcher-servlet.xml is in class path. context object has to be cached.
Then use context.getBean() to access beans from any where.
Other option seems to be , use overloaded method where we can pass the context attribute name. I have not used it.
WebApplicationContextUtils.getWebApplicationContext(ServletContext sc, String attrName)
Related
<bean id="configuration" class="com.mypackage.util.Configuration" factory-method="getInstance">
<property name="path" value="${path.props.app.dev}"></property>
</bean>
Then I have the following in my class
Configuration.getInstance();
Whereas the spring application context is loaded in another class Factory like this
private Factory() {
context = new ClassPathXmlApplicationContext("META-INF/spring.xml");
}
The problem is that before Factory class is accessed the context does not load and the configuration object gives null for path whereas when Factory is accessed and after that path property is accessed it gives the correct path.
Please tell me how to do it correctly? That is how can i get my member variable path with correct data without accessing Factory class.
Assuming that you are using Spring WebMVC. There are 2 ways:
Putting you bean configurations to dispatcher config XML (mvc-dispatcher-servlet.xml)
Remain your spring.xml and specify it in web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>spring.xml</param-value>
</context-param>
In both cases, you will no longer need a class like Factory. Besides, because of that Spring creates beans in singleton scope by default, you do not need to implement a getInstance() method for your com.mypackage.util.Configuration class.
I have been putting efforts in understanding this error. I have gone through most of the questions related to this and I am not clear as most of them addressed how to solve it. I want to understand what error is and why is it coming . Please help me in understanding below :
Why does spring look into current thread for the scope "session" ? Does spring store all the request attributes and session attributes in the thread context ?
2.I recieve this error inconsistently. If it is an issue, it should come all the times.
Below is my code snippet.
-- Application context
<bean id="location" class="com.mindtree.ruc.cmn.utils.LoginLocation" scope="session">
<aop:scoped-proxy/>
</bean>
<bean id="homePageRH" class="com.rsaame.pas.home.ui.HomePageRH">
<property name="location" ref="location" />
</bean>
-- web.xml
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
-- logs:
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.rsaame.pas.dao.cmn.PASStoredProcedure]: Constructor threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.location': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:141)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:108)
at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280)
... 42 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.location': Scope 'session' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:341)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:653)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:604)
The Problem is that the session scope is only available in Spring Contexts that run in a Web Context. -- But in a normal web application you have two Spring Contexts!! One that is started by
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:META-INF/spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
and a second that is started by:
<servlet>
<servlet-name>SpringProject-DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
In the first context (loaded by the ContextLoaderListener) it does not run in a "WebContext", therefore do not have a session scope!
Easyest solution When possible: Move that sesson scoped been to the web context (webmvc-config.xml in the example above)
Maybe this helps a bit: ContextLoaderListener or not?
The answer to your first question lies in your configuration itself. The bean scope is defined as session and you have specified <aop:scoped-proxy/> as well. This means that this particular bean is to be used within a thread which mandatorily has a HTTP session associated with it. If in case no session is available you get the mentioned error.Answer to second question is that it seems you are referring this bean from at least two other beans; one which has HTTP session associated with it while the other doesn't. Hence the issue is intermittent.To get rid of it you need to analyse your bean definitions and ensure that bean in question is used / injected such that a HTTP session is available while invocation.
I'm using Spring MVC. In a Controller class, I want to use the #Value annotation to inject a value that comes from a properties file:
#Value("${upload.dir}")
private String uploadDir;
So I need to put a property-placeholder somewhere.
The web.xml is typical:
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/mvc-dispatcher-servlet.xml</param-value>
</init-param>
...
</servlet>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/business-context.xml</param-value>
</context-param>
First, I put the placeholder in business-context.xml. It doesn't work: "Could not autowire field".
Then I put it in mvc-dispatcher-servlet.xml, it works.
So I'm confused about these two contexts, are they the same one or different? Because the beans I defined in business-content.xml can be autowired, but the #Value doesn't work.
I don't want to put the placeholder in both xml files 'cause I have a long 'location' property. Also the business-context.xml will be used by some jobs, so it cannot be omitted.
Any way to make placeholder defined in business-context.xml become visible in mvc-dispatcher-servlet.xml as well?
A BeanFactoryPostProcessor which is what the property-placeholder is will only operate (and be visible) to the application context it is defined in. This is by design. So no you cannot make a property-placeholder from a parent visible to a child context (well with some nasty hacks you could).
As a work around you could do the following in your business-context.xml
<util:properties id="applicationProperties" location="path-to-your-very-long-location" />
<context:property-placeholder properties-ref="applicationProperties" />
and this in your mvc-dispatcher-servlet.xml.
<context:property-placeholder properties-ref="applicationProperties" />
Define the same <context:property-placeholder ../> in both xml context and simply reference the already loaded properties. Added advantage the properties are only loaded once.
RESTEasy 2.0.1GA
Java 1.6
Spring 3.0.3
I have tried everything I can, and cannot make head or tail of what's going on. I have a Spring MVC application, however I'd like to have some RESTEasy endpoints available outside the Spring MVC app, but in the same container, ultimately being able to wire in the same beans.
As a first step, I'm simply trying to stand-up RESTEasy inside the container, serving requests from a Spring-configured bean. I have tried the boilerplate from the instructions and have also tried manual setup, to no avail.
Bean
#Resource
#Path("/")
public class NeighborComparison {
private String foo;
#GET #Path(value="customer") #Produces("text/plain")
public String getNeighborComparison() {
return "foo";
}
}
web.xml
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/api</param-value>
</context-param>
<listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<!-- NOT configuring SpringContextLoaderListener because I declare my own, so if I do, everything
blows up, plus all it actually does is sanity check configuration -->
<listener>
<listener-class>com.example.MyCustomContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
applicationContext.xml
<bean id="resteasy.providerFactory" class="org.jboss.resteasy.spi.ResteasyProviderFactory"
factory-method="getInstance">
</bean>
<bean id="resteasy.dispatcher" class="org.jboss.resteasy.core.SynchronousDispatcher">
<constructor-arg ref="resteasy.providerFactory"/>
</bean>
<bean id="resteasy.spring.bean.processor" class="org.jboss.resteasy.plugins.spring.SpringBeanProcessor">
<description>
Add Resources and #Providers to the appropriate places
in Resteasy's infrastructure
</description>
<constructor-arg ref="resteasy.dispatcher"/>
</bean>
<bean id="neighborComparison" class="opower.api.customer.neighbor_comparison.NeighborComparison">
</bean>
According to the documentation, all I have to do is “manually register the RESTeasy BeanFactoryPostProcessor by allocating an instance of org.jboss.resteasy.plugins.spring.SpringBeanProcessor”. I believe this spring configuration does that.
Jetty starts and the app context spins up with no issues. Application works normally, however when I
> curl -H"Accept: text/plain" localhost:8080/ei/api/customer
("ei" is the application context). The log shows (this and only this):
2011-03-29 16:44:24,153 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] PathInfo: /customer
2011-03-29 16:44:24,156 DEBUG [qtp-575315405-0] [EI] [] [asy.core.SynchronousDispatcher] Failed executing GET /customer
org.jboss.resteasy.spi.NotFoundException: Could not find resource for relative : /customer of full path: http://localhost:8080/ei/api/customer
Even if I could convince RESTEasy to show me the mappings, it seems that it's just not discovering my bean.
If I map it explicitly via the resteasy.resources context param, it works, though obviously doesn't have access to auto-wired Spring beans.
Anything else I can try? I have debug log on the entire RESTEasy codebase and I don't get any messages. I've also confirmed that Spring is, in fact, creating my bean, so it's just that RESTEasy isn't finding it.
Your resource class needs to be annotated with #Path annotation for RESTeasy to pick up on it during bootstrap:
#Path("/customer")
#Resource
public class NeighborComparison {
#GET #Path("/{customerId}") #Produces("text/plain")
public String getNeighborComparison(#PathParam("customerId") long customerId) {
return "foo";
}
}
Note the #Path("/{customerId}} annotation without which your #PathParam parameter would not have been mapped correctly, resulting in a pretty detailed exception (and an accompanying 500 response on the client side). Assuming the service is picked up by RESTeasy of course.
In addition if you don't use RESTeasy's SpringContextLoader, you have to make sure your SpringBeanProcessor instance is registered with the ApplicationContext. RESTeasy delegates to it by registering an ApplicationListener in SpringContextLoader:
ApplicationListener listener = new ApplicationListener() {
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent) {
ContextRefreshedEvent cre = (ContextRefreshedEvent) event;
ConfigurableListableBeanFactory autowireCapableBeanFactory = (ConfigurableListableBeanFactory) cre
.getApplicationContext().getAutowireCapableBeanFactory();
new SpringBeanProcessor(dispatcher, registry, providerFactory)
.postProcessBeanFactory(autowireCapableBeanFactory);
}
}
};
configurableWebApplicationContext.addApplicationListener(listener);
If using a custom context loader and not the RESTEasy-provided one, this code has to appear somewhere in your context loader so that everything gets wired up. A bit convoluted, yeah. It is SpringBeanProcessor that goes through all Spring beans and registers with RESTeasy those that have a #Path annotation somewhere in their hierarchy (type and their corresponding interfaces).
I am separating my spring bean configuration files as follows:
myapp-service.xml
myapp-servlet.xml
However I am getting the error;
Error creating bean with name 'beanName' defined in ServletContext resource [/WEB-INF/myapp-servlet.xml]: Cannot resolve reference to bean 'beanService' while setting bean property 'beanService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'beanService' is defined
All I need to do (I think) is figure out how to tell Spring to read the myapp-service.xml file where the path to beanService is defined.
Which file/location is that done in?
Thanks
It's defined in your web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
Alternatively in myapp-servlet.xml you could put:
<import resource="myapp-service.xml"/>
if you like to include more applicationContext files and are indeed developing a web application:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-1.xml,
/WEB-INF/applicationContext-2.xml
</param-value>
</context-param>
also wildcarding works, applicationContext* will have the same effect here.
if you are bootstrapping spring context by hand e.g from code:
ApplicationContext context =
new ClassPathXmlApplicationContext(new String[] { "applicationContext-1.xml", "applicationContext-2.xml" });