Autowiring inside abstract class made for mapstruct
Solution 1
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.
Solution 2
In order for @Autowired
to work, the DeviceDataMapper
class needs to be a Spring bean. It will not work if you instantiate it yourself.
Either make it a Spring bean and use it like one, or pass a reference to deviceService
into it from your controller.
Related videos on Youtube
Abdul Wadhood Rehman
Updated on May 20, 2022Comments
-
Abdul Wadhood Rehman almost 2 years
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
fromjavax.inject
with same result. -
Gunnar almost 9 yearsI would also recommend to use Spring as the component model for the mapper: @Mapper(componentModel="spring" public abstract class DeviceDataMapper { ... }. That way you can get it in injected (the generated implementation will be a Spring bean) instead of resorting to the
INSTANCE
pattern. -
kryger over 7 years@Gunnar this should be a standalone (and accepted) answer. Reference
-
user1927638 about 3 yearsAre there any advantages to using the spring component model approach vs the instance pattern?