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

Access to the target property name #2688

Closed
HemalathaGowdar opened this issue Dec 13, 2021 · 20 comments
Closed

Access to the target property name #2688

HemalathaGowdar opened this issue Dec 13, 2021 · 20 comments
Labels
Milestone

Comments

@HemalathaGowdar
Copy link

HemalathaGowdar commented Dec 13, 2021

Expose target property to method arguments

@filiphr
Copy link
Member

filiphr commented Dec 13, 2021

Can you please provide an example?

@filiphr filiphr added closing-when-no-response Marking issues that are ready to be closed and removed closing-when-no-response Marking issues that are ready to be closed labels Dec 13, 2021
@HemalathaGowdar
Copy link
Author

HemalathaGowdar commented Dec 13, 2021

@Mapper(config = MapperBConfig.class , uses = EValueMapper.class)
@Component 
public abstract class AttribMapper {
    @Mapping(source = "indicator" , target = "ïndicator")
    @Mapping(source = "indicator2" , target = "shellType")
    public abstract TargetAttributes TargetAttributesMapper( SourceAttributes src, @MappingTarget TargetAttributes target);

    @Condition
    public boolean conditioncheck(String value)
    {
        if(contains in map attribute check) // basically am trying to map to the target attribute if that attribute is required by consumer 
            return true
        else return false
    }
}

This method should get invoke for all attributes mapping.
I also tried Conditionexpression to check whether this attribute in teh consumer list to map or not . This also not coming in the generated impl class . I am basically trying for presence check of that attribute in the consumer list. if yes , I should do mapping else ignore mapping part

Could you please suggest here.

@Zegveld
Copy link
Contributor

Zegveld commented Dec 20, 2021

If I understand correctly what you want is something like I've got a Map<String, Object> named source and another Map<String, Object> named target and I only want to map the entries from source for which there is already an entry present in target?
Trying to do this using conditions with Iterables or Maps is not supported yet, see #1610 for more information.

However writing the mapping yourself might not be that much additional code, and mapstruct can still use it in the mappingchain like this:

@Mapper
public abstract class ConditionalMapMapper {
    static class Item {
        Map<String, String> value;
       // getters and setters
    }

    static class ItemDto {
        Map<String, String> value;
       // getters and setters
    }

    abstract Item map(ItemDto dto, @MappingTarget Item item);

    void map(Map<String, String> source, @MappingTarget Map<String, String> target) {
        for ( Entry<String, String> entry : source.entrySet() ) {
            if ( target.containsKey( entry.getKey() ) ) {
                target.put( entry.getKey(), entry.getValue() );
            }
        }
    }
}

The map method with the source and target map will be used in the implementation to map from/to a map.

public class ConditionalMapMapperImpl extends ConditionalMapMapper {

    @Override
    Item map(ItemDto dto, Item item) {
        if ( dto == null ) {
            return null;
        }

        if ( dto.getValue() != null ) {
            if ( item.getValue() == null ) {
                item.setValue( new LinkedHashMap<String, String>() );
            }
            map( dto.getValue(), item.getValue() );
        }
        else {
            item.setValue( null );
        }

        return item;
    }
}

Hope this helps.

@filiphr filiphr added the closing-when-no-response Marking issues that are ready to be closed label Dec 25, 2021
@HemalathaGowdar
Copy link
Author

No , I am looking something if Target attribute name is present in my attribute list(list which has selected target attribute name for each diff scenario ) to map then only i should map else I should skip mapping.

@Zegveld
Copy link
Contributor

Zegveld commented Dec 27, 2021

So something like:

@Mapper
public abstract class ConditionalMapMapper {
    static class Item {
        Map<String, String> value;
       // getters and setters
    }

    static class ItemDto {
        Map<String, String> value;
       // getters and setters
    }

    abstract Item map(ItemDto dto, @MappingTarget Item item, @Context List<String> attributeList);

    void map(Map<String, String> source, @MappingTarget Map<String, String> target, @Context List<String> attributeList) {
        for ( Entry<String, String> entry : source.entrySet() ) {
            if ( attributeList.contains( entry.getKey() ) ) {
                target.put( entry.getKey(), entry.getValue() );
            }
        }
    }
}

The map method with the source and target map will be used in the implementation to map from/to a map.

public class ConditionalMapMapperImpl extends ConditionalMapMapper {

    @Override
    Item map(ItemDto dto, Item item, List<String> attributeList) {
        if ( dto == null ) {
            return null;
        }

        if ( dto.getValue() != null ) {
            if ( item.getValue() == null ) {
                item.setValue( new LinkedHashMap<String, String>() );
            }
            map( dto.getValue(), item.getValue(), attributeList );
        }
        else {
            item.setValue( null );
        }

        return item;
    }
}

Am I getting closer or still misunderstanding you?

@HemalathaGowdar
Copy link
Author

HemalathaGowdar commented Jan 18, 2022

Sorry for the delay .

This is what we are looking.

package mapstruct;

@Mapper(uses = TesterMapper.PresenceUtill.class)
public interface TesterMapper {
	
	TesterMapper inst = Mappers.getMapper(TesterMapper.class);
	
	@Mapping(source ="name" , target ="name"  )
	@Mapping(source ="secName" , target ="sName" , conditionExpression = "java(variablePresenceCheck(\"sName\"))" )
	@Mapping(source ="isHuman" , target ="isHuman" )
	 MapsStructTarget  mapstrucMapper (MapStructSource src);
	
	
	 class PresenceUtill {

		@Condition
		public boolean checkmethod(String str , String source)
		{
			if (null != str)
			{
				System.out.println(str);
				System.out.println(source);
			
				return true;
			}
			return false;
		}
		
		@Condition
		public boolean checkmethod(Boolean str)
		{
			if (null != str)
			{
				return true;
			}
			return false;
		}

	}
	
	
	  default boolean variablePresenceCheck(String str) { 
		  
		  if (I will check this variable name is present in my attrib list  ) { return true;
		  }
	  return false; }
	 

}

Using conditionExpression I can achieve this , by passing the name of the variable explicitly in conditionExpression.
Do we have something in @condition annotation too - I need the name of the target variable on each mappings. so that I can evaluate whether I need to set this variable or skip

@Zegveld Zegveld removed the closing-when-no-response Marking issues that are ready to be closed label Jan 18, 2022
@Zegveld
Copy link
Contributor

Zegveld commented Jan 18, 2022

@filiphr , I don't believe there is an annotation to reference the property name yet, is there?
So this would be a feature request to implement a method argument annotation much like how @TargetType works for passing the class, perhaps something like @TargetProperty.

@HemalathaGowdar
Copy link
Author

Thanks for the information . We can use conditional expression when we have diff names. But when we have the same names for the entire classes , in that case we are not using @mapping annotations.

Could you please suggest for this scenario ? can we achieve this by overriding any of the existing methods for now

@filiphr
Copy link
Member

filiphr commented Jan 18, 2022

You are right @Zegveld there is no annotation that would allow access to the target property name. Supporting @TargetProperty for a string method argument is something that we could add.

I will rename this issue.

@HemalathaGowdar you can still use @Mapping even if the source and target names are identical.

e.g.

@Mapping(target = "id", conditionExpression = "java(...)")

@filiphr filiphr changed the title Condition annotated method not being invoked in generated IMPL class Access to the target property name Jan 18, 2022
@HemalathaGowdar
Copy link
Author

Yes , we can . But the problem is we have so many files with lot of attributes . That new annotation to support in @condition methods . If you could help me with this new feature timelines . Ours is enhancement project ,we can wait for this feature. This would help us.

@filiphr
Copy link
Member

filiphr commented Jan 22, 2022

If you could help me with this new feature timelines

Unfortunately we can't provide timelines, since all of us are working on this on a part time voluntary basis and we try to focus on the most requested features for new releases. In case you are interested in seeing this feature sooner you can always provide a PR that we can review and integrate.

@BabkenSahakyan
Copy link

This is exactly the problem I'm facing now. In my case for a given class I've a list of non editable properties which is configurable and may change at runtime and this @Condition methods seems the only appropriate place to do this checking. With a support of @MappingTarget and @TargetProperty problem will be nicely solved.

Thank you all.

@HemalathaGowdar
Copy link
Author

HemalathaGowdar commented Mar 4, 2022

When am giving conditional Expression , the NULL check (Null value check strategy) is getting replaced by conditional expression method. I need NULL check too irrespective of conditionalExpression. Could u please suggest

@filiphr
Copy link
Member

filiphr commented Mar 6, 2022

@HemalathaGowdar please do not use this issue to ask questions about unrelated things. The documentation for this is in the Conditional Mapping section of our documentation. If something is not clear please open a discussion, ask on StackOverflow or out Gitter Room.

ivlcic added a commit to ivlcic/mapstruct that referenced this issue Apr 28, 2022
Access to the target property name mapstruct#2688
mapstruct#2688

As agreed in:
mapstruct#2831
ivlcic added a commit to ivlcic/mapstruct that referenced this issue May 30, 2022
@filiphr filiphr added this to the 1.6.0 milestone May 30, 2022
filiphr pushed a commit to filiphr/mapstruct that referenced this issue Aug 1, 2022
@filiphr
Copy link
Member

filiphr commented Aug 1, 2022

Thanks for your work on this @ivlcic. This has been integrated into main.

@filiphr filiphr closed this as completed Aug 1, 2022
@FlorianCassayre
Copy link

This seems to correspond to what our project is needing. Is there a planned date for the release of 1.6.0 (even a release candidate)?

@filiphr
Copy link
Member

filiphr commented Nov 12, 2022

@FlorianCassayre we have some other issues that we would like to tackle before we release a first beta release for 1.6. I hope that I can speed this up

@FlorianCassayre
Copy link

Thanks for the reply, I understand; we will follow that closely and will be looking forward to that beta release.

@ivlcic
Copy link
Contributor

ivlcic commented May 16, 2023

Hi guys how's 1.6.0 progressing?

@filiphr
Copy link
Member

filiphr commented May 20, 2023

@ivlcic it is going slower that I would like. Unfortunately I do not have ample of time, so trying to find the time to wrap things up and do an initial release

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

No branches or pull requests

6 participants