Iurii Iurii - 3 months ago 18
Java Question

MapStruct requires Impl class

I have next classes:

Mapper

public interface DeviceTokensMapper {

DeviceTokensMapper INSTANCE = Mappers.getMapper(DeviceTokensMapper.class);

@Mappings({
@Mapping(source = "tokenName", target = "tokenName"),
@Mapping(source = "userOsType", target = "osType"),
})

DeviceTokensDTO toDeviceTokensDTO(DeviceTokens deviceTokens);
}


Entity:

@Entity
public class DeviceTokens {

@Id
@Column(name="token_name", nullable = false)
private String tokenName;

@Column(name = "os", nullable = false)
@Enumerated
private UserOSType userOsType;

public DeviceTokens() {}

public DeviceTokens(String tokenName, UserOSType userOSType) {
this.tokenName = tokenName;
this.userOsType = userOSType;
}

public String getTokenName() {
return tokenName;
}

public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}

public UserOSType getUserOsType() {
return userOsType;
}

public void setUserOsType(UserOSType userOsType) {
this.userOsType = userOsType;
}
}


DTO:

public class DeviceTokensDTO {

private String tokenName;

private UserOSType osType;

public DeviceTokensDTO() {}

public DeviceTokensDTO(String tokenName, UserOSType osType) {
this.tokenName = tokenName;
this.osType = osType;
}

public UserOSType getOsType() {
return osType;
}

public void setOsType(UserOSType osType) {
this.osType = osType;
}

public String getTokenName() {
return tokenName;
}

public void setTokenName(String tokenName) {
this.tokenName = tokenName;
}
}


And method from spring service class where I use this mapping:

@Transactional
public DeviceTokensDTO storeToken(String tokenId, UserOSType userOsType) {
DeviceTokens deviceTokens = new DeviceTokens(tokenId, userOsType);
DeviceTokens newDevice = deviceTokensRepository.save(deviceTokens);

return DeviceTokensMapper.INSTANCE.toDeviceTokensDTO(newDevice);
}


When I run above method I see next exception:


ERROR [dispatcherServlet]:? - Servlet.service() for servlet
[dispatcherServlet] in context with path [] threw exception [Handler
processing failed; nested exception is
java.lang.ExceptionInInitializerError] with root cause
java.lang.ClassNotFoundException:
dto.DeviceTokensMapperImpl


So why mapper require implementation class? Could please someone advise?
Thanks.

Answer

MapStruct generates code at compile time, and the call to Mappers.getMapper(DeviceTokensMapper.class); will look for the generated implementation of the mapper interface. For some reason it seems to be missing in your deployment unit (WAR etc.).

Btw. when working with Spring as your DI container, you can use @Mapper(componentModel="spring") and you will be able to obtain mapper instances via dependency injection instead of using the Mappers factory.