Spring switch implementations based on a runtime condition - java

This is a simplified version of what I am trying to achieve.
I have multiple implementations of the same interface. Based on the user input at runtime I want to pick the correct implementation.
For example suppose I an interface called Color. There are many classes that implement this interface, the Red class, the Blue class, the Green class and so on.
At run time I need to pick implementations based on the user input. One way to achieve this would be something like this
#Autowired
#Qualifier("Red")
private Color redColor;
#Autowired
#Qualifier("Green")
private Color greenColor;
private Color getColorImplementation()
{
if(userInput=="red")
{
return redColor;
}
else if(userInput=="green")
{
return greenColor;
}
else
{
return null;
}
}
But the problem with this is that everytime a new implementation is added, I would have to update the code that picks the implementation, which beats the whole purpose of inversion of control part of spring. What is the right way to do this using spring?

You could autowire all implementations of the interface in question and then decide based on properties provided by interface which to use.
#Autowired
private List<Color> colors;
public void doSomething(String input) {
colors.stream().filter(c -> c.getName().contains(input)).findFirst().ifPresent(c -> {
// something
}
}
This is also less magical and more in line with OO principles. Dependency injection is to wire up things initially, not for dynamic switching at runtime.

You want to Autowire the ApplicationContext, then you can get all the Color beans with Map<String, Color> colors = appContext.getBeansOfType(Color.class);. This presumes that the userInput and the bean name are identical.
If that isn't the case, a solution would be to add a getName() to the Color interface; then you can autowire a List<Color> and construct the Map yourself.
Can't you make the Color an Enum?

The Spring ServiceLocatorFactoryBean (scroll down to the middle) API was built just for this purpose:
Create a dummy interface (ColorFactory) that provides a single method such as Color getColor(String color)
Create the proxy bean instance for org.springframework.beans.factory.config.ServiceLocatorFactoryBean passing ColorFactory as the serviceLocatorInterface parameter
Define beans for all of your color implementations with names matching the parameter you'd like to pass to getColor
Inject the factory into the collaborators and invoke getColor as needed
You could contrive this with similar APIs on the ApplicationContext, but the advantage of this approach is that it abstracts Spring from your Java implementation (for XML configured projects).

Same issue happen in my implementation where in, the scenario was based on user input, where the respective interface implementation needs to be invoked.
This solve my problem:
**Base Interface**
#Service
public interface ParentInterface {
public String doThis(ClassA param);
}
**First Implementation**
#Component("FirstImp")
public class FirstServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Second Implementation**
#Component("SecondImp")
public class SecondServiceImp implements ParentInterface {
public String doThis(ClassA param){
}
**Factory**
#Service
public class ServiceResolver {
#Autowired
#Qualifier("FirstImp")
private ParentInterface firstImpl;
#Autowired
#Qualifier("SecondImp")
private ParentInterface secondImpl;
public ParentInterface getInstance(String condition){
switch(condition) {
case "X": return firstImpl;
case "Y": return secondImpl;
default:
throw new IllegalArgumentException(condition);
}
}
}
**Controller**
#RestController
public class UserController {
#Resource
private ServiceResolver serviceresolver;
#PostMapping("/userbase/{inp1}/messages/{inptype}")
public ResponseEntity<String> sendData(#PathVariable String
inp1,#PathVariable String inptype, #RequestBody XYZBean msg)
{
for(ABC data : msg.getSubData())
serviceresolver.getInstance(data.getType()).doThis(msg);
return new ResponseEntity<String>("created",HttpStatus.OK);
}
}

Related

Java - Getter/Setter, behavior and Interfaces

I have a question, a little bit theoretical:
Assume, I have the following classes :
interface ReportInterface {
void execute();
}
class Report implements ReportInterface {
private final Repository rep;
Report(Repository ref){
this.rep = ref;
}
public void execute(){
//do some logic
}
}
class ReportWithSetter implements ReportInterface {
private final Repository rep;
private String release;
ReportWithSetter(Repository ref){
rep = ref;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
public void setRelease(String release){
this.release=release;
}
}
The second report needs an additional parameter release to work properly, but my interface is defined without parameters for execute method, so I work around it with a setter method, so it would look like:
ReportWithSetter rep2 = new ReportWithSetter (rep);
rep.setRelease("R1.1");
rep.execute();
So I don't like this additional rep.setRelease. I looks weird and artificial - a user of this class may be confused, and for example, if I make the class as a singleton bean in Spring, it is a source of potential error, if it is requested for the second time and somebody forgets to trigger rep.setRelease for the second time. Besides putting it into constructor (I want to make it a spring bean), what would be the best practice to handling this situation?
Assuming you are allowed to change the interface, here are a few solutions I can think of:
Solution #1
void execute(Optional<String> release);
or
void execute(#Nullable String release);
and then use them for Report class as execute(Optional.empty()) or execute(null).
Solution #2
void execute(String... release);
and then use it for Report class as execute() and for ReportWithSetter class as execute("R1.1").
Solution #3
Define both void execute(); and void execute(String release); in the interface. Then while implementing, throw UnsupportedOperationException in the method you don't need. For example, in Report class, you would do:
public void execute(){
//do some logic
}
public void execute(String release){
throw new UnsupportedOperationException("Use the overloaded method");
}
You can also make both these methods as default in the interface, so your implementation classes don't have to worry about implementing the unsupported method.
Use whichever is most readable and maintainable for you.
Solution 1: Spring Dependency Injection - Field Injection:
Spring's Dependency Injection works with reflection, so Setter methods are not required.
So if you make your Report class a Spring Bean and use #Autowired to inject another bean, then the Setter method is not required.
It would look like this:
#Component
class ReportWithRelease implements ReportInterface {
#Autowired private final Repository rep;
#Autowired private Release release;
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
I changed "String release" to "Release release", because making a bean of "String" would be also strange. So the "Release" class would have to contain your "String release".
If "String release" contains only some configured value, which does not change at runtime. Then you can use #Value to read its String value from a properties file.
Solution 2: Spring Constructor Injection:
Constructor injection is another option, which is even more recommended.
Then your Report bean would look like this:
#Component
class ReportWithRelease implements ReportInterface {
private Repository rep;
private Release release;
#Autowired
public ReportWithRelease(Repository rep, Release release) {
this.rep = rep;
this.release = release;
}
public void execute(){
if (release == null) throw IlligalArgumentException("release is not specified");
//do some logic
}
}
Factory method patterns are good if you want to create instances of different classes of same interface.
class MyFactory {
ReportInterface createInstance(Class clazz, String... args) {
if (Report.class.equals(clazz)) {
return new Report();
}
if (ReportWithSetter.class.equals(clazz)) {
return new ReportWithSetter(args[0]);
}
throw new IllegalArgumentException(clazz.getName());
}
}
Spring of course offers autowiring, but introducing #AutoWire should be done for systematic purposes.
Here you can do with a two-stage execute, a factory.
class ReportFactory /*ReportWithSetter*/ {
private final Repository rep;
private final String release;
private final ReportInterface report = ...;
ReportFactory (Repository rep, String release) {
this.rep = rep;
this.release = release;
}
public ReportInterface report() {
return report;
}
}
new ReportFactory(rep, release).execute();

Dynamically injecting generic objects with guice

My current situation:
I want to inject the following class into my application:
public interface IConfigAccessor<T extends IConfig> {
...
}
ConfigAccessors are a proxy-objects, created dynamically at runtime. The creation of these object works as follows:
public class ConfigFactory implements IConfigFactory {
private final IConfigUpdater updater;
#Inject
public ConfigFactory(IConfigUpdater updater) {
this.updater = updater;
}
#Override
public <T extends IConfig> IConfigAccessor<T> register(final String configKey, final Class<T> configClass) {
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
As you can see, to create these objects, I need to inject the ConfigUpdater and other depdencies. This means, that guice needs to be fully configured already.
To get the instance out of Guice, I use the following code:
IConfigFactory configClient = injector.getInstance(IConfigFactory.class);
IConfigAccessor<ConcreteConfig> accessor = configClient.register("key", ConcreteConfig.class)
How I want to inject them via Guice:
Currently, I can get the requried objects, but I have to manually pass them around in my application.
Instead, what I want to have is the following:
public class SomeClass {
#Inject
public SomeClass(#Config(configKey="key") IConfigAccessor<ConcreteConfig> accessor) {
// hurray!
}
}
What's the correct approach/technology to get this working?
After a lot of research, I'm feeling a bit lost on how to approach this topic. There are a lot of different things Guice offers, including simple Providers, custom Listeners which scan classes and identify custom annotations, FactoryModuleBuilders and more.
My problem is quite specific, and I'm not sure which of these things to use and how to get it working. I'm not even sure if this is even possible with Guice?
Edit: What I have so far
I have the following annotation which I want to use inside constructor paramters:
#Target({ ElementType.FIELD, ElementType.PARAMETER })
#Retention(RetentionPolicy.RUNTIME)
public #interface InjectConfig {
String configKey();
}
Inside the module, I can bind a provider to IConfigAccessor (with the above annotation) as such:
bind(IConfigAccessor.class).annotatedWith(InjectConfig.class)
.toProvider(new ConfigProvider<>());
However, there are two problems whith this:
The provider cannot provide IConfigAccessor. To create such an instance, the provider would need an IConfigUpdater, but since I use 'new' for the provider, I can't inject it.
Inside the provider, there is no way to find out about the configKey used in the Annotation.
Second approach:
Let's assume that I already know all configurations and configKeys I want to inject during startup. In this case, I could loop over all possible configKeys and have the following binding:
String configKey = "some key";
final Class<? extends IConfig> configClass =...;
bind(IConfigAccessor.class).annotatedWith(Names.named(configKey))
.toProvider(new ConfigProvider<>(configKey, configClass));
However, problem (1) still resides: The provider cannot get an IConfigUpdater instance.
The main problem here is that you cannot use the value of the annotation in the injection. There is another question which covers this part:
Guice inject based on annotation value
Instead of binding a provider instance, you should bind the provider class, and get the class by injecting a typeliteral.
That way, your config factory can look like that:
public class ConfigFactory<T extends IConfig> implements IConfigFactory {
#Inject private final IConfigUpdater updater;
#Inject private TypeLiteral<T> type;
#Override
public IConfigAccessor<T> register(final String configKey) {
Class<T> configClass = (Class<T>)type.getRawType();
ConfigCache<T> configCache = new ConfigCache<>(new SomeOtherThings(), configKey, configClass);
updater.register(configCache);
return new ConfigAccessor<>(configCache, configKey, configClass);
}
}
And then SomeClass:
public class SomeClass {
#Inject
public SomeClass(ConfigFactory<ConcreteConfig> accessor) {
ConcreteConfig config = accessor.register("key");
}
}
Since SomeClass needs to know "key" anyway, this is not too much a change information-wise. The downside is that the SomeClass API now gets a factory instead of the concrete config.
[EDIT]
And here is someone who actually did inject annotated values using custom injection.

Java : Builder Design Pattern

I have classes which has been autowired with all the attributes related to it. I need to return the object of these classes when a request for a particular class is received. A senior developer is suggesting to use the builder pattern. However the information I would be passing is just the request. I am confused can someone help.
Class DogDetailsProvider{
#Autowired
DogVendor dVendor;
#Autowired
DogOwner dOwner;
#Autowired
DogHealth dHealth;
}
Class CatDetailsProvider{
#Autowired
CatVendor cVendor;
#Autowired
CatOwner cOwner;
#Autowired
CatHealth cHealth;
}
Class ElephantDetailsProvider{
#Autowired
EleVendor eVendor;
#Autowired
EleOwner eOwner;
#Autowired
EleHealth eHealth;
}
I think that you probably need something like Service Locator Pattern. It helps decide which object you have to use depending on particular request. It reduces boilerplate code when you want to access your services.
At first you have to create interface with accessor methods to your vendor/owner/health classes:
public interface DetailsProvider {
Vendor getVendor();
Owner getOwner();
Health getHealth();
}
Your DogDetailsProvider, CatDetailsProvider, ElephantDetailsProvider have to implement that DetailsProvider interface. Also your vendor/owner/health classes have to have interface to keep inheritance mechanism.
Then you have to create service locator:
#Service
public class DetailsProviderLocator {
private DetailsProvider dogDetailsProvider;
private DetailsProvider catDetailsProvider;
private DetailsProvider elephantDetailsProvider;
#Autowired
public DetailsProviderLocator(
#Qualifier("DogDetailsProvider") DetailsProvider dogDetailsProvider,
#Qualifier("CatDetailsProvider") DetailsProvider catDetailsProvider,
#Qualifier("ElephantDetailsProvider") DetailsProvider elephantDetailsProvider) {
this.dogDetailsProvider = dogDetailsProvider;
this.catDetailsProvider = catDetailsProvider;
this.elephantDetailsProvider = elephantDetailsProvider;
}
DetailsProvider getDetailsProvider(Animal animal) {
switch(animal) {
case CAT : return catDetailsProvider;
case DOG : return dogDetailsProvider;
case ELEPHANT : return elephantDetailsProvider;
default : throw new IllegalArgumentException("Not allowed!");
}
}
}
public enum Animal {
CAT, DOG, ELEPHANT;
}
Now depending on enum (which can be anything, depends on your request) your service locator will return specific service. It is also easy to extend, because of inheritance you can create new services and just add new value to enum.
I need to return the object of these classes when a request for a particular class is received
This sounds like you need getter methods for objects such as dVendorin classes like DogDetailsProvider. You can either add boilerplate code for the getter methods or use lombok's #Getter.
Builder pattern is used to create objects by exposing setter methods in a builder class for each of the attributes of the object which needs to be built. Since you need to "get" and not "set" any data, using the Builder pattern would not help at all.

Configure Implementation Class of Abstract Factory with Spring

For my application, I have a Scale interface and multiple classes implementing this interface, for example NormalizedScale, LogScale, etc. In one of my Services, I need to create many Scales, and I want to use Spring to define which implementation of the Scale it should create. How would I implement something like this?
--
I was thinking to create a factory ScaleFactory, like in the Abstract Factory Pattern, which I could call ScaleFactory.getScale() to get a Scale of whichever implementation I configured in the Spring XML:
class ScaleFactory {
Class<? extends Scale> scaleImplClass;
public static Scale getScale() {
return scaleImplClass.newInstance();
}
}
Scale myScale = ScaleFactory.getScale();
But with that approach, how could I configure which implementation the ScaleFactory should use from Spring XML?
--
An alternative would be to make the ScaleFactory a #Service, and then autowire the ScaleFactory into my service:
#Autowired
ScaleFactory scaleFactory;
...
Scale myScale = scaleFactory.getScale();
Then I can use an autowired property in the ScaleFactory to define the scaleImplClass. But that seems weird because my Factory is also a Service and I have an instance of that factory.
--
Another approach would be to have the Class scaleImplementationClass property in my service instead of the ScaleFacotry and use the ScaleFactory like so:
#Value("${scaleImplementationClass}")
Class scaleImplementationClass
...
Scale myScale = ScaleFactory.getScale(scaleImplementationClass);
But then the factory is quite pointless because I could also just as well run scaleImplementationClass.newInstance().
There are a couple of different Spring-like ways you can handle this. The approach I have personally gone for looks a bit like this:
public interface ScaleFactory {
public Scale newInstance();
public String type();
}
public class FirstScaleFactory implements ScaleFactory {
public Scale newInstance() {
return new FirstScale();
}
public String type() {
return "first";
}
}
public class SecondScaleFactory implements ScaleFactory {
public Scale newInstance() {
return new SecondScale();
}
public String type() {
return "second";
}
}
public class ScaleManager {
private final Map<String, ScaleFactory> factories;
#Autowired
public ScaleManager(List<ScaleFactory> factories) {
this.factories = factories.stream()
.collect(Collectors.toMap(f -> f.type(), Function::identity));
}
public Scale newInstance(String type) {
return Optional.ofNullable(factories.get(type))
.map(factory -> factory.newInstance())
.orElseThrow(IllegalArgumentException::new);
}
}
With this approach, your ScaleManager is a standard Spring bean that can be wired into any class that needs a scale instance. At initialization time, it gets all ScaleFactories that are defined in the Spring context, and autowires them in as a List<ScaleFactory>, which is then converted to a Map (where the ScaleFactory type is the key). This avoids you needing to worry about class names of Scale, and gives your the ability to change them later (as long as you keep the type key consistent)`
Your ScaleFactory implementations can then do whatever they need to do. For example, if you have one type of Scale that you know is immutable, you can have the factory return the same instance every time. Alternatively you can have every invocation return a separate instance - the instantiation of the Scale is up to the implementation-dependent factory.
You can simply use "Qualifiers" which is basically going to point to a specific "named" bean. By default the bean names are the name of your classes, with the first letter in lower case (MyClass -> myClass). If you want to define your own names you can do as follow :
#Service("customizedBeanName")
You would end up doing something like this :
#Autowired
#Qualifier("logScale")
private Scale logScale;
#Autowired
#Qualifier("anotherScale")
private Scale anotherScale;
As for spring 5.x there's a simpler and cleaner way of doing this. I have decided to use #ConditionalOnProperty annotation but you may choose any #Conditional* of your preference.
Here's the thing, I've have simplified to extreme:
public interface MyService {}
#Service
#ConditionalOnProperty(prefix = "myService", name = "Impl", havingValue = "Some")
public class SomeService implements MyService {}
#Service
#ConditionalOnProperty(prefix = "myService", name = "Impl", havingValue = "Foo")
public class FooService implements MyService {}
#Service
public class SimpleService {
#Autowired
SimpleService(MyService service) {
// service instance will depend on configuration
}
}
I'm using springboot so I've decided to use application.properties in order to set values via environment variables like this:
myService.Impl=${MY_SERVICE_IMPL}
Then, I have a fully dynamic injection based on environment variables that may be passed to a docker container for instance.

Changing Guice bindings at runtime

I would like to be able to change the Guice injections at runtime to support multiple injections based on user input. This is what I would like to achieve:
public interface IDao {
public int someMethod();
}
public class DaoEarth implements IDao {
#Override
public int someMethod(){ ... }
}
public class DaoMars implements IDao {
#Override
public int someMethod(){ ... }
}
public class MyClass {
#Inject
private IDao myDao;
public int myMethod(String domain) {
//If Domain == Earth, myDao should be of the type DaoEarth
//If Domain == DaoMars, myDao should be of the type DaoMars
}
}
I was thinking of writing my own Provider, but I don't know how to use that provider to change my bindings at runtime. Any input is welcome and appreciated :)!
Update
Here's what I currently came up with, it's not as pretty as I'd like, so I'm still looking for feedback
public class DomainProvider {
#Inject #Earth
private IDaoProvider earthDaoProvider;
#Inject #Mars
private IDaoProvider marsDaoProvider;
public IDaoProvider get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public IDaoProvider get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
//MarsDaoProvider would be equivalent
public class EarthDaoProvider implements IDaoProvider {
#Inject #Earth
private IDao earthDao;
public IDao getDao() {
return earthDao;
}
}
// This means that in "MyClass", I can do:
public class MyClass {
#Inject
private DomainProvider domainProvider;
public int myMethod(String domain) {
IDaoProvider daoProvider = domainProvider.get(domain);
IDao dao = daoProvider.getDao();
//Now "dao" will be of the correct type based on the domain
}
}
//Of course elsewhere I have the bindings set like
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
Your version is almost perfect as it is: You're going to need to inject some kind of object that returns one or the other based on code you write, and don't need assisted injection or anything like that. That said, you can skip some of the boilerplate:
public class DomainProvider {
// Just inject Providers directly without binding them explicitly.
#Inject #Earth Provider<IDao> earthDaoProvider;
#Inject #Mars Provider<IDao> marsDaoProvider;
public Provider<IDao> get(Domain domain){
switch (domain){
case EARTH:
return earthDaoProvider;
case MARS:
return marsDaoProvider;
}
}
public Provider<IDao> get(String domain){
Domain parsedDomain = Domain.valueOf(domain.toUpperCase());
return get(parsedDomain);
}
}
Your MyClass in that case would be exactly identical. Here, Provider is either the one-method generic interface com.google.inject.Provider, or the equivalent builtin javax.inject.Provider that it extends. Read more about Guice Providers on the relevant Guice wiki topic.
bind(IDao.class).annotatedWith(Earth.class).to(EarthDao.class);
// You can now inject "#Earth IDao" and also "#Earth Provider<IDao>".
Basically, if you bind a key Foo (to a class, provider, #Provides method, or instance), you automatically get to inject either a Foo or Provider<Foo> with no additional work. Providers are also a great way to ensure that you get a new instance with every call to get, if that's what you want; with your original, you'll always get the same instance of EarthDao or MarsDao for any given DomainProvider you inject. (If you have a scoped binding like #Singleton, Guice will respect that too; Provider just lets Guice get involved, rather than reusing a plain old Java reference.)
This means you can skip your custom EarthDaoProvider and MarsDaoProvider, unless you really need to perform any external initialization on them—at which point you'd probably be better off calling bind(EarthDao.class).toProvider(EarthDaoProvider.class) so the preparation also happens when injecting EarthDao directly. You could also just have DomainProvider return an IDao instance directly by calling get on the appropriate Provider, and be assured that it'll be a new instance every time.

Categories