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

Support generic declarations of source and target bean types #583

Open
agudian opened this issue Jun 30, 2015 · 9 comments
Open

Support generic declarations of source and target bean types #583

agudian opened this issue Jun 30, 2015 · 9 comments
Assignees

Comments

@agudian
Copy link
Member

agudian commented Jun 30, 2015

Follow-up to #574.

The following doesn't work, because we currently don't resolve the real property-types against the generic declarations of top-level source or target types.

public class IdHoldingTo<ID> {
    private ID id;
   // getter/setter
}
public class Target {
    private Long id;
    // getter/setter
}

@Mapper
public interface IdMapper {
    Target toTarget(IdHoldingTo<Long> src);

    IdHoldingTo<Long> toHolder(Target target);
}
@samwright
Copy link

I've ran into this problem recently, and I imagine it isn't an easy one to fix as it has been unresolved for a while. As a quick-fix, what about introducing @Mapping#targetType and @Mapping#sourceType to override the field type detection? Example:

@Mapper
public interface IdMapper {
    @Mapping(source = "id", target = "id", sourceType = Long.class)
    Target toTarget(IdHoldingTo<Long> src);

    @Mapping(source = "id", target = "id", targetType = Long.class)
    IdHoldingTo<Long> toHolder(Target target);
}

It requires extra parameters and isn't ideal, but if detecting the generic field types is tricky then it might be a quick win. WDYT?

@agudian
Copy link
Member Author

agudian commented Oct 21, 2015

The type detection is one thing - but once "we" get #644 fixed, it should be almost no problem anymore... @sjaakd is working hard on the fix, and it's probably the most important bugfix that needs to be done for the upcoming Final. So we need some solution there anyway, for many usecases.

The other thing that could turn out tricky is to check where in our code templates the generics-declaration might be missing... :)

So I'd say let's wait out the fix for #644 and then we can revisit this issue - it shouldn't be too hard to do then anymore.

@ghost
Copy link

ghost commented Jan 11, 2017

Have this problem as well. I added generics to my BaseEntity class as some entity ids were of different types, such as String:

public interface BaseEntity<T> {
    T getId();
}

...results in this error message when running the bootRun task:

/Users/arminnaderi/IdeaProjects/chronpwn/chronpwn-forum/src/main/java/com/chronpwn/forum/domain/mapstruct/ThreadMapper.java:8: error: Can't map property "com.chronpwn.common.domain.User author" to "com.chronpwn.forum.domain.mapstruct.Reference author". Consider to declare/implement a mapping method: "com.chronpwn.forum.domain.mapstruct.Reference map(com.chronpwn.common.domain.User value)".
    ThreadForm threadToThreadForm(Thread thread);
               ^
/Users/arminnaderi/IdeaProjects/chronpwn/chronpwn-forum/src/main/java/com/chronpwn/forum/domain/mapstruct/ThreadMapper.java:9: error: Can't map property "com.chronpwn.forum.domain.mapstruct.Reference forum" to "com.chronpwn.forum.domain.Forum forum". Consider to declare/implement a mapping method: "com.chronpwn.forum.domain.Forum map(com.chronpwn.forum.domain.mapstruct.Reference value)".
    Thread threadFormToThread(ThreadForm threadForm);

Not possible to declare a map() method as the EntityManager can't be injected into the ThreadMapper interface.

@ghost
Copy link

ghost commented Jan 11, 2017

I also updated the ReferenceMapper class specified within the documentation to handle the generics:

@Component
@ApplicationScope
public class ReferenceMapper {

    @PersistenceContext
    private EntityManager entityManager;

    public <I, T extends BaseEntity<I>> T resolve(Reference reference, @TargetType Class<T> entityClass) {
        return reference != null ? entityManager.find( entityClass, reference.getId() ) : null;
    }

    public <I> Reference<I> toReference(BaseEntity<I> entity) {
        return entity != null ? new Reference<>( entity.getId() ) : null;
    }
}

@agudian agudian self-assigned this Jan 11, 2017
@agudian agudian added this to the 1.2.x milestone Jan 11, 2017
@agudian
Copy link
Member Author

agudian commented Jan 11, 2017

Oh, that seems to have fallen off the radar. I'd like to give it another look in the next weeks.

@ghost
Copy link

ghost commented Jan 11, 2017

Actually, my problem is not the same as mentioned above. I read issue #79, and it seems to already be supported. Sorry about that.

This is the ReferenceMapper implementation that solved my problem:

@Component
@ApplicationScope
public class ReferenceMapper {

    @PersistenceContext
    private EntityManager entityManager;

    public <I extends Serializable, T extends BaseEntity<I>> T resolve(Reference<I> reference, @TargetType Class<T> entityClass) {
        return reference != null ? entityManager.find( entityClass, reference.getId() ) : null;
    }

    public <I extends Serializable, T extends BaseEntity<I>> Reference<I> toReference(T entity) {
        return entity != null ? new Reference<>( entity.getId() ) : null;
    }
}

@gunnarmorling gunnarmorling modified the milestones: 1.2.1, 1.2.0.Final Aug 15, 2017
@filiphr filiphr modified the milestones: 1.2.1, 1.3.x Jul 12, 2018
@filiphr filiphr modified the milestones: 1.3.0.Beta2, Future planning Oct 11, 2018
@itayEss
Copy link

itayEss commented Jun 24, 2020

https://stackoverflow.com/questions/32096886/mapstruct-mapping-of-generics

Hey, is there any progress regarding that issue ?

@jonsalvas
Copy link

Any news on this one? We are having a very similar issue with mapping models using generics

@Zegveld
Copy link
Contributor

Zegveld commented Apr 26, 2022

example of opening post seems to be working with 1.4.2.Final
Resulting mapper:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2022-04-26T22:25:36+0200",
    comments = "version: 1.4.2.Final, compiler: Eclipse JDT (IDE) 1.4.50.v20210914-1429, environment: Java 17.0.1 (Azul Systems, Inc.)"
)
public class IdMapperImpl implements IdMapper {

    @Override
    public Target toTarget(IdHoldingTo<Long> src) {
        if ( src == null ) {
            return null;
        }

        Target target = new Target();

        target.setId( src.getId() );

        return target;
    }

    @Override
    public IdHoldingTo<Long> toHolder(Target target) {
        if ( target == null ) {
            return null;
        }

        IdHoldingTo<Long> idHoldingTo = new IdHoldingTo<Long>();

        idHoldingTo.setId( target.getId() );

        return idHoldingTo;
    }
}

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

No branches or pull requests

7 participants