GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add support for "adders" in combination with streams · Issue #1561 · mapstruct/mapstruct

Add support for "adders" in combination with streams #1561

New issue
Copy link
New issue
Copy link
Closed
Closed
Add support for "adders" in combination with streams#1561
Copy link
Labels
enhancementgood first issueup-for-grabsIssues targeted for community contributionIssues targeted for community contribution
Milestone
1.3.0.Beta2

Description

@sebastianhaberey
sebastianhaberey
opened on Jul 24, 2018
Issue body actions

Phew, this took me a while to figure out. Given a target entity like this:

public class Car {

  ...

  public Stream<String> getPartIds() {
    ...
  }

  public void addPartId(String partId) {
    ...
  }
}

MapStruct will not recognize the adder (regardless of collection mapping strategy) and will not generate the mapping code for the "partIds" attribute. Would it be difficult to implement this?

Activity

  1. sjaakd commented on Jul 24, 2018

    @sjaakd
    sjaakd
    on Jul 24, 2018
    Contributor
    More actions

    adder strategy was made with a particular use case in mind: JPA / DALI. Probably it can be extended. However, you could (nowadays) also do it by handing a context annotated variable from parent to child mapping. See here for an example. Let me know if this suffices your requirements.

  2. sebastianhaberey commented on Jul 25, 2018

    @sebastianhaberey
    sebastianhaberey
    on Jul 25, 2018
    ContributorAuthor
    More actions

    I just had a go at the context-based approach you mentioned above. But I don't see how I could implement a generic context that applies to all our mapped classes, meaning that I'd probably have to write a considerable amount of repetitive code to accomodate each of our cases.

    Our current workaround would be to add a setter method like setPartIds(Stream<String> partIds) to all our target classes. Luckily, we have control over those. But I still think it would be great if MapStruct recognized adders here.

  3. filiphr
    added
    enhancement
    up-for-grabsIssues targeted for community contributionIssues targeted for community contribution
    on Aug 18, 2018
  4. filiphr commented on Aug 18, 2018

    @filiphr
    filiphr
    on Aug 18, 2018
    Member
    More actions

    @sebastianhaberey you are completely right MapStruct should be able to recognize such adders as well. Just for my info, if that method was List<String> it was working right? If that is the case then I suppose the fix is really easy.

  5. filiphr commented on Aug 18, 2018

    @filiphr
    filiphr
    on Aug 18, 2018
    Member
    More actions

    Just had a quick look the fix is really easy we do

    mapstruct/processor/src/main/java/org/mapstruct/ap/internal/model/common/Type.java

    Lines 626 to 649 in 10f855f

    private Accessor getAdderForType(Type collectionProperty, String pluralPropertyName) {
    List<Accessor> candidates = new ArrayList<Accessor>();
    if ( collectionProperty.isCollectionType ) {
    // this is a collection, so this can be done always
    TypeMirror typeArg = first( collectionProperty.determineTypeArguments( Iterable.class ) ).getTypeBound()
    .getTypeMirror();
    // now, look for a method that
    // 1) starts with add,
    // 2) and has typeArg as one and only arg
    List<Accessor> adderList = getAdders();
    for ( Accessor adder : adderList ) {
    ExecutableElement executable = adder.getExecutable();
    if ( executable == null ) {
    // it should not be null, but to be safe
    continue;
    }
    VariableElement arg = executable.getParameters().get( 0 );
    if ( typeUtils.isSameType( arg.asType(), typeArg ) ) {
    candidates.add( adder );
    }
    }
    }

    so it is just a matter of adding a new if there to consider Stream. Will leave it for the community if someone wants to contribute to it, we can always help out here

  6. filiphr
    added
    good first issue
    on Aug 18, 2018
  7. filiphr
    added this to the 1.3.x milestone on Aug 18, 2018
  8. sebastianhaberey commented on Aug 21, 2018

    @sebastianhaberey
    sebastianhaberey
    on Aug 21, 2018
    ContributorAuthor
    More actions

    Ok cool I'd like to have a go at it if that's ok. I'll check out the repository and see if I can get the tests to run.

  9. filiphr commented on Aug 21, 2018

    @filiphr
    filiphr
    on Aug 21, 2018
    Member
    More actions

    Great. If you need any help you can find us in the MapStruct gitter room or just write here

  10. sebastianhaberey commented on Aug 22, 2018

    @sebastianhaberey
    sebastianhaberey
    on Aug 22, 2018
    ContributorAuthor
    More actions

    With your help I have located a few places that I think would have to be extended for this to work. The mapping of

    an entity with methods Collection getProperties / setProperties(Collection) to / from
    an entity with methods Stream getProperties / addProperty(X)

    works now. But when mapping

    an entity with methods Collection getProperties + addProperty(X) to / from
    an entity with methods Stream getProperties + addProperty(X)

    i get:

    for-each not applicable to expression type
    required: array or java.lang.Iterable
    found: java.util.stream.Stream<java.lang.String>

    @filiphr could you have a look at my changes and see if you can spot the error? There's also a unit test that will provoke the error when enabled.

    Edit: alternatively we could decide not to deal with the second use case here and go with the simple solution

  11. filiphr commented on Sep 5, 2018

    @filiphr
    filiphr
    on Sep 5, 2018
    Member
    More actions

    I forgot to get back to you @sebastianhaberey. Had a quick glance. The problem is in the AdderWrapper and AdderWrapper.ftl.

    When mapping from Stream into an adder then we need to iterate over it and the current AdderWrapper.ftl does:

    if ( ${sourceReference} != null ) {
        for ( <@includeModel object=adderType.typeBound/> ${sourceLocalVarName} : ${sourceReference} ) {
            ${ext.targetBeanName}.${ext.targetWriteAccessorName}<@lib.handleWrite><@lib.handleAssignment/></@lib.handleWrite>;
        }
    }
    

    In your case the sourceReference is the Stream. We probably need a new StreamAdderWrapper that would allow us to map from a Stream into a list using an adder.

  12. sebastianhaberey commented on Sep 6, 2018

    @sebastianhaberey
    sebastianhaberey
    on Sep 6, 2018
    ContributorAuthor
    More actions

    Nice! I think you hit the nail on the head. I introduced a StreamAdderWrapper and it works nicely (unit test is green). I created a pull request - please have a look, especially at the .ftl file since I've never used FreeMarker before. I basically copied it and did a bit of guesswork there.

  13. filiphr
    added a commit that references this issue on Sep 24, 2018

    #1561 add support for adders in combination with streams

    30c2dad
  14. filiphr commented on Sep 24, 2018

    @filiphr
    filiphr
    on Sep 24, 2018
    Member
    More actions

    Thanks a lot @sebastianhaberey for providing the PR for this. We have integrated it into master

  15. filiphr
    closed this as completedon Sep 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementgood first issueup-for-grabsIssues targeted for community contributionIssues targeted for community contribution

    Type

    No type

    Projects

    No projects

      Milestone

      • 1.3.0.Beta2

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.