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.
Related
Okay I've done a lot of googling and I can't seem to find a clear answer. Let's keep it as simple as possible. I have a web.xml file
<listener>
<listener-class>A</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:springcontexts/*.xml</param-value>
</context-param>
<context-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:wsspringcontexts/*.xml</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring_mvc_contexts/*.xml</param-value>
</init-param>
</servlet>
I think I know how to migrate this to Spring Boot ...
#SpringBootApplication(exclude = DispatcherServletAutoConfiguration.class)
#ImportResource("classpath*:springcontexts/*.xml")
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(Application.class, args);
}
}
Somewhere in a sub-package...
#Configuration
#EnableWebMvc
public class SpringMVCConfiguration
{
#Bean
public ServletRegistrationBean mvc()
{
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.setConfigLocation("classpath*:spring_mvc_contexts/*.xml");
// the dispatcher servlet should automatically add the root context
// as a parent to the dispatcher servlet's applicationContext
DispatcherServlet dispatcherServlet = new DispatcherServlet(applicationContext);
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(dispatcherServlet, "/spring/*");
servletRegistrationBean.setName("DispatcherServlet");
return servletRegistrationBean;
}
}
...and we do the above again for the other Servlet
My first problem is how to add the listener "A" to Spring Boot and ensure it runs before the root application is refreshed? Some beans that get configured require some static fields to be setup (legacy code), and this setup is done in listener "A". This works fine when deployed as a standard war using the above web.xml
In addition does the above Spring Boot setup look correct?
Why not put your legacy initialisation in a postConstruct method on a bean ?
Failing that you can add a listener that implements
ApplicationListener<ContextRefreshedEvent>
and overrides
public void onApplicationEvent(final ContextRefreshedEvent event)
Does your Spring Boot setup look OK ? Difficult to tell, though I'd let Spring Boot autoconfigure things like the dispatcher servlet for you and get rid of any XML config if at all possible.
I'm trying to integrate Vaadin with Spring. In my main Vaadin application class I have:
public class MyVaadinApplication extends UI {
#Inject
private PrivatePersonBo privatePersonBo;
#Override
public void init(VaadinRequest request) {
Layout layout = new FormLayout();
layout.setCaption("New Private Person");
setContent(layout);
ApplicationContext appContext = new ClassPathXmlApplicationContext("resources/spring/Context.xml");
appContext.getBean(MyVaadinApplication.class);
PrivatePersonBo privatePersonBo = (PrivatePersonBo) appContext.getBean("privatePersonBo");
PrivatePerson existingEmployee = privatePersonBo.findByName("TestUserName");
}
}
If I get bean from context directly I recieve bean, however If I comment line which recieves bean from appContext then #Inject annotation doesn't work and I get NullPointerException. My deployment descriptor is below:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:resources/spring/Context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>VaadinApplicationServlet</servlet-name>
<servlet-class>com.vaadin.server.VaadinServlet</servlet-class>
<init-param>
<param-name>UI</param-name>
<param-value>pl.adamsalata.MyVaadinApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>VaadinApplicationServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Any suggestions please?
You can integrate Vaadin 7 with Spring in two simple steps:
1) Create a UIProvider that lookup UIs in spring context:
public class SpringUIProvider extends DefaultUIProvider {
#Override
public UI createInstance(UICreateEvent event) {
ApplicationContext ctx = WebApplicationContextUtils
.getWebApplicationContext(VaadinServlet.getCurrent().getServletContext());
return ctx.getBean(event.getUIClass());
}
}
2) Declare the UIProvider in web.xml:
<context-param>
<param-name>UIProvider</param-name>
<param-value>org.example.SpringUIProvider</param-value>
</context-param>
And remember to use prototype scope for UI classes.
If you want to integrate Vaadin with Spring then use #Configurable feature. Then all instantiated objects (even if you create them using new MyObject() code) will be integrated with Spring context. You can find more details about such setup in Spring documentation: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-using-aspectj
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.
I get this error with a gwt (using requestfactory) and spring
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [org.calibra.server.service.AccountService] is defined: expected single bean but found 0:
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:271)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1101)
at org.calibra.server.SpringServiceLocator.getInstance(SpringServiceLocator.java:24)
at com.google.web.bindery.requestfactory.server.LocatorServiceLayer.createServiceInstance(LocatorServiceLayer.java:56)
My service locator
public class SpringServiceLocator implements ServiceLocator {
#Override
public Object getInstance(Class<?> clazz) {
ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(
RequestFactoryServlet.getThreadLocalServletContext());
return context.getBean(clazz);
}
}
My spring service
#Service
public class AccountServiceImpl implements AccountService{
#Override
public void addNewAccount(Account account) {
...
}
#Override
public List<Account> loadAllAccounts() {
...
}
}
Gwt requestContext, reference my spring service
#Service(value=AccountService.class, locator=SpringServiceLocator.class)
public interface AccountRequest extends RequestContext {
Request<Void> addNewAccount(AccountProxy account);
Request<List<AccountProxy>> loadAllAccounts();
}
my web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>gwtRequest</servlet-name>
<servlet-class>com.google.web.bindery.requestfactory.server.RequestFactoryServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>gwtRequest</servlet-name>
<url-pattern>/gwtRequest</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>welcomeGWT.html</welcome-file>
</welcome-file-list>
I don't understand how i can have 0 AccountService beans ?
i tried to add in the dispatcher-servlet
<bean id="accountService" class="org.calibra.server.service.AccountServiceImpl"/>
I got the same result
Any idea?
edit: if somebody have a full complete example, that could be useful.
I think using the ContextLoaderListener alone is not enough as you don't seem to have the DispatcherServlet in use (have you?).
The following lines work for me:
<filter>
<filter-name>springRequestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>springRequestContextFilter</filter-name>
<url-pattern>/gwtRequest</url-pattern>
</filter-mapping>
I've seen this question in a couple of other places. You should try explicity defining the AccountServiceImpl as a bean in your applicationContext.xml (not the dispatch-servlet.xml) first and see if you still get the error, if you don't then you know it's that you're missing the component-scan in your application context xml which is what I think is the case.
hope this helps
I have a spring.xml file where in all the bean definitions are listed, where i have listed all the dependencies using beans, specified messageSource, dataSource etc. Also i have a class ApplicationContext class where iam using the context to get all the beans.
The code is ::
package models;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class ApplicationContextClass {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
AbstractApplicationContext context = new ClassPathXmlApplicationContext("Spring.xml");
context.registerShutdownHook();
ATTModel attmodel = (ATTModel) context.getBean("att");
//ProjectModel project = (ProjectModel)context.getBean("project");
//project.call1();
attmodel.call();
System.out.println(context.getMessage("insertiondone",null, "Default greeting",null));
}
}
and i have Dao class where an applicationContext is used to access JDBCtemplate related bean. I have to develop a web application now using spring MVC and i need to use this applicationContext. How can i use these applicationContext classes in SpringMVC. I knw i need to use applicationcontextlisteners but where to write them ? Thanks..
You have two ways. In web.xml define this.
<servlet>
<servlet-name>yourapp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
And to your WEB-INF folder add yourapp-servlet.xml with your beans and mvc configuration.
Other way is. In web.xml define this.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
And to your WEB-INF add applicationContext.xml with your beans.
You can also combine these approaches.