JerseyConfig and #Profile to hide a REST endpoint - spring

I'm trying to hide a REST endpoint based on runtime configuration in Spring and Jersey. The most straightforward way is to throw the NotFoundException from the controller itself but maybe there's more kosher. The controller is registered in the constructor of the config class which extends org.glassfish.jersey.server.ResourceConfig.
I thought of using the #Profile annotation on the controller but I can still access the endpoint. When I hit that endpoint, I get the following error:
o.g.j.s.s.SpringComponentProvider - None or multiple beans found in Spring context
but then Jersey manages to access that controller, which I confirmed by attaching a debugger to the Spring process. So Jersey does not honor the #Profile setting.
On a separate note, I also have Swagger plugged into Jersey and when accessing the definition endpoint (.../swagger.json) I can see the endpoint provided by the #Profile-disabled controller.
Is there anything better I can do here is is throwing the NotFoundException the best option?

Note: Sorry, I thought I saw that you were using Spring Boot. The following answer is only relevant for Spring Boot.
#Profile is only good for Spring bean registration, but you are still registering the service with Jersey as a resource. What you can do is use a ResourceConfigCustomizer and add the #Profile to the customizer. This way it will only register the resource with Jersey ResourceConfig if the correct profile is active.
#Component
#Profile("..")
public class MyResourceConfigCustomizer implements ResourceConfigCustomizer {
#Override
public void customize(ResourceConfig config) {
config.register(MyResource.class);
}
}

Related

Configuring spring-oauth2-client for non boot spring framework

In spring boot, application.yml takes in the Spring oauth2 client config. How do I configure it for the non-boot application. By configuration I mean giving client ID, secret, scopes and redirect URI.
You could find an example here:
https://www.baeldung.com/spring-security-5-oauth2-login#non-boot
You need to:
Build your ClientRegistration.
A ClientRegistrationRepository.
Register your repository on WebSecurityConfigurerAdapter.
If you don't use SpringBoot : there is no application.yml and even if you can add the support of yml files. It won't handle your oauth2 client config.
Anyway you can use Spring security to implement your custom Authorization Service, a User service and implement a Token Store of your choice (JBDCTokenStore or JWTTokenStore for example). But It's a very wide question depending on your business logic.
You can find some well documented samples on :
https://github.com/spring-projects/spring-security-oauth/tree/master/spring-security-oauth2
Of course you can handle both XML and javaConfig even mixed Spring confugurations.
Create a #Configuration class with a #ComponentScan on the packages containing components or bean definitions.
#Configuration
#ComponentScan({ "com.firm.product.config.xml","com.firm.product.config.java" })
public class SpringConfig {
}
You can also set properties with #PropertySource() ans #Value annotations. It's very well documented.

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 jersey - prevent startup instantiation of controller

I am using spring boot with web and jersey (spring-boot-jersey-starter). I have a Jersey endpoint that needs to inject a request scope bean. However, at startup of the application I am getting a no bean found error.
#Component
#Path("blah")
#RequestScoped
public class JerseyController{
#Inject
private MyEntity entity;
}
#Component
public class JerseyConfiguration extends ResourceConfig{
public JeyseyConfiguration(){
register(JeyseyController.class);
registere(MyEntityProvider.class);
}
}
Is there a way, in a spring-boot web app, to prevent Spring from attempting to instantiate and inject my JerseyController until an HTTP request is received so that the injected dependency can be provided by my Jersey provider?
#Component is not required on Jersey resources. Having it will cause Spring to instantiate it (with default Singleton scope). I don't think Spring doesn't respect the #RequestScoped. This is a Jersey annotation. If you want to use the #Component, I think the Spring #Scope("request") might do the trick though.
You can also remove the #RequestScoped. This is the default scope for Jersey resources.
The only time I have ever found a need to use #Component on Jersey resources, is if I need to use the Spring #Value (maybe AOP also, but I don't do much AOP). Other than that, the Jersey-Spring integration already supports the most common used feature of Spring which is DI. And if you really want to make the Jersey resource a singleton, Jersey supports the #Singleton annotation.

Why do we need #Component spring annotation for Jersey resource in spring-boot-starter-jersey project?

This question is regarding the sample:
https://github.com/spring-projects/spring-boot/blob/master/spring-boot-samples/spring-boot-sample-jersey/src/main/java/sample/jersey/Endpoint.java
Why do we need "#Component" annotation for Jersey resource when using spring-boot -starter-jersey project?
If I remove it, the Jersey servlet can still serve resources.
So what is the need for "#Component"?
You don't need it. Jersey uses HK2 as it's internal DI framework, and HK2 has a Spring bridge. This is what's used internally to bridge Spring components into the HK2 IoC container, so that they can be injected into Jersey components. And Jersey implements an AutowiredInjectionResolver1 that allows for injection of Spring components using #Autowired. You don't even need #Autowired though. All the Spring components can be injected with the normal #Inject.
The only drawback I've ran into, not making the Jersey components a Spring #Component is that it doesn't support #Value when you want to inject property values.
The one thing I don't like is that when you declare something a Spring #Component, it automatically makes it a singleton. But Jersey resources are by default request scoped. You can add a Spring #Scope("request"), and it should change the resource to a request scoped resource. Jersey has declared the Spring RequestScope, so we can use it. How exactly it ties in to Jersey's request scope, I am not a hundred percent sure. I ran into a problem a while back. I can't remember what it was, but that has kept me from ever using the Spring request scope again.
Assuming I want to keep all my resources request scoped, I would take sticking to the normal Jersey request scope, and not being able to inject #Values, over having to use Spring's request scope. Maybe I'm imagining things, and there was no issue using it, but personally I'll just stick to what I know works :-)
UPDATE
Another thing that does't work if you don't make the resource a Spring #Component is Spring's AOP. That's fine with me though as HK2 also has AOP.
1 - An InjectionResolver allows you to use custom annotations to create injection targets.
When you remove #Component jersey takes control of the scope of the instance. With #Component a singleton instance is created, removing it you can use the following jersey annotations:
• Request scope (Default):
By using the #RequestScope annotation or none, we can have a life-cycle till
the request lasts. This is the default scope of the root-resource classes. For
each new request, a new root-resource instance is being created and served
accordingly for the first time. However, when the same root-resource method
is being called, then the old instance will be used to serve the request.
• Per-lookup scope:
The #PerLookup annotation creates root-resource instances for every request.
• Singleton:
The #Singleton annotation allows us to create only a single instance
throughout the application.
Try different behaviors using a counter inside your class...
public class MyWebResource {
private int counter;
#GET
#Path("/counter")
#Produces(MediaType.APPLICATION_JSON)
public Response getCounter() {
counter++;
return Response.status(Status.OK).entity(counter).build();
}
}

Service activator method mapping using #Header annotation in Spring Integration

I'm developing web app using Spring Integration to route my messages, but I have some problems with passing my header value. My message goes through router and service activator.
The header value is available in a routing method of my router so it seems to be ok. Let's assume that it is not a problem (I checked this by disabling my service activator).
When it comes to my service activator method the following error is thrown:
"Failed to find any valid Message-handling methods named process on target class MyService."
my-spring-integration.xml
<channel id="route" />
<service-activator method="process" input-channel="route" ref="myService" output-channel="myOutputChannel" />
MyRouter.java
#Component
public class MyRouter {
public String router(String message, #Header("isValid") boolean isValid) {
// isValid is "true"
return "route";
}
}
MyService.java
#MessageEndpoint
#Transactional
public class MyService {
public void process(String message, #Header("isValid") boolean isValid) {
...
}
}
Why is that? Are headers values erased after routing? Or my configuration is wrong? I tried to add #ServiceActivator annotation to my process method, but it didn't help.
Any help will be greatly appreciated.
I would guess that this is caused by having an #Transactional annotation on a Service which doesn't implement any interfaces.
Spring will implement the transactional logic using JDK dynamic proxies, these rely on proxied classes implementing suitable interfaces. There is a Spring blog about this here.
To fix this I would suggest that you create an interface called MyService with a single method called process. Then have you service implement this interface.
I'm working with legacy code and it was probably caused by old spring integration version. My application support '#Headers', but it doesn't support '#Header' annotation. #Header annotation was accepted in my router which is interface and not in my service activator which does not implement any interface. I suspect it was caused by old version of spring integration or cglib.

Resources