#2239 matching generics - #2320
Conversation
filiphr
left a comment
There was a problem hiding this comment.
Really great job @sjaakd.
I've left some comments (mostly to clarify that I've understood some parts correctly 😄).
I think that the approach in the TypeVarMatcher is quite clear and quite extensive now.
The MethodMatcher was a bit more complex to follow, but I think I got the gist of it.
Regarding the failing test. I think that the test should pass. What I am having troubles to see is which change is causing this test to fail? When looking up the lifecycle methods we are passing the correct type I presume (the Order.Builder).
|
Thans for the review @filiphr . I'll get back on that later this week. |
My initial idea was: Look at L67 in I need to match the The method I need to match is It contains both:
How can I match and the returntype and the But, I'll take some distance and see if I miss something.. (Probably 😄 ) I'll get back on this one. The remainder of your comments have been processed. |
|
I did some further analysis..
There's no magic here. What it receives is, in this case:
It tries to match this with:
So, if we want to succeed, the What I did to make it more easy, remove all other stuff: @Mapper
public interface OrderMapper {
OrderMapper INSTANCE = Mappers.getMapper( OrderMapper.class );
@Mapping( target = "items", ignore = true )
Order map(OrderDto source, @Context MappingContext context);
// Item map(ItemDto source, @Context MappingContext context);
}public class MappingContext {
private final List<String> invokedMethods = new ArrayList<String>();
//
// @BeforeMapping
// public void beforeWithoutParameters() {
// invokedMethods.add( "beforeWithoutParameters" );
// }
//
// @BeforeMapping
// public void beforeWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
// invokedMethods.add( "beforeWithTargetType" );
// }
//
// @BeforeMapping
// public void beforeWithBuilderTargetType(OrderDto source, @TargetType Class<Order.Builder> builderClass) {
// invokedMethods.add( "beforeWithBuilderTargetType" );
// }
//
// @BeforeMapping
// public void beforeWithTarget(OrderDto source, @MappingTarget Order order) {
// invokedMethods.add( "beforeWithTarget" );
// }
//
// @BeforeMapping
// public void beforeWithBuilderTarget(OrderDto source, @MappingTarget Order.Builder orderBuilder) {
// invokedMethods.add( "beforeWithBuilderTarget" );
// }
//
// @AfterMapping
// public void afterWithoutParameters() {
// invokedMethods.add( "afterWithoutParameters" );
// }
//
// @AfterMapping
// public void afterWithTargetType(OrderDto source, @TargetType Class<Order> orderClass) {
// invokedMethods.add( "afterWithTargetType" );
// }
//
// @AfterMapping
// public void afterWithBuilderTargetType(OrderDto source, @TargetType Class<Order.Builder> builderClass) {
// invokedMethods.add( "afterWithBuilderTargetType" );
// }
//
// @AfterMapping
// public void afterWithTarget(OrderDto source, @MappingTarget Order order) {
// invokedMethods.add( "afterWithTarget" );
// }
//
// @AfterMapping
// public void afterWithBuilderTarget(OrderDto source, @MappingTarget Order.Builder orderBuilder) {
// invokedMethods.add( "afterWithBuilderTarget" );
// }
@AfterMapping
public Order afterWithBuilderTargetReturningTarget(@MappingTarget Order.Builder orderBuilder) {
invokedMethods.add( "afterWithBuilderTargetReturningTarget" );
return orderBuilder.create();
}
public List<String> getInvokedMethods() {
return invokedMethods;
}
}Put a debug statement on the And just inspect, targetType, sourceTypes You can step back in the stack to see what happens. |
|
OK I see it now. Currently the If you replace the I think that what you are doing is correct there. However, we need to provide this information when we are gathering the |
Yup.. But test: ExternalSelectionTest#shouldSelectGeneratedExternalMapperWithImportForPropertyType then fails.. |
That's interesting. I see |
|
Let's take one step back to the generated code: `public class OrderMapperImpl implements OrderMapper {
@Override
public Order map(OrderDto source, MappingContext context) {
if ( source == null ) {
return null;
}
Builder order = Order.builder();
Order target = context.afterWithBuilderTargetReturningTarget( order );
if ( target != null ) {
return target;
}
return order.create();
}
}What is actually the reason that we distinguish here? Why is the return type unequal to the result type ( So why couldn't we do the: if (target != null ) {
return target.create();
}Like said.. generating a context might be the reason.. |
That's a reminiscence of an older version of the solution.. It can be removed.. I'll do so. |
|
@filiphr I've provided a fix.. pursue a solution on different spots than the lifecycle methods.. But that could be done in new PRs with additional testcases. For the time being this goes far enough.. Have a look if you agree with the approach. |
|
Really good job with the tests in this one @sjaakd, really thorough 😄 |
Thanks. 😄 I'll still add some testcases in the future probably to add some more realistic scenarios I found when implementing this. Just to make sure they work as well. But first lets get the bulk out. I answered some comments I missed in earlier review. Have a look if you agree. If you agree, I'll do the merge. |
From your 3 comments, I agree with one and resolve it. There are 2 more left.
Once this is done, check https #2377, I think that it is solved by this PR, but it would be good to add that test case as well. |
TODO:
Anyway.. what is bothering me is the failing test case:
BuilderLifecycleCallbacksTest.lifecycleMethodsShouldBeInvoked.It misses one
aftermethod call. Particularly it wants a method:But, the method matcher is working as expected. Hence its either looking for a method:
Or
After all, it can match only one target type. In the desired case, it should match 2 (which is not possible). Which makes me think: is this behavior wrong?
@filiphr :
TypesandElementshave to offer instead of doing it ourselves.