Spring Dependency Injection with Generic Types - java

There exist following classes
class Entity{
}
class Dto{
}
public abstract class BaseMapper<E extends Entity, D extends Dto>{
}
And several sepcific implementation of mappers like:
FooMapper extends BaseMapper<Foo, FooDto>{
}
FeeMapper extends BaseMapper<Fee, FeeDto>{
}
No I want to integrate some "Wrapper" which does a bit more than normal mapping of the data, because I got a new concept/issue
#Component
public final class RevMapper<ENTITY extends Entity, DTO extends Dto> {
private BaseMapper<ENTITY, DTO> baseMapper;
#Autowired
public <MAPPER extends BaseMapper<ENTITY, DTO>> RevMapper(MAPPER mapper) {
this.baseMapper = mapper;
}
public List<RevDto<DTO>> toDto(final List<Rev<ENTITY>> revList) {
for(Rev<ENTITY> rev: revList){
...
baseMapper.toDto(rev.getEntity(), true);
}
...
}
}
And include it in my service like:
#Autowired
private RevMapper<Foo, FooDto> fooRevMapper;
The problem now is:
Parameter 0 of constructor in com.test.package.RevMapper required a single bean, but 2 were found:
- FooMapper
- FeeMapper
Spring doesn't know which to take. And yeah what I know is about the type erasure in generics. So basically after compile the application just know that there is a
RevMapper<Entity,Dto>
but not which type it is specifically. How could I tell Spring to insert the right component, or how would you handle this problem. I do not want to write the same lines of code for each type of Mapper....

The solution I can think of is not as time consuming than creating many many subclasses.
First make the RevMapper not a #Component and then create a class like follows:
#Configuration
public final class Mappers{
private final FooMapper fooMapper;
private final FeeMapper feeMapper;
#Autowired
public Mappers(FooMapper fooMapper, FeeMapper feeMapper){
this.fooMapper = fooMapper;
this.feeMapper = feeMapper;
}
#Bean
public RevMapper<Foo, FooDto> fooRevMapper(){
return new RevMapper(fooMapper);
}
#Bean
public RevMapper<Fee, FeeDto> feeRevMapper(){
return new RevMapper(feeMapper);
}
}
It's no more than just creating a method for every different RevMapper you want to provide.

Related

What is the advantage of #Qualifier in Spring?

Let's say we have 2 implementations of an interface:
#Component
public class Toyota implements Car {}
#Component
public class Bmw implements Car {}
What is the advantage of using a #Qualifier
#Autowired
#Qualifier("toyota")
private Car car;
over using the specific implementation type when autowiring?
#Autowired
private Toyota car;
The downside of #Qualifier I see here is losing "type-safety" by relying on a string that could get out of sync with the bean (class) name.
How to avoid this fragility? What is the advantage of #Qualifier?
There are other ways to create beans besides #Component. Consider:
#Configuration
public class CarConfig {
#Bean
public Toyota first() {
return new Toyota(1);
}
#Bean
public Toyota second() {
return new Toyota(2);
}
}
In this case, your 2nd example where you disambiguate by choosing a more specific type is not possible. Using a named qualifier is the only way to select between these two.
You also may not want the client class to know about the specific implementations of your interface. It might encourage the client class to use methods of Toyota's API that aren't part of Car's interface. Relying on those methods will increase coupling and may make it harder to swap out the implementation for a different one later.
How about the following approach:
public final class CarTypes {
private CarTypes() {}
public static final String TOYOTA = “toyota”;
public static final String BMW = “bmw”;
}
public interface Car {...}
public class Toyota implements Car {...}
public class BMW implements Car {...}
#AllArgsConstructor
public class CarFactory { // or whatever that uses the car
private final Car car;
}
And the spring configuration:
static import CarTypes.*;
#Configuration
public class MyConfig {
#Bean(name = TOYOTA)
public Car toyotaWhateverMethod() { return new Toyota();}
#Bean(name = BMW)
public Car bmwWhateverMethod() {return new BMW();}
#Bean
public CarFactory toyotaCarFactory(#Qualifier(TOYOTA) Car car) {
return new CarFactory(car);
}
}
Note that the classes themselves do not carry any annotation at all, and in the configuration you always rely on the final fields of a statically imported class CarTypes
It allows you to program to an interface rather than the implementation. Refer this for why it is good to program to an interface.
So if you program to an interface , you should auto-wire to an interface rather than an implementation, and #Qualifier is used to specify which bean to be injected if you have more than one bean implement the same interface.
I see here is losing "type-safety" by relying on a string that could
get out of sync with the bean (class) name. How to avoid this
fragility?
You can simply configure the bean name in #Component explicitly rather than relies on the default which the bean name is derived from the class name. Set a constant for the bean name and make sure the all codes that need to access it should access via this constant :
#Component(Toyota.BEAN_NAME)
public class Toyota implements Car {
public static final String BEAN_NAME = "MyToyota";
}
#Autowired
#Qualifier(Toyota.BEAN_NAME)
private Car car;

Spring Boot : generic Crudrepository interface and generic service interface

I wanted to know if i could use the same spring crudRepository and Services interface with multiple classes by attributing a generic type to both of them in order to avoid rewriting the same thing over and over.
i'll try to explain this idea better with an example;
imagine if we had two different classes "Dog" and "Cat"
public class Dog extends Serializable{ //attributes here... }
public class Cat extends Serializable{ //attributes here... }
the service interface will more likely look like this :
public interface Services<T> {
List<T> getAllRecords();
T getRecordById(int id);
T insertRecord(T animal);
// etc
}
and the repository will be like this :
public interface GenericRepository<T> extends CrudRepository<T,Serializable>{ //....}
then we'll be able to implement the services such as this :
#Service
public class CatServiceImpl implements Services<Cat>
{
#Autowired
GenericRepository<Cat> repositoryCat;
//...
}
#Service
public class DogServiceImpl implements Services<Dog>
{
#Autowired
GenericRepository<Dog> repositoryDog;
//...
}
and so on..
the problem is in the controller how can the #AutoWired annotation differentiate between the implementations?
Any suggestions?

Limit a collection of autowired components using Package

I am working on a project for parsing files that uses Chains of Responsibility of an abstract class called EntityMapper that are used for parsing. Currently we have 2 types of Files/Entities:
GrantEntity
BillEntity
All EntityMappers extend the abstract class:
public abstract class EntityMapper<T extends AbstractBaseEntity> implements Function<MapperExchange, T>
Soon we will have a DonationEntity that will represent a file that has some structural characteristics as grantEntity.
Instead of creating new classes of Type extends EntityMapper<DonationEntity> I wanted to ask if there is a way to filter an #AutoWired collection using package names or a regex.
Something like ?:
#Autowired
#ComponentScan("com.my.package.first,com.my.package.second")
private List<EntityMapper<GrantEntity>> entityMappers;
I unfortunately did not find an answer in the link below except to do it by hand and remove the elements from the collection:
How to filter a collection of beans using a collection of regex in Spring?
You can use #Qualifer annotation to indicate logically similar components. Then specify a matching #Qualifier to the injection target. For example
class DependencyToInject{
}
#Configuration
public class AppConfig{
#Bean
#Qualifier("main")
public DependencyToInject dependency1(){
//return instance
}
#Bean
#Qualifier("main")
public DependencyToInject dependency2(){
//return instance
}
#Bean
#Qualifier("sub")
public DependencyToInject dependency3(){
//return instance
}
}
#Component
public class DependentClass{
#Autowired
#Qualifier("main")
private List<DependencyToInject> mainList;
#Autowired
#Qualifier("sub")
private List<DependencyToInject> subList;
}

What is the best approach to get injected beans with same interface in factory using Spring?

I created one factory to decide what best implementation should be returned, based in some conditional check.
// Factory
#Component
public class StoreServiceFactory {
#Autowired
private List<StoreService> storeServices;
public StoreService getService(){
if(isActiveSale){
return storeServices.get("PublicStoreService")
}
return storeServices.get("PrivateStoreService")
}
}
//Service Implementations
#Service
#Qualifier("PublicStoreService")
public class PublicStoreService implements StoreService {
public getStoreBalanceScore(){
Do Stuff....
}
}
#Service
#Qualifier("PrivateStoreService")
public class PrivateStoreService implements StoreService {
public getStoreBalanceScore(){
Do Stuff....
}
}
// Controller
#Autowired
StoreServiceFactory storeServiceFactory;
#Override
public StoreData getStoreBalance(String storeId) {
StoreService storeService = storeServiceFactory.getService();
return simulationService.simulate(sellerId, simulation);
}
Is this approach good? If yes, how can i get my service from an elegant way?
I would like to use only annotations, without configurations.
You should use a map instead of a List and pass a string parameter to the getService method.
public class StoreServiceFactory {
#Autowired
private Map<String,StoreService> storeServices = new HashMap<>();
public StoreService getService(String serviceName){
if(some condition...){
// want to return specific implementation on storeServices map, but using #Qualifier os something else
storeServices.get(serviceName)
}
}
}
You can prepopulate the map with supported implementations. You can then get an appropriate service instance as follows :
// Controller
#Autowired
StoreServiceFactory storeServiceFactory;
#Override
public StoreData getStoreBalance(String storeId) {
StoreService storeService = storeServiceFactory.getService("private");//not sure but you could pass storeId as a parameter to getService
return simulationService.simulate(sellerId, simulation);
}
If you don't like using Strings, you can define an enum for the supported implementations and use that as the key for your map.
You don't need to create a list or map on your code. You can retrieve it directly from Spring context using GenericBeanFactoryAccessor. This has various method to retrieve a specific bean like based on name, annotation etc. You can take a look at javadoc here. This avoids unnecessary complexity.
http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/beans/factory/generic/GenericBeanFactoryAccessor.html

Using guice to pass in a run-time parameter to constructor

If I have the following class:
public class ObjectDAOMongoDBImpl<T> extends GenericDAOMongoDBImpl<T, ObjectId> implements ObjectDAO<T> {
public ObjectDAOMongoDBImpl(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {
super(entityClass, mongo, morphia, dbName);
}
}
Where, entityClass is provided at run-time - how can I use guice to bind the said type to an interface?
public class RunnerModule extends AbstractModule {
#Override
protected void configure() {
bind(GenericDAO.class).to(ObjectDAOMongoDBImpl.class);
}
}
public class Runner<T, V> {
GenericDAO<T, V> dao;
#Inject
public Runner(GenericDAO<T, V> dao) {
this.dao = dao;
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new RunnerModule());
injector.getInstance(Runner.class);
}
}
It's fine to define mongo, morphia, and dbName as literals to RunnerModule (is there a cleaner way?), but I have no way of knowing what entityClass is until runtime.
This isn't doable with Guice idiomatically, and it isn't its primary focus either.
jfpoilpret have said everything that can be said, but I would like to approach the problem from another direction, where you have the option to (possibly) solve your problem by losing type-safety.
So, in your code, you ask Guice to get an instance of your Runner<T, V> class like this
injector.getInstance(Runner.class);
but this can't be resolved by Guice, because Runner<T, V> has a dependency on GenericDAO<T, V>, but you didn't bind an exact implementation for it. So as jfpoilpret has said, you have to bind some concrete implementations for it in your module.
I'm guessing that you want to determine the exact GenericDAO<T, V> implementation that you pass to your Runner<T, V> based on some input data, which data's type isn't known at compile time. Now, let's assume you have two implementations.
bind(new TypeLiteral<GenericDAO<String, ObjectID>>(){}).to(StringDAO.class);
bind(new TypeLiteral<GenericDAO<Double, ObjectID>>(){}).to(IntegerDAO.class);
Based on different type of inputs you can do this
Injector injector = Guice.createInjector(new RunnerModule());
// possible input which you get from *somewhere* dynamically
Object object = 1.0;
TypeLiteral<?> matchedTypeLiteral = null;
for (Key<?> key : injector.getAllBindings().keySet()) {
TypeLiteral<?> typeLiteral = key.getTypeLiteral();
Type type = typeLiteral.getType();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() == GenericDAO.class) {
List<Type> actualTypeArguments = Arrays.asList(parameterizedType.getActualTypeArguments());
if (actualTypeArguments.get(0) == object.getClass())
matchedTypeLiteral = typeLiteral;
}
}
};
Runner<?, ?> runner = new Runner<>((GenericDAO<?, ?>) injector.getInstance(Key.get(matchedTypeLiteral)));
System.out.println(runner.dao.getClass()); // IntegerDAO.class
If Object object = "string";, then the other implementation will be found. This is of course rather ugly and can be improved with checking for sub-classes and stuff, but I think you get the idea. The bottom-line is that you can't get around this.
If you manage to do it (getting around it), please drop me an e-mail because I would like to know about it! I had faced the same problem as you're facing not too long ago. I've written a simple BSON codec where I wanted to load specific implementations of a generic interface based on the type of some arbitrary input. This worked well with Java-to-BSON mappings, but I couldn't do it the other way around in any sensible way, so I've opted for a simpler solution.
The way you wrote it, entityClass can only be Object.class (== Class<Object>), and nothing else.
Hence, first of all, your ObjectDAOMongoDBImpl should be generic:
public class ObjectDAOMongoDBImpl<T>
extends GenericDAOMongoDBImpl<T, ObjectId> ...
That part of the problem is related to java, not Guice.
Now for Guice part, you need to define a binding including the generic types, ie by using Guice TypeLiteral:
bind(new TypeLiteral<GenericDAO<T, V>>(){}).to(...);
where T and V must be known in the code above (can't just be generic parameters there).
Looking at this question may also give you further details related to your situation.
This question is a bit old, but I've recently ran into a similar problem, and managed to solve it quite elegantly by adding a tiny extra layer, a factory.
Consider the following repository:
public interface Repository<T extends Model<T>> {
void save(T t);
T load(long key);
}
class SomeDbRepositoryImpl<T extends Model<T>> implements Repository<T> {
private final SomeDbConnection db;
private final Class<T> type;
RepositoryImpl(final Class<T> type, final SomeDbConnection db) {
this.db = db;
this.type = type;
}
...
}
Then, suppose I have a service that needs an instance of Repository<User>. My first try was to try to make Guice pass an instance of Repository<User> in the constructor, and then I'd bind it somehow. The problem is that I really don't want to have to add repository bindings and providers for each model. If I were to do that, the code would look like this:
// Won't work.
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final Repository<User> userRepository) {
this.userRepository = userRepository;
}
...
}
What I ended up doing is creating a RepositoryFactory class, which is not generic by itself, but it contains a generic method.
public interface RepositoryFactory {
<T extends Model<T>> Repository<T> getRepository(Class<T> type);
}
class SomeDbRepositoryFactoryImpl implements RepositoryFactory {
private final SomeDbConnection db;
#Inject SomeDbRepositoryFactoryImpl(final SomeDbConnection db) {
this.db = db;
#Override <T extends Model<T>> Repository<T> getRepository(Class<T> type) {
return new SomeDbRepositoryImpl(type, db);
}
}
So, this is completely type-safe, and I don't have to add a binding for each module. The service that uses a Repository would then look like:
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final RepositoryFactory f) {
this.userRepository = f.getRepository(User.class);
}
...
}
You could also keep the instance of RepositoryFactory instead of already getting the Repository instance.
I hope this can be useful to someone.
Beyond what Kohányi has said, you could load the DAO or entity classes reflectively by name, and then bind only the specific types asked for in the command-line arguments:
package com.example;
public class App
{
public static void main(final String[] args)
{
final Injector appleInjector = Guice.createInjector(new DynamicDaoModule(getClass("com.example.AppleDao")));
appleInjector.getInstance(Runner.class);
final Injector orangeInjector = Guice.createInjector(new DynamicDaoModule( getClass("com.example.OrangeDao")));
orangeInjector.getInstance(Runner.class);
// final Injector commandLineInjector = Guice.createInjector(new DynamicDaoModule(getClass(args[0])));
// commandLineInjector.getInstance(Runner.class);
}
private static Class getClass(final String className)
{
try
{
return Class.forName(className);
}
catch (final ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
}
class DynamicDaoModule extends AbstractModule
{
private final Class<? extends GenericDao<? extends Entity>> daoClass;
public DynamicDaoModule(final Class<? extends GenericDao<? extends Entity>> daoClass)
{
this.daoClass = daoClass;
}
#Override
protected void configure()
{
// bind GenericDao<? extends Entity> to daoClass
final TypeLiteral<GenericDao<? extends Entity>> daoOfEntity = (TypeLiteral) TypeLiteral.get(Types.newParameterizedType(GenericDao.class, Types.subtypeOf(Entity.class)));
bind(daoOfEntity).to(daoClass);
}
}
interface Entity
{
}
class Apple implements Entity
{
}
class Orange implements Entity
{
}
class Runner
{
#Inject
public Runner(final GenericDao<? extends Entity> dao)
{
System.out.println("This runner has an " + dao);
}
}
class GenericDao<T extends Entity>
{
private final Class<? extends Entity> entityClass;
protected GenericDao(final Class<? extends Entity> entityClass)
{
this.entityClass = entityClass;
}
#Override
public String toString()
{
return String.format("%s constructed with entityClass %s", getClass().getSimpleName(), entityClass.getSimpleName());
}
}
class AppleDao extends GenericDao<Apple>
{
#Inject
public AppleDao()
{
super(Apple.class);
}
}
class OrangeDao extends GenericDao<Orange>
{
#Inject
public OrangeDao()
{
super(Orange.class);
}
}
And the output would be
This runner has an AppleDao constructed with entityClass Apple
This runner has an OrangeDao constructed with entityClass Orange
I have changed the example to have entity classes implement an interface, in case they share some functionality that would be useful to Runner or GenericDao. If in fact you don't have such an interface, the technique also works with entity classes like String and Double if you remove the extends Entity upper bounds (e.g. GenericDao<T>).
I also removed the <T> parameter on Runner, as that was providing no benefit due to type erasure. If you were to subclass Runner<T>, then you might have Guice provide AppleRunner extends Runner<Apple> or OrangeRunner extends Runner<Orange>. But the type parameter provides nothing if Runner itself is the only concrete class Guice will be providing.
EDIT Oops, I left the class injections in. They are removed now. Of course, if you have a concrete GenericDao subclass for each entity, then perhaps you don't need to inject the entity classes themselves.
I suppose it's not clear to me whether you can provide concrete GenericDao subclasses for all the entity types ahead of time or not. If not, and you were only using the GenericDao class itself for each different kind of entity class, then you would want to inject concrete entity classes and not concrete DAO classes.

Categories

Resources