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 #1561DescriptionPhew, 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? Activitysjaakd commented on Jul 24, 2018 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. sebastianhaberey commented 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. filiphr commented on Aug 18, 2018 @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. filiphr commented on Aug 18, 2018 Just had a quick look the fix is really easy we do
|
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 sebastianhaberey commented 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. filiphr commented on Aug 21, 2018 Great. If you need any help you can find us in the MapStruct gitter room or just write here sebastianhaberey commented 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 filiphr commented on Sep 5, 2018 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. sebastianhaberey commented 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. added a commit that references this issue on Sep 24, 2018#1561 add support for adders in combination with streams filiphr commented on Sep 24, 2018 Thanks a lot @sebastianhaberey for providing the PR for this. We have integrated it into master
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|