Pass input object to factory
Opened this issue · 4 comments
Hello,
Currently when using a factory, the factory takes no arguments. This brings some problems when you need to create an instance of a type that's bound to a field of the input object.
For example we have a class (say DTO) that holds the "type" attribute and, when mapping it, I'd like to read that attribute and instantiate the correct class (a subclass of the abstract class A).
The factory seems to be not working.
As a (not working) workaround I tryed:
I tryed to use an abstract mapper and:
- defined an abstract "merge" method like:
public abstract A merge(A a, DTO o)
- defined "a factory" method:
public A from(DTO d){
switch(d.type):
...
B b = the_correct_instance_based_on d.type
b = merge(b,d) //<- try to use the merge method
}
with the hope that it would pick up the "merge" method to copy all the fields of the object. The truth is that merge uses my from method and I get infinite recursion :/.
Another workaround that I tryed:
Defined a basemapper with the merge method, then inject that mapper into another mapper that defines the from method and uses the merge from the injected one to fill the object. This method doesn't work because the generated merge object always tries to CREATE a new object if the input is null. To me this is a bit strage because it's not an expected behavior.
Hi,
Thanks for reporting, the issue. For sure giving the input bean to the factory is a specific case.
First, the merge method is not valid as far as I can see. It should be
public abstract A merge(DTO o, A a)
You should always use the expected output bean as the last method parameter.
Instead of using the abstract class A, you should define a merge method for the subclass B so the generated methods will not use your from method.
Now about the second workaround, if you are really declaring parameters in this specific order, the input is considered to be the A bean and not the DTO one.
Adding support for factory methods with the input bean as parameter is possible but I don't think it is needed.
Hello,
Thank you for your reply. Indeed my post was wrong, merge is declared like this:
A merge (DTO,A)
Instead of using the abstract class A, you should define a merge method for the subclass B so the generated methods will not use your from method.
Ok I see that this requires me to create a factory for EACH subclass of A, since the code automatically checks for the create method, right?
I think that a factory that takes the input bean would be nice, it's also done in other "similar" projects like jackson... :)
And what about the fact that merge automatically creates an object if the input is null? Is this really required? I mean, if someone declares a method like that it is because he already has the two objects and wants to copy one into the other, isn't it? Because if you remove this implicit construction into these kind of methods, then the factory is not needed since it gives us the possibility to create the object and then use selma to map the content (similar but simpler than what I did in workaround 2)
Hi,
I'll keep you updated, for the factory with input support.
About the fact :
And what about the fact that merge automatically creates an object if the input is null? Is this really required? I mean, if someone declares a method like that it is because he already has the two objects and wants to copy one into the other, isn't it? Because if you remove this implicit construction into these kind of methods, then the factory is not needed since it gives us the possibility to create the object and then use selma to map the content (similar but simpler than what I did in workaround 2)
This is not the expected behavior of Selma. So this can be a bug, but are you sure that you've got the good parameter order ? In the other cas Selma will consider this to be an aggregation of two beans so will for sure try to create an instance.
I don't have enough code to reproduce this. Maybe you can, provide a pull request with a demonstrating code in selma-processor tests ?