Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate additional delegating mappers for @InheritInverseConfiguration #88

Closed
pw-lehre opened this issue Aug 14, 2023 · 5 comments · Fixed by #94
Closed

Generate additional delegating mappers for @InheritInverseConfiguration #88

pw-lehre opened this issue Aug 14, 2023 · 5 comments · Fixed by #94

Comments

@pw-lehre
Copy link

Hi everyone,

I'd like to define multiple Spring Converter<S, T> implementations (with different generic parameters) in a single @Mapper annotated interface. However, due to type erasure, it is currently not possible to directly declare the same interface multiple times.

Would it be possible to generate additional implementation classes that delegate back to the additional Mapping methods? Currently, we need to manually define a delegate mapper.

Current approach:

@Mapper
public interface MyMapper extends Converter<BarTo, FooTo> {

    @Override
    @Mapping(source = "attribA", target = "attribB")
    FooTo convert(BarTo source);


    @InheritInverseConfiguration
    BarTo convertInverse(FooTo source);


     // Manual delegating mapper required
    @Mapper
    abstract class MyMapperDelegate implements Converter<FooTo, BarTo> {

        @Autowired
        private MyMapper mapper;

        @Override
        public BarTo convert(FooTo source) {
            return this.mapper.convertInverse(source);
        }

    }

    // Generated Mapper Impl
   @Component
   public class MyMapper$MyMapperDelegateImpl extends MyMapperDelegate {}

}

It would be nice if additional Implementation classes could be generated with a simple annotation such as e.g. @GenerateDelegate.

Idea for a future approach:

@Mapper
public interface MyMapper extends Converter<BarTo, FooTo> {

    @Override
    @Mapping(source = "attribA", target = "attribB")
    FooTo convert(BarTo source);

    // Any SAM interface with matching structure
    @GenerateDelegate(class = org.springframework.core.convert.converter.Converter.class)
    @InheritInverseConfiguration
    BarTo convertInverse(FooTo source);


     // Generated Mapper Impl
    @Component
    public class MyMapperDelegateImpl implements Converter<FooTo, BarTo> {
      
        @Autowired
        private MyMapper mapper;

        @Override
        public BarTo convert(FooTo source) {
            return this.mapper.convertInverse(source);
        }
    }
}

I'm asking this here since it would be especially useful together with the Spring Converter Interface, and would potentially also require an entry in the ConversionServiceAdapter.

@Chessray
Copy link
Collaborator

I like the idea. If I'm not mistaken, we wouldn't even need a special annotation. Any method with @InheritInverseConfiguration that matches the type parameters as inverting the Converter declaration can already lead to generating this new Inverted Mapper class.

@pw-lehre
Copy link
Author

If it works automatically without further configuration, that would be even better.

As a stopgap solution, I'm currently using Spring magic to register @InheritInverseConfiguration-annotated methods in the Spring converter registry. But those methods aren't in the ConversionServiceAdapter, i.e. other Mappers cannot discover and use the inverse mappers. In short, solving this properly in maptruct would help here.

@Chessray
Copy link
Collaborator

Chessray commented Aug 21, 2023

Outline:

  • Any method annotated with @InheritInverseConfiguration whose signature is the exact opposite of the Converter type declaration will lead to the generation of an InvertedMapper class outlined above.
  • In order to keep the pattern, the generated adapter class should contain a matching method.
  • For backward compatibility, this behavior requires some explicit flag or new annotation to be set.

@Chessray Chessray changed the title Generate additional delegating mappers to fulfill SPIs Generate additional delegating mappers for @InheritInverseConfiguration Aug 29, 2023
@Chessray
Copy link
Collaborator

Chessray commented Sep 21, 2023

@pw-lehre I've done an implementation in this branch. While I'm still polishing some of the edges (including documentation), please feel free to have a go at it and check whether this looks like what you've got in mind.

In the end, I went for requiring an additional annotation @DelegatingConverter which will generate a full class similar to your example. This new annotation can even be used without @InheritInverseConfiguration, although I can't see a use case for that.

@pw-lehre
Copy link
Author

@Chessray Thanks a lot for the implementation, I did not expect that so many changes would be required for this. I'll try it out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants