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.
We can't use @Autowired on a constructor of an abstract class. Spring doesn't evaluate the @Autowired annotation on a constructor of an abstract class. The subclass should provide the necessary arguments to the super constructor.
Once ObjectB will be injected into ObjectA, ObjectA will be able to access ObjectB properties and methods. To inject ObjectB in ObjectA, a constructor or a setter make it possible. In both cases, ObjectB is injected in ObjectA. And thus, usable within ObjectA.
You don't. You only declare the beans which have a concrete subclass of that abstract class.
MapStruct is a code generator tool that greatly simplifies the implementation of mappings between Java bean types based on a convention over configuration approach. The generated mapping code uses plain method invocations and thus is fast, type-safe, and easy to understand.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With