JAX-RS - Spring Boot vs without Spring Boot - spring-boot

I want to use Spring boot with JAX-RS (Jersey Implementation). If we were not using Spring Boot, we could use the following code to register all the Rest service classes
#ApplicationPath("/myrest")
public class MyApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
s.add(HelloWorld.class);
return s;
}
}
This works fine in a Servlet 3.0 supported container.
But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?

But when we use Spring Boot with JAX-RS(Jersey) why do we have to extend from org.glassfish.jersey.server.ResourceConfig Why extending from javax.ws.rs.core.Application doesn't work?
Because Spring Boot uses the ResourceConfig type as the as a service that it injects into its auto configurer, namely the JerseyAutoConfiguration. If you look at the source code, you will see
#Autowired
private ResourceConfig config;
From there, Sprig Boot configures the app with that instance. If a ResourceConfig bean is not available in the Spring context, then not auto-configuration happens.

Related

What Is the Correct Way To Use AbstractReactiveWebInitializer

I've got a Spring WebFlux application running successfully as a standalone spring boot application.
I am attempting to run the same application in a Tomcat container, and following the documentation, I've created a class that extends AbstractReactiveWebInitializer. The class requires that I implement a method getConfigClasses that would return classes normally annotated with #Configuration. If the working spring boot app started with a class called ApplicationInitializer, then the resulting implementations would look like this:
#SpringBootApplication(scanBasePackages = "my.pkg")
#EnableDiscoveryClient
#EnableCaching
public class ApplicationInitializer {
public static void main(String... args) {
SpringApplication.run(ApplicationInitializer.class, args);
}
}
and
public class ServletInitializer extends AbstractReactiveWebInitializer {
#Override
protected Class<?>[] getConfigClasses() {
return new Class[] {ApplicationInitializer.class};
}
}
When deployed, the only thing that starts is ApplicationInitializer, none of the autoconfigured Spring Boot classes (Cloud Config, DataSource, etc) ever kick off.
The documenation states this is the class I need to implement, I just expected the remainder of the spring environment to "just work".
How should I be using this class to deploy a Reactive WebFlux Spring Boot application to a Tomcat container ?
Edit:
After some additional research, I've narrowed it down to likely just Cloud Config. During bean post processing on startup, the ConfigurationPropertiesBindingPostProcessor should be enriched with additional property sources (from cloud config), but it appears to be the default Spring properties instead, with no additional sources.
The misisng properties is causing downstream beans to fail.
Spring Boot does not support WAR packaging for Spring WebFlux applications.
The documentation you're referring to is the Spring Framework doc; Spring Framework does support that use case, but without Spring Boot.
you can extend SpringBootServletInitializer, add add reactive servlet on onStartup method

Spring Boot Actuator requires #EnableWebMvc but that turns off other features

I got confused trying to integrate Actuator to a project using Spring Boot 1.5.11's static resource serving feature:
Spring Boot Actuator does not work without #EnableWebMvc, HTTP 406 is returned because the right Http media converter is not installed.
But if I add #EnableWebMvc, it turns off serving resources from the static folder and other Spring Boot features.
Is there a way to initialize Actuator without losing Boot features?
Found a bug in Spring Boot 2.0, it seems it was there in Boot 1.5 as well. Workaround: setting favorPathExtension to false turns off buggy code in ServletPathExtensionContentNegotiationStrategy and Actuator endpoints start working.
#Configuration
public class WebConfig implements WebMvcConfigurer {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false);
}
}

How to register resource with javax.ws.rs.core.Applicaiton in spring-boot-starter-jersey powered REST application

In my spring boot application (powered by spring-boot-starter-jersey):
I can easily make a resource config (jersey way but not jaxrs way) like this:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends ResourceConfig {
And I just want to try with javax.ws.rs.core.Applicaiton:
#Configuration
#ApplicationPath("/sample")
public class SampleResourceConfig extends javax.ws.rs.core.Applicaiton{
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(SampleResource.class);
return classes;
}
But no lucky, it does not work.
Did I miss something?
Thanks
Leon
It won't work as the Spring Boot auto-configuration is made specifically to look for a bean of type ResourceConfig, not Application. If you want to use Application, you can't use the auto-configuration. You'll need to just create the JAX-RS servlet yourself and register it with a Spring Boot ServletRegistratiobBean, similar to what you'll see in the source code I linked to.

Integrating Spring XML beans from external jar into a CDI application

I have a new CDI Java EE application running on WebSphere. Now I want to use an existing module (.jar) in my CDI project, however the existing module uses Spring with Spring annotations and an Spring XML configuration file with additional bean definitions in it. Normally I would just import the Spring XML in my project, but in the CDI application this will not work.
I tried to load the Spring XML using JBoss Seam, like so:
#Produces
#SpringContext
#Configuration(locations = "classpath*:external-spring--context.xml")
ApplicationContext context;
But the context is null? I cannot realy find good examples on how to do this, help is much appreciated :)
I solved it by adding an CDI producer that will create the Spring context using the spring XML file:
public class SpringBeansFactory {
#Inject
ApplicationContext context;
#Produces
public BusinesService getBusinessService() {
return context.getBean(BusinesService.class);
}
}
class SpringContextFactory {
#Produces
public ApplicationContext getApplicationContext() {
return new ClassPathXmlApplicationContext("classpath:spring-context.xml");
}
}

How to use Jersey 2 with Spring IoC container

What is the best way to enable injection of spring beans into Jersey 2? Jersey seems to not support this natively.
What is needed to wire the 2 frameworks together? In pom.xml and web.xml?
Jersey 2.3 has now spring support:
https://jersey.github.io/documentation/latest/user-guide.html#spring
As stated in the documentation
The Spring extension module configuration is based on annotations
So you have to tell spring to scan your classpath, for example:
<context:component-scan base-package="my.package.to.resources">
and annotate your resource class with a spring annotation (I advise to use #Component, and then specify the jersey resource scopes #Singleton/#PerLookup/#RequestScoped )
#Component
#Singleton
#Path("example")
public class Example {
//Spring beans can't be injected directly into JAX-RS classes by using Spring XML configuration
#Autowired
private MyOtherBean myOtherBean;
#GET #Path("hello")
public String hello() {
return myOtherBean.hello();
}
}
As of June 2013, Jersey 2.0 has no official Spring support. There are two options:
Use third party code from here https://github.com/marko-asplund/jersey/tree/master/ext/jersey-spring
Wait until HK2 spring bridge becomes stable and documented https://java.net/jira/browse/HK2-40
See also:
http://jersey.576304.n2.nabble.com/Spring-framework-support-for-Jersey-2-td7580673.html
EDIT: Jersey 2.3 has spring support now, see the answer by Fabio below
You should be able to annotate jersey components and then use annotations to inject the beans.
#Service //(or #Component)
public class MyJerseyService {
#Autowired
private MyObj mySpringBean
}

Resources