Spring-boot integration with RESTEasy

I am trying to prototype a Spring boot application. I come from a Guice JAX-RS application, so I prefer the standard JAX-RS annotations to Spring MVC. I received Jetty and served:

@Configuration @Import({ResteasyBootstrap.class, SpringBeanProcessorServletAware.class, HttpServletDispatcher.class}) public class EmbeddedJetty { @Bean @Singleton public EmbeddedServletContainerFactory servletContainer() { JettyEmbeddedServletContainerFactory factory = new JettyEmbeddedServletContainerFactory(); factory.setPort(9000); factory.setSessionTimeout(10, TimeUnit.MINUTES); return factory; } } 

However, I just can't figure out how to properly connect RESTEasy. With the above SpringBeanProcessorServletAware it is freed, it seems that ServletContext not being introduced through ServletContextAware before it is used:

 java.lang.NullPointerException: null at org.jboss.resteasy.plugins.spring.SpringBeanProcessorServletAware.getRegistry(SpringBeanProcessorServletAware.java:30) at org.jboss.resteasy.plugins.spring.SpringBeanProcessor.postProcessBeanFactory(SpringBeanProcessor.java:247) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:284) at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:174) at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:680) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:522) at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:766) 

I also tried using SpringContextLoaderListener , but it seems to conflict with the spring-boot class AnnotationConfigEmbeddedWebApplicationContext .

I am using spring-boot 1.3.3 and spring-frame 4.3.0.rc1

+2
source share
3 answers

Another answer will not contain your resources like spring beans, this autoconfiguration will integrate them correctly:

Configuration class:

 @Configuration @ConditionalOnWebApplication public class RestEasyAutoConfigurer { private Environment environment; @Bean(name = "resteasyDispatcher") public ServletRegistrationBean resteasyServletRegistration() { ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HttpServletDispatcher(), getPrefix() + "/*"); registrationBean.setInitParameters(ImmutableMap.of("resteasy.servlet.mapping.prefix", "/rs/")); // set prefix here registrationBean.setLoadOnStartup(1); return registrationBean; } @Bean(destroyMethod = "cleanup") public static RestEasySpringInitializer restEasySpringInitializer() { return new RestEasySpringInitializer(); } @Bean // use Spring Boot configured Jackson public CustomResteasyJackson2Provider jackson2Provider(ObjectMapper mapper) { return new CustomResteasyJackson2Provider(mapper); } public static class RestEasySpringInitializer implements ServletContextInitializer, ApplicationContextAware, BeanFactoryPostProcessor { private ResteasyDeployment deployment; private ConfigurableApplicationContext applicationContext; private ConfigurableListableBeanFactory beanFactory; public void cleanup() { deployment.stop(); } @Override public void onStartup(ServletContext servletContext) throws ServletException { ListenerBootstrap config = new ListenerBootstrap(servletContext); deployment = config.createDeployment(); deployment.start(); servletContext.setAttribute(ResteasyProviderFactory.class.getName(), deployment.getProviderFactory()); servletContext.setAttribute(Dispatcher.class.getName(), deployment.getDispatcher()); servletContext.setAttribute(Registry.class.getName(), deployment.getRegistry()); SpringBeanProcessor processor = new SpringBeanProcessor(deployment.getDispatcher(), deployment.getRegistry(), deployment.getProviderFactory()); processor.postProcessBeanFactory(beanFactory); applicationContext.addApplicationListener(processor); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = (ConfigurableApplicationContext) applicationContext; } } } 

And Jackson Supplier:

 @Provider @Consumes({"application/*+json", "text/json"}) @Produces({"application/*+json", "text/json"}) public class CustomResteasyJackson2Provider extends ResteasyJackson2Provider { private ObjectMapper mapper; public CustomResteasyJackson2Provider(ObjectMapper mapper) { this.mapper = mapper; } @Override public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) { return Optional.ofNullable(_mapperConfig.getConfiguredMapper()).orElse(mapper); } } 

NOTE. This is the working configuration for spring Boot 1.3.3 / RESTEasy 3.0.16

+6
source

You can use the RESTEasy Spring Boot startter. Here's how you do it:

Adding a POM Dependency

Add the Maven dependency below to your spring boot application pOM file.

 <dependency> <groupId>com.paypal.springboot</groupId> <artifactId>resteasy-spring-boot-starter</artifactId> <version>2.1.1-RELEASE</version> <scope>runtime</scope> </dependency> 

Register JAX-RS Application Classes

Just define your JAX-RS application class (application subclass) as Spring bean and it will be automatically registered. See the example below. See the JAX-RS Application Registration Methods section in How to Use RESTEasy Spring Boot Starter for more information.

 package com.test; import org.springframework.stereotype.Component; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; @Component @ApplicationPath("/sample-app/") public class JaxrsApplication extends Application { } 

JAX-RS Resource and Vendor Registration

Just define them as Spring beans and they will be automatically registered. Note that JAX-RS resources can be single-point or request scope, while JAX-RS providers must be single.

More information on the GitHub project page .

+2
source

Here is a complete working example.

  • First, an exemplary JAX-RS endpoint:

     @Path("/api") public class SampleResource { @GET @Path("/sample") @Produces(MediaType.APPLICATION_JSON) public String getSample() { return "Some JSON"; } } 
  • Next up is the JAX-RS configuration class, which loads all endpoints.

     import javax.ws.rs.core.Application; public class RestEasyConfig extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(SampleRest.class); return classes; } } 
  • Finally, in your Spring configuration, initialize the RESTEast filter and report its existence.

     import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.jboss.resteasy.plugins.server.servlet.FilterDispatcher; ... @Bean public FilterRegistrationBean filterRegistrationBean() { Map<String, String> initParams = new HashMap<>(); initParams.put("javax.ws.rs.Application", RestEasyConfig.class.getCanonicalName()); FilterRegistrationBean registrationBean = new FilterRegistrationBean(); registrationBean.setFilter(new FilterDispatcher()); registrationBean.setInitParameters(initParams); return registrationBean; } 

    The endpoint must be up and running. If you are missing the FilterDispatcher class in your class path, add the resteasy-jaxrs library to your build descriptor.

+1
source

All Articles