I'm using Spring boot + Jersey + Spring security, I want to have public and private endpoints, I want an schema as follow:
/rest/public/pings
/rest/private/accounts
I have my configuration as follow:
Jersey configuration:
@Configuration
@ApplicationPath("/rest")
public class RestConfig extends ResourceConfig {
public RestConfig() {
register(SampleResource.class);
}
}
Spring security configuration:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
........
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/rest/public/**").permitAll();
http.antMatcher("/rest/**").authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic();
http.csrf().disable();
}
}
The question is how can I register two application paths inside of my /rest context, one for /public and the other one for /private ?
NOTE: I tried to create another ResourceConfig as follow:
@Configuration
@ApplicationPath("/rest/public")
public class RestPublicConfig extends ResourceConfig{
public RestPublicConfig() {
register(PingResource.class);
}
}
But I'm getting the next error:
No qualifying bean of type [org.glassfish.jersey.server.ResourceConfig] is defined: expected single matching bean but found 2: restConfig,restPublicConfig
Thanks for your help :)
Jersey is an alternative to Spring RESTFul applications created with @RestController . Spring is a popular Java application framework for creating enterprise applications. Spring Boot is the next step in evolution of Spring framework.
Jersey is the JAX-RS API example implementation provided by Sun, while Spring REST is of course Spring's implementation of the same API/JSRs. The major difference is that Spring REST easily integrates into other Spring APIs (if you wish) such as Spring Data Rest.
In a Spring Boot application, we expose a REST API endpoint by using the @RequestMapping annotation in the controller class. For getting these endpoints, there are three options: an event listener, Spring Boot Actuator, or the Swagger library.
A Jersey Configuration is a class that extends from ResourceConfig from the jersey library. A Jersey Configuration class will typically define an @ApplicationPath annotation specifying path to connect via REST.
In a servlet container, the Jersey runtime, runs as either a servlet or as a servlet filter. How spring boot configures servlets and filters is through ServletRegistrationBean
s and FilterRegistrationBeans
, respectively. To get an idea of how that configuration works behind scenes, you can look at the source code for the JerseyAutoConfiguration
In the JerseyAutoConfiguration
, you can see that a ResourceConfig
is injected, and that is the ResourceConfig
used to create the Jersey servlet or Jersey filter (depending on your choice of configuration). So the reason for the error is that you can't have ambiguous beans, which you have two ResourceConfig
beans. So Spring doesn't know which one to inject.
What you can do though, is use two different servlets for each ResourceConfig
. The problem is that Spring Boot only hooks you up with one servlet for Jersey, so you need to configure the other one yourself. There are two options:
Use the Spring Boot auto-configuration for one of the Jersey applications, and add another ServletRegistrationBean
for your other one. The one thing to note is that the ResourceConfig
for your created ServletRegistrationBean
should not be a Spring component (i.e. no @Component
or @Configuration
), or else you will still face the same error.
public class PublicConfig extends ResourceConfig {
public PublicConfig() {
register(PingResource.class);
}
}
...
// in your Spring Boot configuration class
@Bean
public ServletRegistrationBean publicJersey() {
ServletRegistrationBean publicJersey
= new ServletRegistrationBean(new ServletContainer(new PublicConfig()));
publicJersey.addUrlMappings("/rest/public/*");
publicJersey.setName("PublicJersey");
publicJersey.setLoadOnStartup(0);
return publicJersey;
}
Don't use the Spring Boot configuration at all. Just create two ServletRegistrationBean
s. In this case, none of your ResourceConfig
classes should be Spring beans.
@Bean
public ServletRegistrationBean publicJersey() {
ServletRegistrationBean publicJersey
= new ServletRegistrationBean(new ServletContainer(new PublicConfig()));
publicJersey.addUrlMappings("/rest/public/*");
publicJersey.setName("PublicJersey");
publicJersey.setLoadOnStartup(0);
return publicJersey;
}
@Bean
public ServletRegistrationBean privateJersey() {
ServletRegistrationBean privateJersey
= new ServletRegistrationBean(new ServletContainer(new PrivateConfig()));
privateJersey.addUrlMappings("/rest/private/*");
privateJersey.setName("PrivateJersey");
privateJersey.setLoadOnStartup(1);
return privateJersey;
}
Personally, I prefer the second option, as it is easier to reason about the configurations when they are all in one place.
Another thing to note is that the two Jersey applications will be completely independent, meaning you will need to register providers (like filters) for both applications
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With