Inheritance (Late Binding) via Dependency Injection in Java - java

I am using Spring DI to wire my components and I came across this issue.
I have a BaseService class which has multiple implementations. And the layer above it, has a builder which calls the service to get data to populate POJOs. Service implementation I need to call (ServiceA,ServiceB) changes according to the type of POJO I need to build.
In such case, how can I autowire the service, as it requires late binding the service. How can I tackle this kind of scenario? (Example in Spring DI would really help)
I read similar questions but could not find the answer. And I read that SOA patterns such as Service Host provide different solutions to exact use case.
Please help.
Thanks

How about using a FactoryBean:
public class BuilderFactory implements FactoryBean<Builder> {
#Autowired
private ApplicationContext appContext;
...
#Override
public Builder getObject() {
Builder builder = new Builder();
switch(something()) {
case "foo":
builder.service = new ServiceA();
break;
case "bar":
builder.service= new ServiceB();
break;
...
default:
//handle cases where it's unclear which type to create
}
return builder;
}
}
where Builder instances have a public/package-private field BaseService service that gets called in their getData(), buildPojos() and wherever other methods.
(you could also use static factory methods to instantiate Builder if you want this field to be private)

You can use ServiceLocatorFactoryBean. In your case you would do something like this:
public interface BaseServiceLocator {
BaseService lookup(String qualifier); //use whatever qualifier type makes sense here
}
<bean id="serviceLocatorFactoryBean"
class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface"
value="your.package.BaseServiceLocator" />
</bean>
Then your builder would look something like this:
public class Builder {
#Autowired
private BaseServiceLocator baseServiceLocator;
#Override
public YourReturnType businessMethod() {
SomeData data = getData();
BaseService baseService = baseServiceLocator(data.getType()); //here I am assuming that getType() is a String
//whatever
}

I had the same requirement in one of my projects. I used reflection to get the services according to the pojo requirement. This way there will be no static values even if you define new pojo and service in future you wont have to change any implementation.
I had named my pojos and Services similarly. ie
POJO Name:Pond5DownloadStrategy and ServiceName: Pond5DownloadStrategyService.
I defined all the services in spring. I had a DownloadStrategyFactory which had a single method
getService(Object obj). which is also instantiated as spring bean.
what getService method did is.
I get the POJO name as string using obj.getClass().getSimpleName() and then I append Service at the end. ex.
If I pass Pond5DownloadStrategy then I do AppContext.getBean("Pond5DownloadStrategyService");

Please look at my answer here.
Although is under spring batch topic it’s actually related to your question and the Strategy Design pattern.
StrategyA StrategyB are your ServiceA,ServiceB etc.
You need to use the StrategyLocator in your Builder class (in the original answer it’s equivalent is MyTaskelt). The look-up will be based on your pojo type.
strategy = strategyLocator.lookup(POJOs.class);
In the answer I suggested a PlugableStrategyMapper, but if you predefine all Servcies you can place them in a Map in the application-context.xml

For example, for manual binding:
public class Builder {
#Autowired
private Map<String, Service> services;
// Bind pojo classes to bean names.
private Map<Class<?>, String> binding;
public Service getService(Object object) {
return services.get(binding.get(object.getClass()));
}
public Map<Class<?>, String> getBinding() {
return binding;
}
public void setBinding(Map<Class<?>, String> binding) {
this.binding = binding;
}
}
However, manual binding could be repetitive so if you don't really need his flexibility, you could use a naming convention (#AmitChotaliya answer) or enforce the binding via Service method.
public interface Service {
Class<?> getTargetType();
}
public class Builder {
#Autowired
private Set<Service> services;
// Bind pojo classes to Services.
private Map<Class<?>, Service> binding = new ConcurrentHashMap<Class<?>, Service>();
#PostConstruct
public void init() {
for (Service service : services) {
binding.put(service.getTargetType(), service);
}
}
public Service getService(Object object) {
return binding.get(object.getClass());
}
}

Related

Incapsulating class with static wrapper method is good idea?

I have been refactoring a huge method in the project I work and came up with this idea to create a validation service like this -
public class TrickyValidation {
String validationVariable1;
String validationVariable2;
String validationVariable3;
HashMap<String, Object> itemsMap;
Object dependentObject;
#Autowired
SpringService service;
public static boolean doTrickyValidation(HashMap<String, Object> itemsMap, Object dependentObject) {
return new TrickyValidation(itemsMap, dependentObject).validate();
}
private TrickyValidation(Object itemsMap, Object dependentObject) {
this.itemsMap = itemsMap;
this.someDependentObject = dependentObject;
init();
}
private boolean validate() {
// loads of logic for validation by using validationVaribales
return true;
}
private void init() {
// Some methods to extract thease variables from itemsMap, dependentObject etc..
this.validationVariable1 = service.get(dependentObject);
this.validationVariable1 = ...;
this.validationVariable1 = ...;
}
}
My goal what I want to do here is to Encapsulate everything as much as possible and use clean code principles.
I feel a bit here like fighting spring framework because I don't want
that "TrickyValidation" class would be #Servcie and belong to spring container. Will Autowired even work here?
Is it a good design? Most likely I will use this validation in a loop. I like this solution because when I have to validate things I just simply call one and only public static method of this class TrickyValidation.doTrickyValidation(map, obj)
Any suggestions are welcome on how to improve this, or why it's a bad idea.
This code probably won't work because in the init method of the object you're trying to access service which is not autowired into this instance. In general the autowiring works only for objects managed (created by) Spring.
In this case you create "manually" the object of class TrickyValidation...
IMO the better design is to split the "Validator" object that can be Spring managed and the Validation itself that is not spring based.
#Component
public class Validator {
#Autowired
private Service service;
public boolean doTrickyValidation(HashMap<String, Object> itemsMap, Object dependentObject) {
// resolve the validation strategy from the items passed to this method.
TrickyValidation validation = resolveTrickyValidation(itemsPam, dependentObject);
return validation.validate();
}
private TrickyValidation resolveTrickyValidation(...) {
// construct the proper validation strategy
// access service if you want
}
}

How to Inject all subclasses of a specific class with no common interface?

Question:
In order to Inject all subclasses of a superclass with no common interface, I created an interface tightly-coupled to said superclass, that every "properly" written subclass is supposed to implement.
This works, but seems insane. Was there a better way?
A simple cast do not work, as the Instance holds only a proxy that do not resolves to any real subclass of the interface when called. This results in a ClassCastException.
Some context:
I was recently tasked to provide framework code for an application. In this application, several data transfer objects are mapping from and to service level POJOs, but their mappings are not always trivial. Dozer is used to do most of the work and to avoid boilerplate code.
In the specific cases requiring explicit mapping instructions, the current recommendation with Dozer is to use the API driven mapping. All the BeanMappingBuilder subclasses, defining the mappings, should be added to the Dozer mapper upon initialisation.
In order to keep all the work needed to add a new BeanMappingBuilder in one place, I came with a convoluted use of dependancy injection that will automatically add it to the Dozer mapper, despite it having no common interface, only a common superclass with the others.
Some code:
The interface:
#Local
public interface DtoBeanMappingBuilder {
BeanMappingBuilder get();
}
Subclass example:
#Stateless
public class SomeDtoMappingBuilder extends BeanMappingBuilder implements DtoBeanMappingBuilder {
#Override
public BeanMappingBuilder get() {
return this;
}
#Override
protected void configure() {
mapping(
// Some mapping...
);
}
}
Mapper with injection point:
#Singleton
#Startup
public class DtoBeanMapper {
private DozerBeanMapper innerMapper;
#Inject
#Any
private Instance<DtoBeanMappingBuilder> mappingBuilders;
public <D> D map(Object source, Class<D> destinationClass) {
return innerMapper.map(source, destinationClass);
}
#PostConstruct
private void init() {
innerMapper = new DozerBeanMapper();
mappingBuilders.forEach(mb -> innerMapper.addMapping(mb.get()));
}
}

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.

Dependency injection using Guice with the DAO pattern

For a small side project I'm working on I've been trying to implement something of a DAO pattern for my interactions with the DB, and have started using Guice (for my first time) to handle the DI for me. Right now I have this class hierarchy:
DAOImpl takes a reference to a class type so my database client (mongo/morphia) can do some initialization work and instantiate a BasicDAO provided by morphia. Here's snippets of the relevant classes:
public class DAOImpl<T> implements DAO<T> {
private static final Logger LOG = LoggerFactory.getLogger(DAOImpl.class);
private static final String ID_KEY = "id";
private final org.mongodb.morphia.dao.DAO morphiaDAO;
#Inject
public DAOImpl(Datastore ds, Class<T> resourceClass) {
morphiaDAO = new BasicDAO(resourceClass, ds);
LOG.info("ensuring mongodb indexes for {}", resourceClass);
morphiaDAO.getDatastore().ensureIndexes(resourceClass);
}
}
public class UserDAO extends DAOImpl<User> {
#Inject
public UserDAO(Datastore ds) {
super(ds, User.class);
}
public User findByEmail(String email) {
return findOne("email", email);
}
}
I know that I need to tell Guice to bind the relevant classes for each generic DAOImpl that gets extended, but I'm unsure of how to do it. This looks like it might have been answered but it's not clicking for me. I've tried some of the following:
public class AppInjector extends AbstractModule {
#Override
protected void configure() {
bind(com.wellpass.api.dao.DAO.class).to(DAOImpl.class);
// bind(new TypeLiteral<SomeInterface<String>>(){}).to(SomeImplementation.class);
// bind(new TypeLiteral<MyGenericInterface<T>>() {}).to(new TypeLiteral<MyGenericClass<T>>() {});
// bind(new TypeLiteral<DAO<User>>() {}).to(UserDAO.class);
bind(new TypeLiteral<DAO<User>>(){}).to(new TypeLiteral<DAOImpl<User>>() {});
}
}
These are some of the the errors I've seen:
com.google.inject.CreationException: Unable to create injector, see the following errors:
1) No implementation for org.mongodb.morphia.Datastore was bound.
while locating org.mongodb.morphia.Datastore
for the 1st parameter of com.wellpass.api.dao.UserDAO.<init>(UserDAO.java:12)
at com.wellpass._inject.AppInjector.configure(AppInjector.java:18)
2) java.lang.Class<T> cannot be used as a key; It is not fully specified.
at com.wellpass.api.dao.DAOImpl.<init>(DAOImpl.java:19)
at com.wellpass._inject.AppInjector.configure(AppInjector.java:14)
Any help would be much appreciated.
If you want an injection site like the following:
#Inject
public DAOConsumer(DAO<User> dao) {
}
to be injected with an instance of your UserDAO class then
bind(new TypeLiteral<DAO<User>>() {}).to(UserDAO.class);
is the correct syntax.
As for your other error:
1) No implementation for org.mongodb.morphia.Datastore was bound.
This is because Datastore is an interface. You need to bind the interface to an implementation, an instance, or a Provider<Datastore>.
To work out how to do this, think of the steps you would need to do this manually without the extra complication of Guice. Once you 100% understand this, you can try and design an object graph that appropriately reflects the steps in the initialization of morphia.
To get you started, the morphia quick tour has a guide on how to get an instance of the Datastore object:
final Morphia morphia = new Morphia();
// tell Morphia where to find your classes
// can be called multiple times with different packages or classes
morphia.mapPackage("org.mongodb.morphia.example");
// create the Datastore connecting to the default port on the local host
final Datastore datastore = morphia.createDatastore(new MongoClient(), "morphia_example");
datastore.ensureIndexes();
From their code, you can see that there are at least two dependencies required to get the Datastore:
A singleton Morphia
A singleton MongoClient
You will have to write some code to set this up, possibly using Guice's Provider class.

Categories