Forcing Spring to call subclass for one method - spring

New to spring magic, hoping spring magic can solve my dilemma.
My groovy/spring app uses a jar to handle logging in. I want to override a method in the jar to do some custom processing during the log in process (post login).
The class in the jar looks like this:
#Component
class Processor extends GenericProcessor {
#Override
ProcessedRequest handle(Request request) {
// do things
return processRequest(request)
}
//Do nothing method method I want to override
ProcessedRequest processRequest(request) {
return request
}
}
In my application, I have subclass that extends the jar class:
class MyProcessor extends Processor {
#Override
ProcessedRequest processRequest(request) {
//do custom processing
return request
}
}
I tried making MyProcessor an #Component, but the Processor class just calls its own processRequest method instead of the processRequest method in myProcessor.
Is there something I can do with Spring to say "Whenever myProcessor exists, use it instead of Processor" through some combination of #Component/#Bean/#Qualifier?
Other notes:
Processor in the jar is called within the jar, so it isn't easy to replace the call location with myProcessor
I do have access to change the jar source code, though I would rather not, as its a shared jar.

as a suggestion, try to put #Primary under your class MyProcessor. use #Primary to give higher preference to a bean when there are multiple beans of the same type
#Component
#Primary
class myProcessor extends Processor {
...
}

Related

Spring Boot: scanning components into an injectable list or set

Spring Boot here. I have dozens and dozens of classes that are all subclass/implementations of the same interface:
public interface AnimalService {
void eat();
// etc.
}
#Component
public class DogService implements AnimalService {
#Override
public void eat() { return ... }
// etc.
}
// many many many of these
I have a #Service-annotated class (AnimalService) that needs to be injected with each one of these subclasses:
#Service
public class AnimalProcessingService {
#Autowired
private List<AnimalService> allAnimalServices; // DogService, SharkService, etc.
// the rest of the class definition is omitted intentionally
}
Now I could do this injection the hard way:
#Configuration
public class AnimalConfig {
private DogService dogService;
private SharkService sharkService;
// ...etc.
#Bean
public List<AnimalService> allAnimalServices() {
return Arrays.asList(dogService, sharkService /*, ...etc. */);
}
}
But there's gotta be an easier way to do this, right?
How can inject this List<AnimalService> without having to manually create the list? Does this method allow you to filter out certain candidates (like if I just want a subset of the animal services)? Ideally something annotation-based (even if I have to define my own annotations) that works with Spring autowiring/DI/component scanning. Thanks for any and all help here!
Essentially you're looking for #ComponentScan, which is a Spring (not Boot) annotation. It allows you to define a list of packages for Spring to scan for #Components (or "sub-annotations" such as #Service), to automatically instantiate beans of those classes and add them to the Spring context. So you can consider it a more automated way of the more manual #Bean method declaration.
Since you're using Spring Boot, however, you might want to look into #SpringBootApplication which, when used, enables component scan automatically. All you have to do is making sure your #Component classes are defined in the same package as, or sub-packages of, the #SpringBootApplication-annotated class.
Once you've enabled component scanning, you can just inject a List<AnimalService> where you need it, like in a constructor, and do your processing (filtering?) there.

Spring MVC: Inheriting controllers

Within my web application I have a tool for generating PDF/XLS reports. These "reporters" inherit from a basic controller and they just describe the reporting functionality, something like:
public abstract class Reporter {
getPath() {
return "/reporter/" + getClass().getSimpleName().replace("Reporter", "").toLowerCase() + ".{pdf|xls}";
}
handleRequest() {
// prepare the data
generateReport(...)
// do something with it
// then report pdf or excel
}
}
#Controller
public class DailyReporter extends Reporter {
#Override
void generateReport(...) {}
}
#Controller
public class AverageReporter extends Reporter {
#Override
void generateReport(...) {}
}
In this way I can just describe the data for each Reporter.
Using Spring MVC, the getPath() method is actually part of the Annotation, but using getClass().getSimpleName().toLowerCase() in the annotation is not possible as it needs to be "Compile time constant". Is there a way to do this with Spring MVC?
Don't use inheritance. Use composition/delegation.
Have a single controller, mapped to /reporter/{type}.{pdf|xls}. Define an interface Reporter, and one spring bean implementing that interface per type of report. Inject a List<Reporter> in your controller. And for each request, find the reporter responsible for the type passed in the URL, and call it.

Load service for interface only where there is no other service

In my application I have interface with default implementation that is service:
public interface MessageGenerator {
Message getMessage();
}
#Service
public class PropertiesMessageGenerator implements MessageGenerator {
#Override
public Message getMessage() {
return doSmth();
}
}
This service is loaded by spring boots #ComponentScan and everything works fine until I've added new implementation with #Profile
#Service
#Profile("p1")
public class ProfileMessageGenerator implements MessageGenerator {
#Override
public Message getMessage() {
return doSmthWithProfile();
}
}
How can I stop loading into DI service PropertiesMessageGenerator when ProfileMessageGenerator is in context?
PS
I cannot use #Profile("default") on MultipleMessages, because I've got more profiles that I load at one time.
A bit late to the party, but might help future visitors:
I've got it working in Spring Boot 2.5.1 by configuring my service like this:
#Service
#ConditionalOnMissingBean(value = BaseService.class, ignored = DefaultService.class)
public class DefaultService implements BaseService {
...
}
Without the ignored field in the annotation, the condition will match DefaultService and thus not instantiate it. That behavior is a bit strange, but excluding itself from the condition makes it work. With this, I can create an additional implementation of BaseService that is just annotated with #Service and instead it will not instantiate DefaultService but the other implementation.
If you don't use component scanning you could define and pick the bean using #Qualifier
If you want to maintain using component scanning use the #Conditional annotation.
Create your own implementation of 'org.springframework.context.annotation.Condition.class' and pass this to the annotation.
This could read a property to define when it returns true which could be set when what you want is in the context.
#ConditionalOnMissingBean(MessageGenerator.class) can be used if you do not want to implement your own Condition.
Or just annotate ProfileMessageGenerator with #Primary.

How to Initialize Jersey Application (ResourceConfig) With Spring?

I'm using Jersey 2 and Spring, and I'm trying to initialize my Jersey application (i.e. the class derived from ResourceConfig) with parameters from the Spring context.
Background: I have a single Jersey application that I build (i.e. a single WAR) and I deploy it across a server cluster with different Spring configurations on different servers to enable or disable different parts of the server, e.g. some of the servers have /search resources turned on, etc. This was really easy in Jersey 1.0: I just put,
<context:component-scan base-package="com.mycompany.resources.search"/>
in a Spring config to have Jersey scan that particular package and enable the JAX-RS resource providers in it.
Now in Jersey 2.0 the Spring <context:component-scan ... /> doesn't work, so resources have to be programmatically registered in a startup class derived from ResourceConfig:
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.mycompany.resources.search");
}
}
So far so good, but I need to conditionally scan that package, and I can't figure out how to get any Spring configuration into the MyApplication class. I thought that constructor injection might work:
public class MyApplication extends ResourceConfig {
#Autowired
public MyApplication(#Qualifier("my-config") MyConfiguration myConfiguration) {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
However HK2 complains that it can't find a default constructor to use... so this indicates to me that DI is in play in the construction of this class, but that the DI isn't using Spring.
Similarly, using the the Spring bean lifecycle doesn't work:
public class MyApplication extends ResourceConfig implements InitializingBean {
#Autowired
private MyConfiguration myConfiguration;
public MyApplication() {
}
#Override
public void afterPropertiesSet() throws Exception {
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.search");
}
}
}
(The afterPropertiesSet method isn't called.)
So now I'm stuck: is there any way to configure a Jersey ResourceConfig application object using Spring?
UPDATE:
I accepted #JohnR's answer below but I'll also include my eventual solution which I think is a bit cleaner. #JohnR's answer was to have the object initialized twice: first by Spring and then by Jersey/HK2. When Spring initializes the object you cache the dependencies in a static member, and then when Jersey/HK2 initializes it later you can retrieve the dependencies.
I ended up doing this:
public class MyApplication extends ResourceConfig {
public MyApplication() {
ApplicationContext rootCtx = ContextLoader.getCurrentWebApplicationContext();
MyConfiguration myConfiguration = rootCtx.getBean(MyConfiguration.class);
if (myConfiguration.isEnabled()) {
packages("com.mycompany.resources.whatever");
}
}
}
Rather than having the object initialized twice, we let Jersey/HK2 initialize it but then we retrieve the dependencies from Spring.
Both solutions are vulnerable to timing: they both assume that Spring is initialized before Jersey/HK2.
Expanding on my previous comment:
Trying to extend ResourceConfig is dangerous if you don't know what you're doing. Jersey becomes unpredictable, and if you try to subclass it into an Abstract class, Jersey crashes.
Instead, the JAX-RS specification provides us with a very useful interface called Feature: It allows you to register any classes you want as if you were configuring your own application. Furthermore, you don't need to use the awkward AbstractBinder, you just specify what contracts you register your classes with.
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
// Don't use #Component here, we need to inject the Spring context manually.
public class MySpringFeature implements Feature {
#Context
private ServletContext servletContext;
private ApplicationContext applicationContext;
#Autowired
private MySecurityDAO mySecurityDAO;
#Autowired
private MySpringResponseFilter myResponseFilter;
#Override
public boolean configure(FeatureContext context) {
if(this.servletContext == null) {
return false; // ERROR!
}
this.applicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
if(this.applicationContext == null) {
return false; // ERROR!
}
// This is where the magic happens!
AutowireCapableBeanFactory bf = applicationContext.getAutowireCapableBeanFactory();
bf.autowireBean(this);
// From here you can get all the beans you need
// Now we take a Spring bean instance,
// and register it with its appropriate JAX-RS contract
context.register(myResponseFilter, ContainerResponseFilter.class);
// Or, we could do this instead:
SomeSecurityFilter mySecurityFilter = new SomeSecurityFilter();
mySecurityFilter.setSecurityDAO(mySecurityDAO);
context.register(mySegurityFilter, ContainerRequestFilter.class);
// Or even this:
SomeOtherSpringBean someOtherBean = applicationContext.getBean(SomeOtherSpringBean.class);
context.register(someOtherBean, SomeOtherJerseyContract.class);
// Success!
return true;
}
}
And in your ResourceConfig:
public class MyApplication extends ResourceConfig() {
public MyApplication() {
register(MySpringFeature.class);
}
}
Ta-da!
So now I'm stuck: is there any way to configure a Jersey
ResourceConfig application object using Spring?
I don't think you can configure Jersey to obtain your ResourceConfig from Spring as a Spring managed bean. It's a bit hackish, but you could do something like this. Note that you'll end up with two instance of your ResourceConfig: one managed by Spring and another by Jersey:
public class MyApplication extends ResourceConfig {
// static, available to all instances
private static MyConfiguration myConfiguration;
public MyApplication() {
// when Spring creates the first instance of MyApplication, myConfiguration
// will be null because the setter wasn't called yet
if (myConfiguration != null)
{
// second instance created by jersey... Spring will have autowired
// the first instance, and myConfiguration is static
if (myConfiguration.isEnabled())
packages("com.mycompany.resources.search");
}
}
#Autowired
public void setMyConfiguration(MyConfiguration config)
{
// instance level setter saves to a static variable to make it available for
// future instances (i.e. the one created by jersey)
MyApplication.myConfiguration = config;
}
}
Again, this is fairly hackish. You'll want to make sure Spring is initialized before Jersey and look closely at any threading issues that could occur during initialization.

Spring Autowiring not working for Abstract classes

I have a project where I have an interface, an Abstract class implementing the same interface and then a set of concrete classes which implement this interface and extend the Abstract Class.
public interface Invoice
{
void process();
}
#component
public abstract class AbstractInvoice(){
#Resource
protected Writer writer;
protected validateInvoice(){
//some implementation
}
}
#Component
public Class TypeAInvoice() extends AbstractInvoice implements Invoice{
#Override
public void process(){
//... some code
writer.write();
}
}
public Interface Writer(){
public void write();
}
#Component
public class CDWriter implements Writer{
#Override
public void write() { /* implementation.....*/}
}
Spring file has a component scan for the package.
<context:annotation-config>
<context:component-scan base-package="com.xyz" />
I am using a factory to get an instance of TypeAInvoice invoice
Now calling invoice.process() gets a NPE when getting to write.write()
I am not sure what am I missing here. I tried to see the component scan and scope and could not find anything conceptually wrong.
I am using a factory to get an instance of TypeAInvoice invoice
Depending on what your Factory does, this may be the problem. If the Factory creates a new TypeAInvoice, Spring wiring doesn't apply. You have to query the Spring context for the Bean. One way (though not very pretty) is to use ContextLoader:
return ContextLoader.getCurrentWebApplicationContext().getBean(TypeAInvoice.class)
I'd say static Factories and Spring don't go to well together. Spring stands for the Inversion of Control pattern, while Factories stand for the Service Locator pattern. I'd suggest that you get rid of your factories and autowire your Spring Beans.
Everything is good, except for the fact you use a factory to get the TypeAInvoice. If you create it like TypeAInvoice typer = new TypeAInvoice() then spring knows nothing of it, the Writer is not autowired, there for you get the NullPointerException. You should get the bean from the spring application context.
In my case, inside a Spring4 Application, i had to use a classic Abstract Factory Pattern(for which i took the idea from - http://java-design-patterns.com/patterns/abstract-factory/) to create instances each and every time there was a operation to be done.So my code was to be designed like:
public abstract class EO {
#Autowired
protected SmsNotificationService smsNotificationService;
#Autowired
protected SendEmailService sendEmailService;
...
protected abstract void executeOperation(GenericMessage gMessage);
}
public final class OperationsExecutor {
public enum OperationsType {
ENROLL, CAMPAIGN
}
private OperationsExecutor() {
}
public static Object delegateOperation(OperationsType type, Object obj)
{
switch(type) {
case ENROLL:
if (obj == null) {
return new EnrollOperation();
}
return EnrollOperation.validateRequestParams(obj);
case CAMPAIGN:
if (obj == null) {
return new CampaignOperation();
}
return CampaignOperation.validateRequestParams(obj);
default:
throw new IllegalArgumentException("OperationsType not supported.");
}
}
}
#Configurable(dependencyCheck = true)
public class CampaignOperation extends EO {
#Override
public void executeOperation(GenericMessage genericMessage) {
LOGGER.info("This is CAMPAIGN Operation: " + genericMessage);
}
}
Initially to inject the dependencies in the abstract class I tried all stereotype annotations like #Component, #Service etc but even though Spring context file had ComponentScanning for the entire package, but somehow while creating instances of Subclasses like CampaignOperation, the Super Abstract class EO was having null for its properties as spring was unable to recognize and inject its dependencies.After much trial and error I used this **#Configurable(dependencyCheck = true)** annotation and finally Spring was able to inject the dependencies and I was able to use the properties in the subclass without cluttering them with too many properties.
<context:annotation-config />
<context:component-scan base-package="com.xyz" />
I also tried these other references to find a solution:
http://www.captaindebug.com/2011/06/implementing-springs-factorybean.html#.WqF5pJPwaAN
http://forum.spring.io/forum/spring-projects/container/46815-problem-with-autowired-in-abstract-class
https://github.com/cavallefano/Abstract-Factory-Pattern-Spring-Annotation
http://www.jcombat.com/spring/factory-implementation-using-servicelocatorfactorybean-in-spring
https://www.madbit.org/blog/programming/1074/1074/#sthash.XEJXdIR5.dpbs
Using abstract factory with Spring framework
Spring and Abstract class - injecting properties in abstract classes
Inject spring dependency in abstract super class
Spring autowire dependency defined in an abstract class
Spring can you autowire inside an abstract class?
Please try using **#Configurable(dependencyCheck = true)** and update this post, I might try helping you if you face any problems.
So precisely my point here is you don't need to get a bean from spring context all the time.

Resources