Constructor parameters for Mappers

1,081 views
Skip to first unread message

George Pai

unread,
Oct 28, 2015, 2:37:01 PM10/28/15
to mapstruct-users
I am in the middle of converting my code from using Spring field injection to using constructor injection, mainly for testing and mocking purposes.  I am having issues with my mappers though, since MapStruct only seems to use Spring field injection.

Summary
  1. Is there a way to define a parameterized constructor for a Mapper
  2. Is there a way to use any other Spring injection other than field when using other mappers

Details

This is what I basically have now (minus irrelevant and implicit code)

public class User {
   
private Set<Role> roles;
}


public class Role {

   
private String name;
}


@Service
public class RoleService {
   
public Role getRoleByName(String roleName) { // impl }
}


public class UserViewModel {
   
private Set<String> roles;
}


@Mapper(uses = "RoleMapper.class")
public interface UserMapper {
   
UserViewModel userToUserViewModel(User user);


   
User userViewModelToUser(UserViewModel userViewModel);
}


@Mapper
public abstract class RoleMapper {
   
protected RoleService roleService;


   
public Role roleNameToRole(String roleName) {
       
Role role = roleService.getRoleByName(roleName);
       
if (role == null) {
           
throw new RuntimeException(MessageFormat.format("Unknown role {0}", roleName));
       
}
       
return role;
   
}


   
public String roleToRoleName(Role role) {
       
return role == null ? null : role.getName();
   
}


   
@Autowired
   
public void setRoleService(RoleService roleService) {

       
this.roleService = roleService;
   
}
}



As you can see I am using setter injection for the RoleMapper instead of constructor injection since compilation fails if I try and define a parameterized constructor. So my first question is "Is there a way to define a parameterized constructor for a Mapper?" (my guess is no since even if there were Mappers.getMapper only has a class as a parameter, with no way to send parameters)

The main issue I'm having is that the uses = "RoleMapper.class" (using Spring) generates an @Autowired private RoleMapper roleMapper; in the UserMapperImpl which works fine except that I can't mock that roleService properly.  If I do a UserMapper userMapper = new UserMapperImpl() in my tests I can't inject a RoleMapper and if I use @RunWith(SpringJUnit4ClassRunner.class) to autowire it and inject mocks then, being that it has a singleton scope, it affects other tests that need it not to be mocked.  Ideally what I would want is constructor (or even setter) injection so that I can construct exactly what I need for some tests while leaving the Spring bean alone.

Andreas Gudian

unread,
Oct 28, 2015, 2:49:40 PM10/28/15
to George Pai, mapstruct-users
Hi George,

Supporting constructor injection is something that is on our agenda, albeit it came up in an issue with component-model "jsr330" in combination with Dagger DI:
https://github.com/mapstruct/mapstruct/issues/571

Would you add a comment that this would also be helpful for Spring, so we don't forget about it?

Thanks,
Andreas

--
You received this message because you are subscribed to the Google Groups "mapstruct-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to mapstruct-use...@googlegroups.com.
To post to this group, send email to mapstru...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

George Pai

unread,
Oct 28, 2015, 2:55:26 PM10/28/15
to mapstruct-users, geo...@megalobrainiac.com
Comment added to about Spring DI to the issue below.

Gunnar Morling

unread,
Oct 29, 2015, 3:25:54 AM10/29/15
to mapstruct-users, geo...@megalobrainiac.com
Am Mittwoch, 28. Oktober 2015 19:55:26 UTC+1 schrieb George Pai:
Comment added to about Spring DI to the issue below.

Thanks! Would you be interested in helping out with implementing this issue?

I suppose as a first step into this direction we could - optionally - generate the default constructor as now *and* a constructor expecting all the dependencies of the mapper. This should help with testing as in your case.
Reply all
Reply to author
Forward
0 new messages