The Wayback Machine - https://web.archive.org/web/20200901162458/https://github.com/mapstruct/mapstruct/issues/1427
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

@Mapper(componentModel = "spring") doesn't support custom name for Spring Service Annotation #1427

Open
zurbergram opened this issue Apr 13, 2018 · 4 comments

Comments

@zurbergram
Copy link

@zurbergram zurbergram commented Apr 13, 2018

Can't specify a name for the Spring Service annotation
If the interface definition something like

@Mapper(componentModel = "spring", componentModelName = "cakeMapperV2")
 public interface CakeMapper{
     Cake map(Cupcake cupcake);
 }

 @Service("cakeMapperV2")
 public class CakeMapperImpl {
 }
@filiphr filiphr added the enhancement label Apr 14, 2018
@filiphr filiphr added this to the Future planning milestone Apr 14, 2018
@filiphr
Copy link
Member

@filiphr filiphr commented Apr 14, 2018

@zurbergram yes this is not possible in the moment out of the box.

However, there is a way for you to achieve what you are looking for with some internal customizations. We have an internal SPI ModelElementProcessor that adds the spring @Component annotation. The one for Spring is the SpringComponentProcessor.

What you can do is to define your own ModelElementProcessor that would be of a custom component model, provide your own marker annotation for the name of the component and you would be able to do what you are looking for.

Just keep in mind that this is an internal SPI, which means that we cannot guarantee backwards compatibility between versions. However, it is rarely changed.

chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 18, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
@chris922
Copy link
Member

@chris922 chris922 commented Apr 18, 2018

Oups, sorry! I wasn't aware about the fact that changes in my forked mapstruct repo will directly be linked to this issue. Hopefully I haven't spammed you with too much notification mails.

@filiphr as my changes are now linked here maybe you could already take a look or should I create a PR? (this is my more or less first 'real' OS contribution; right now I am waiting that the built finishs locally including all tests)

I tried to add the possibility to have an extra annotation (@MapperSpringConfig / @MapperJsr330Config) to be able to have more component model specific configurations, e. g. if @Service or @Component should be used and - as requested in this ticket - to define an own bean name.

Maybe its better to extend the @Mapper configuration with a new property like componentName, but my idea was that there are maybe also other configuration things that only belongs to a special componentModel and having a special annotation for this could be helpful for those usecases.

@filiphr filiphr modified the milestones: Future planning, 1.3.x Apr 21, 2018
chris922 added a commit to chris922/mapstruct that referenced this issue Apr 24, 2018
…mponent models

Added two new annotations that allows to configure the component
models, e. g. the bean name
* MapperSpringConfig
* MapperJsr330Config
@filiphr filiphr modified the milestones: 1.3.0.Beta2, 1.3.0.x Oct 11, 2018
@filiphr filiphr modified the milestones: 1.3.0.x, 2.0 Dec 22, 2018
@i-telligence-af
Copy link

@i-telligence-af i-telligence-af commented Nov 21, 2019

@zurbergram yes this is not possible in the moment out of the box.

However, there is a way for you to achieve what you are looking for with some internal customizations. We have an internal SPI ModelElementProcessor that adds the spring @Component annotation. The one for Spring is the SpringComponentProcessor.

What you can do is to define your own ModelElementProcessor that would be of a custom component model, provide your own marker annotation for the name of the component and you would be able to do what you are looking for.

Just keep in mind that this is an internal SPI, which means that we cannot guarantee backwards compatibility between versions. However, it is rarely changed.

I've tried your suggestion, but the Processor is not picked up by org.mapstruct.ap.MappingProcessor in method getProcessors() (v1.3.1.Final):

/**
     * Retrieves all model element processors, ordered by their priority value
     * (with the method retrieval processor having the lowest priority value (1)
     * and the code generation processor the highest priority value.
     *
     * @return A list with all model element processors.
     */
    private Iterable<ModelElementProcessor<?, ?>> getProcessors() {
        // TODO Re-consider which class loader to use in case processors are
        // loaded from other modules, too
        @SuppressWarnings("rawtypes")
        Iterator<ModelElementProcessor> processorIterator = ServiceLoader.load(
            ModelElementProcessor.class,
            MappingProcessor.class.getClassLoader()
        )
            .iterator();
        List<ModelElementProcessor<?, ?>> processors = new ArrayList<>();

        while ( processorIterator.hasNext() ) {
            processors.add( processorIterator.next() );
        }

        Collections.sort( processors, new ProcessorComparator() );

        return processors;
    }

I assume it's because my ModelElementProcessor is not in the same classloader as MappingProcessor. Am I doing something wrong?

@filiphr
Copy link
Member

@filiphr filiphr commented Mar 15, 2020

Just to share some info about how this can be done with some custom Spring @ComponentScan.

Let's say that we have the following:

package com.example.mapper.v1;

@Mapper
public interface CakeMapper {
}

package com.example.mapper.v2;

@Mapper
public interface CakeMapper {
}

Then your configuration can look like the following:

package com.example.mapper;

@Configuration
public class MapperConfig {

    @Configuration
    @ComponentScan(basePackages = "com.example.mapper.v1", nameGenerator = V1NameGenerator.class)
    public static class V1MapperConfig {
    
    }

    @Configuration
    @ComponentScan(basePackages = "com.example.mapper.v2", nameGenerator = V2NameGenerator.class)
    public static class V2MapperConfig {
    
    }

    protected static class V1NameGenerator extends PackageVersionNameGenerator {
        protected V1NameGenerator() {
            super("V1");
        }
    }

    protected static class V2NameGenerator extends PackageVersionNameGenerator {
        protected V2NameGenerator() {
            super("V2");
        }
    }

    protected static class PackageVersionNameGenerator extends AnnotationBeanNameGenerator {

        protected final String suffix;

        protected PackageVersionNameGenerator(String suffix) {
            this.suffix = suffix;
        }
            
        @Override
        protected String buildDefaultBeanName(BeanDefinition definition) {
            return super.buildDefaultBeanName(definition) + suffix;
        }
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
4 participants
You can’t perform that action at this time.