I am using Guice and FactoryModuleBuilder. Typically, it is enough to just define an interface of the factory and Guice will automatically inject the implementation.
However, the part that I am struggling is that the methods in a factory uses generics. Suppose I have the following. A base type of constructed instances as defined by the interface.
interface Foo<T> {
T get();
}
And two implementations of the Foo interface as defined by the two classes below.
class FooA<T> implements Foo<T> {
#Inject
FooA(#Assisted Class<T> clazz, #Assisted String s) {...}
}
class FooB<T> implements Foo<T> {
#Inject
FooB(#Assisted Class<T> clazz, #Assisted Integer i) {...}
}
Then I have the factory interface as defined below, using two custom binding annotations that allows me to use multiple implementations.
interface FooFactory {
#A Foo<T> build(Class<T> clazz, String s);
#B Foo<T> build(Class<T> clazz, Integer i);
}
I have tried a number of possible solutions, all but one has worked so far. The solution that worked is to basically write my own implementation of FooFactory as shown below. And in the configure method of the module, bind the interface to the implementation; bind(FooFactory.class).to(FooFactoryImpl.class);
class FooFactoryImpl {
Foo<T> build(Class<T> clazz, String s) {
return new FooA(clazz, s):
}
Foo<T> build(Class<T> clazz, Integer i) {
return new FooB(clazz, i);
}
}
However, I have one issue with this solution. The instances are not created by Guice and thus I lose the null checks that comes with Guice. This is drastically different from my other factories that does not have this problem. This means I have to explicitly write null checks for every implementation of Foo. I would like to avoid that.
The following are some of the solutions I have tried.
Solution 1:
FactoryModuleBuilder fmb = new FactoryModuleBuilder()
.implement(Foo.class, A.class, FooA.class)
.implement(Foo.class, B.class, FooB.class);
install(fmb.build(FooFactory.class));
Solution 2:
FactoryModuleBuilder fmb = new FactoryModuleBuilder()
.implement(TypeLiteral.get(Foo.class), A.class, TypeLiteral.get(FooA.class))
.implement(TypeLiteral.get(Foo.class), B.class, TypeLiteral.get(FooB.class));
install(fmb.build(TypeLiteral.get(FooFactory.class)));
The sample code is available at GitHub (if anyone is interested).
To my knowledge, you can't design AssistedInject factories to work in this way. However, it seems to me you're doing too much in one class. Because you have no restrictions on Class<T>, it's clear you aren't using any methods of this class in the constructor, which means, it should be fairly easy to refactor the behavior into a separate class. I know this is a little bit of boilerplate, it's not exactly what you want, but it might look something like this:
interface FooDataFactory {
#A FooData build(String s);
#B FooData build(Integer i);
}
public class FooA<T> implements Foo<T> {
public FooA(FooData data) {
// You should know what class you need when you're actually calling the constructor.
// This way you don't even need to pass around Class<T> instances
}
}
If this approach doesn't work for your use case, let me know and I'll edit to compensate.
Related
I need help with Java Generics.
My model is: I have some classes that extends a Dto (Data Transfer Object) and some classes that extends Entity (The model of my object to DB).
I have
interface Mapper<D extends Dto, E extends Entity>{
//Convert a Entity to Dto.
D toDto(E entity);
And I have some classes that implements this interface (i.e PersonMapper, BookMapper and so far and so on).
#Component
public class PersonMapper implements Mapper<PersonDto, PersonEntity> {
//implementation
}
#Component
public class BookMapper implements Mapper<BookDto, BookEntity> {
//implementation
}
What I want to do is to use Factory Pattern in order to select at runtime my Mapper, that depends from a String that I pass in input.
#Autowired
private PersonMapper personMapper;
#Autowired
private BookMapper bookMapper;
public <D extends Dto, E extends Entity> Mapper<D, E> selectMapper(String entity){
if ("Person".equalsIgnoreCase(entity))
return personMapper;
if("Book".equalsIgnoreCase(entity))
return bookMapper;
...
}
With this situation I have the following compile error:
Type mismatch: cannot convert from PersonMapper to Mapper<D,E>
My solutions:
1)
return (Mapper<D, E>) personMapper;
but I have a Warning:
Type Safety: `Unchecked class from personMapper to Mapper<D,H>`
2)
Using WildCard and castingb
public Mapper<Dto, Entity> selectMapper(String entity){
Mapper<? extends Dto, ? extends Entity> toReturn = null;
if ("Person".equalsIgnoreCase(entity))
toReturn = personMapper;
else if("Book".equalsIgnoreCase(entity))
toReturn = bookMapper;
...
return (Mapper<Dto, Entity>) toReturn;
}
But in this case but I have another time a Warning:
Type safety: Unchecked cast from Mapper<capture#29-of ? extends Dto,capture#30-of ? extends Entity> to Mapper<Dto,Entity>
It works but it doesn't seems to be a clean solution
3) Using wildcard as return type:
public Mapper<? extends Dto, ? extends HistoryEntity> selectMapper(String entity)
but you know, using wildcard as return type is not recommended at all and also doesn't help me because I would like to use this mapper and call mapper.toDto ensuring that the return type is an something that extends Dto.
====================================================================
I don't explain why If I write a class constructor like that
public Service<D extends Dto, E extends Entity>{
public Service(Mapper<D,E> mapper){
this.mapper = mapper;
}
}
and than I inject (for example) bookMapper it works.
If, instead, the Mapper<D,E> is in return type I cannot do such a kind of operation.
====================================================================
The help that I ask to you is:
how can I write a solution using clean code principles (avoiding compile warnings, sonarlint issue etc.) in order to implement this kind of logic?
Thank you very much, I appreciate a lot if you dedicate a little bit of your time helping me to solve my problem.
Those vars (D and E) about the caller and not about your code. The D and E are decided by the caller, so there is absolutely no way to guarantee that PersonDTO fits.
Make that Mapper<? extends DTO, ? extends Entity> (and no variables), and given that those are already the lower bounds, just Mapper<?, ?> - that'll work, you can write your return statements without any casts and without compiler errors or warnings.
Of course, it means the caller has a mostly useless type.
Generics are entirely 'compile time / write time' based. The JVM (java.exe) has no idea what generics are, and in fact most of them don't survive the compilation process. The one and only purpose of generics is to make the compiler flag incorrect code and avoid some casting, that is all.
The nature of turning that string into a Mapper is entirely runtime.
Ergo, if Mapper<?, ?> isn't sufficient, what you want isn't possible. You'd need to write compile/write-time checkable stuff, so the moment you use a String, it's impossible. For example, a method getPersonMapper() can of course return a Mapper<PersonDTO, PersonEntity>, no problem.
More generally (heh) it sounds like you're badly reinventing various wheels here. Look at tutorials of JDBI, JOOQ, and Hibernate to get some ideas about how java code is commonly written to interact with databases.
Factory Pattern is pattern that assemble or create something by factory methods, in you case what you need is just to get corresponding mapper by name, so there is a simple way to do that since the mapper beans are autowired, adding String getName() to Mapper interface then implements it for earch implementation, e.g. in BookMapper
#Override
public String getName() { return "Book"; }
use mapper name as key and mapper bean as value to store mapper beans in a map, then you can retrieve it by its name:
#Service
public class SimpleService {
private BookMapper bookMapper;
private PersonMapper personMapper;
private Map<String, Mapper<? extends DTO, ? extends Entity>> mappers = new HashMap<>();
public SimpleService(BookMapper bookMapper, PersonMapper personMapper) {
this.bookMapper = bookMapper;
this.personMapper = personMapper;
mappers.put(bookMapper.getName(), bookMapper);
mappers.put(personMapper.getName(), personMapper);
}
public Mapper<? extends DTO, ? extends Entity> getMapperByName(String mapperName) {
return mappers.get(mapperName);
}
}
and you can cast it to corresponding mapper without warning.
PersonMapper p = (PersonMapper) simpleService.getMapperByName("Person");
or you can put different mapper in their service and use the service to handle you biz likes codes below, after all, you need specified mappers to do specified operations:
if(personThings){
personService.doSomeThing();
}
if(bookThings){
bookService.doSomething();
}
I'm writing a custom Java annotation for processing CrudRepositories with Reflection in Java Spring. With the org.reflections.reflections library. I'm getting all interfaces annotated with my annotation as a class file like so:
Reflections reflections = new Reflections("basePackage");
Set<Class<?>> annotated = reflections.getTypesAnnotatedWith(MyAnnotation.class);
Only interfaces, which at some point extend JpaRepository are annotated with my #MyAnnotation at the class level.
My repository structure is as follows:
There are two cases,
first case:
public interface SomeRepo extends JpaRepository<SomeEntity, Long> {...}
the second case is composed out of a inheritance hierarchy:
public interface SuperClassRepo <T extends SomeRandomEntity> extends JpaRepository<T, String> {...}
public interface SubClassRepo extends SuperClassRepo<SubEntityOfSomeRandomEntity> {...}
My goal is now to extract the generic type parameters of the underlying JpaRepository.
I achieved to do that if the annotated class is a Java class, not an interface. How can I achieve the same for an interface? I guess I'm also having trouble because of the inheritance. I guess I have to get the "super class" until I reach the JpaRepository and then somewhat extract the generic type arguments.
Help is very much appreciated, thanks in advance
I found a solution by looking at the GenericsUtils#getParameterType as suggested:
private static Class<?> extractKeyFromRepository(Class<?> repository) {
ResolvableType currentType = ResolvableType.forType(repository);
ResolvableType resolvableType = currentType.getInterfaces()[0];
if (JpaRepository.class.equals(resolvableType.getRawClass())) {
ResolvableType[] generics = resolvableType.getGenerics();
ResolvableType generic = generics[1];
return generic.resolve();
} else {
return extractKeyFromRepository(resolvableType.toClass());
}
}
This works only because I ensure beforehand, that what I'm putting in this method is valid. I do it like so, also I pay attention that only one interface is extended, by extending more than one interface one has to figure out which of these interfaces is the JpaRepository:
if (!repository.isInterface()) {throw new IllegalArgumentException();}
if (!JpaRepository.class.isAssignableFrom(repository)) {throw new IllegalArgumentException();}
I have the following classes:
public interface IDataSource<T> {
public List<T> getData(int numberOfEntries);
}
public class MyDataSource implements IDataSource<MyData> {
public List<MyData> getData(int numberOfEntries) {
...
}
}
public class MyOtherDataSource implements IDataSource<MyOtherData> {
public List<MyOtherData> getData(int numberOfEntries) {
...
}
}
I would like to use a factory that return the correct implementation based on the data type. I wrote the following but I get "Unchecked cast" warnings:
public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
if (dataType.equals(MyData.class)) {
return (IDataSource<T>) new MyDataSource();
} else if (dataType.equals(MyOtherData.class)) {
return (IDataSource<T>) new MyOtherDataSource();
}
return null;
}
Am I doing it wrong? What can I do to get rid of the warnings?
I am not aware of any way to get rid of those warnings without #SuppressWarnings("unchecked").
You are passing in a Class object so T can be captured. But you are forced to check the Class at runtime to determine which IDataSource<T> to return. At this time, type erasure has long since occurred.
At compile time, Java can't be sure of type safety. It can't guarantee that the T in the Class at runtime would be the same T in the IDataSource<T> returned, so it produces the warning.
This looks like one of those times when you're forced to annotate the method with #SuppressWarnings("unchecked") to remove the warning. That warning is there for a reason, so it is up to you to provide and ensure type safety. As written, it looks like you have provided type safety.
#SuppressWarnings("unchecked")
public static <T> IDataSource<T> getDataSource(Class<T> dataType) {
You're doing it right, and you should simply suppress the warnings. Factories are one of the tricky areas in generics where you really do need to manually cast to a generic type, and you have to ensure via whatever means that the returned value matches the Class<T> you pass in. For example, in this case you're hard-coding a couple of IDataSource implementations, so I would recommend writing unit tests that verify that the types are correct so that if the MyData implementation changes in an incompatible way, you'll get an error on build.
Just annotate the getDataSource method with #SuppressWarnings("unchecked"), and it's always a good idea to add an explanatory comment when suppressing warnings.
Generics are for compile-time type safety. They can't be used for runtime type determination like that. To get rid of the warning, you can do something like #SuppressWarnings("unchecked") or use the -Xlint:-unchecked compiler flag, as described in the "Raw Types" part of the Java tutorial.
The other answers have answered the problem as you posed it. But I'd like to take a step back to understand what you're trying to accomplish with this factory method. This factory basically provides a map of data types to IDataSource parameters. Dependency injection might be a more appropriate pattern since this is a small well-known set of data types and implementations (as indicated by your example).
Let's say you want to store all Widgets in Mongo but all Gadgets in Mysql, you might have two classes: a MongoWidgetDataSource that implements IDataSource<Widget> and a MysqlGadgetDataSource that implements IDataSource<Gadget>.
Instead of hardcoding a factory method call like MyFactory.getDataSource(Widget.class) inside a data consumer, I would inject the appropriate IDataSource dependency. We might have MyService that does something with widgets (stored in mongo). Using a factory as you proposed would look like this:
public class MyService {
public void doSomething() {
String value = MyFactory.getDataSource(Widget.class).getSomething();
// do something with data returned from the source
}
}
Instead, you should inject the appropriate data source as a constructor arg into the service:
public class MyService {
private final IDataSource<Widget> widgetDataSource;
public MyService(IDataSource<Widget> widgetDataSource) {
this.widgetDataSource = widgetDataSource;
}
public void doSomething() {
String value = widgetDataSource.getSomething();
// now do something with data returned from the source
}
}
This has the added benefit of making your code more reusable and easier to unit test (mock dependencies).
Then, where you instantiate MyService, you can also wire up your data sources. Many projects use a dependency injection framework (like Guice) to make this easier, but its not a strict requirement. Personally, though, I never work on a project of any real size or duration without one.
If you don't use an DI framework, you just instantiate the dependencies when you create the calling service:
public static void main(String[] args) {
IDataSource<Widget> widgetDataSource = new MongoWidgetDataSource();
IDataSource<Gadget> gadgetDataSource = new MysqlGadgetDataSource();
MyService service = new MyService(widgetDataSource, gadgetDataSource);
service.doSomething();
}
In Guice, you would wire up these data sources like this:
public class DataSourceModule extends AbstractModule {
#Override
protected void configure() {
bind(new TypeLiteral<IDataSource<Widget>>() {}).to(MongoWidgetDataSource.class);
bind(new TypeLiteral<IDataSource<Gadget>>() {}).to(MysqlGadgetDataSource.class);
}
}
Dependency inversion is a bit of a different way to think about the problem, but it can lead to a much more decoupled, reusable and testable code base.
This seems to work:
public static <T> IDataSource<T> getDataSource(MyData dataType) {
System.out.println("Make MyDataSource");
return (IDataSource<T>) new MyDataSource();
}
public static <T> IDataSource<T> getDataSource(MyOtherData dataType) {
System.out.println("Make MyOtherDataSource");
return (IDataSource<T>) new MyOtherDataSource();
}
public void test() {
IDataSource<MyData> myDataSource = getDataSource((MyData) null);
IDataSource<MyOtherData> myOtherDataSource = getDataSource((MyOtherData) null);
}
You may prefer to create empty archetypes rather than cast null like I have but I think this is a viable technique.
I have the following factory class:
public class MessagePresenterCreator implements IPresenterFactory{
#Override
public MessagePresenter createPresenter(Message m) {
if (m instanceof Letter) {
return new LetterPresenter();
}
if (m instanceof Cable) {
return new CablePresenter();
}
if (m instanceof Postcard) {
return new PostcardPresenter();
}
throw new IllegalArgumentException();
}
}
Can I configure a guice to auto-generate and supply such factory by the following interface:
public interface IPresenterFactory {
public abstract MessagePresenter createPresenter(Message m);
}
I like to think of factories in two ways - factories that merely assemble objects from components, and factories that do conditional logic in that assembly.
Your factories have logic behind them. Guice can't automate that logic, because it simply handles the wiring up of dependencies. If you have a type that is created that needs some amount of injected dependencies and some things that are provided just at creation time, then the auto-wiring of factories can be done with guice's AssistedInject extension. This would let you give a factory interface, annotate any fields in the created type with #AssistedInject, and guice's extension would create a factory implementation class which would inject anything bound in the Injector, and also pass through those create() parameters. But in such a case, all Guice and AssistedInject are doing is pulling pieces together - wiring things up according to a recipe specified in advance. It's not making decisions about them at the last minute.
You're providing conditional creation of objects. That's not going to work.
An idea above mentions making a factory that depends on mapping of type to presenter - something like:
Map<Class<? extends Message>, Class<? extends MessagePresenter>>
This is a good approach, if you combine it with Multibinder's MapBindings. (I gotta beef up those docs... hmm)
With this approach you can create an extensible factory - defining the initial mappings of Message -> MessagePresenter subclasses, but leave the possibility open for additional mappings later without having to change your factory - just bind more mappings on the multibinder, like so:
MapBinder<String, Snack> mapbinder = MapBinder.newMapBinder(
binder(),
new TypeLiteral<Class<? extends Message>>(){},
new TypeLiteral<Class<? extends MessagePresenter>>(){});
mapbinder.addBinding(MyMessage.class).toInstance(MyMessagePresenter.class);
mapbinder.addBinding(YourMessage.class).toInstance(YourMessagePresenter.class);
And you can do this in as many modules as you like, adding more types between which to switch, using the mapping.
No guice does not have a factory like that built in. You could write a factory that took a Map<Class<? extends Message>, Class<? extends MessagePresenter> and have that use reflection. That way you can manage it in a guice module if that is your goal.
public class MessagePresenterCreator implements IPresenterFactory{
private final Map<Class<? extends Message>, Class<? extends MessagePresenter> mapping;
public MessagePresenterCreator(Map<Class<? extends Message>, Class<? extends MessagePresenter> mapping) {
this.mapping = mapping;
}
#Override
public MessagePresenter createPresenter(Message m) {
Class<? extends MessagePresenter> clazz = mapping.get(m);
if (clazz == null) {
throw new UnsupportedOperationException();
}
return clazz.newInstance();
}
}
Using the generic dao pattern, I define the generic interface:
public interface GenericDao<T extends DataObject, ID extends Serializable> {
T save(T t);
void delete(ID id);
T findById(ID id);
Class<T> getPersistentClass();
}
I then implemented an default GenericDaoImpl implementation to perform these functions with the following constructor:
public GenericDaoImpl(Class<T> clazz) {
this.persistentClass = clazz;
DaoRegistry.getInstance().register(clazz, this);
}
The point of the DaoRegistry is to look up a Dao by the class associating to it. This allows me to extend GenericDaoImpl and overwrite methods for objects that requires special handling:
DaoRegistry.getInstance().getDao(someClass.getClass()).save(someClass);
While it works, there are a few things that I don't like about it:
DaoRegistry is an singleton
The logic of calling save is complicated
Is there a better way to do this?
Edit
I am not looking to debate whether Singleton is an anti-pattern or not.
First of all, what is your problem with DaoRegistry being singleton?
Anyway, you could have an abstract base class for your entities that'd implement save like this
public T save(){
DaoRegistry.getInstance().getDao(this.getClass()).save(this);
}
then you could simply call someEntity.save()
Or it may be more straightforward if the entity classes itself implemented the whole GenericDao interface (save, delete and find methods), so the contents of your GenericDaoImpl would be in the base class of your entities.
It could be better to use instance of DaoRegistry instead of static methods. It would make it more manageable for test configurations. You could implement it as
#Component("daoRegistry")
public class DaoRegistry {
#Autowired
private List<GenericDao> customDaos;
private GenericDao defaultDao = new GenericDaoImpl();
public <T> T getDao(Class<T> clazz) {
// search customDaos for matching clazz, return default dao otherwise
}
}
Also you could add save method to it and rename accordingly. All customised daos should be available as beans.