Autowiring inside abstract class made for mapstruct

Abdul Wadhood Rehman picture Abdul Wadhood Rehman · May 8, 2015 · Viewed 13.1k times · Source

I am trying to build a REST Controller using Spring. To format the data for readability and more integration, I have used Mapstruct. Here's how I wrote Mapper.

@Mapper
public abstract class DeviceDataMapper {

@Autowired
DeviceService deviceService;

public static DeviceDataMapper INSTANCE = Mappers.getMapper(DeviceDataMapper.class);

@Mappings({
    @Mapping(source = "deviceId", target = "iddevice"),
    @Mapping(source = "deviceName", target = "name")
})
public abstract TODevice deviceToTODevice(DeviceData device);

public DeviceData toDeviceToDeviceData(TODevice toDevice){
    DeviceData deviceData = new DeviceData();
    deviceData.setDeviceId(toDevice.getIddevice());
    deviceData.setDeviceName(toDevice.getName());
    deviceData.setDeviceTemplateId(toDevice.getDeviceTemplateId());
    try {
deviceData.setDeviceTemplateName(deviceService.findDeviceTemplateById(toDevice.getDeviceTemplateId()).getName());
    } catch (Exception e) {
        e.printStackTrace();
    }

    return deviceData;
}}

The API Controller function looks like this

@RequestMapping(value = "/{deviceId}",method = RequestMethod.GET)
public @ResponseBody DeviceData get(@PathVariable int deviceId) {
    DeviceData deviceData=new DeviceData();
    try {
        deviceData =    DeviceDataMapper.INSTANCE.toDeviceToDevice(deviceService.findOne(deviceId));
    } catch (Exception e) {
        e.printStackTrace();
    }
    return deviceData;
}

The output deviceData returns fine except for one detail. I couldn't get to this function deviceService.findDeviceTemplateById(toDevice.getDeviceTemplateId() (where deviceService is autowired). The error stack trace shows me NullPointerException. So I am wondering whether is there any general rule about the accessibility of the autowired resources in abstract class? Or is the way I am instantiating that makes this function inaccessible? What should I change to make it work? I have also tried with @Inject from javax.inject with same result.

Answer

Gunnar picture Gunnar · Dec 14, 2016

You could use Spring as the component model for the mapper:

@Mapper(componentModel="spring")
public abstract class DeviceDataMapper {
    ...
}

That way you can inject dependencies into it (e.g. other hand-written it uses) as well as inject the mapper into other classes instead of resorting to the INSTANCE pattern.