CONTEXT:
I process reports with @Scheduled annotation and when invoke Component from Service property not getting initialized with @Value annotation even it physically exists in .properties and printed out in @PostConstruct.
DESCRIPTION:
ReportProcessor interface and InventoryReportProcessor implementation:
@FunctionalInterface
interface ReportProcessor {
public void process(OutputStream outputStream);
}
@Component
public class InventoryReportProcessor implement ReportProcessor {
@Value("${reportGenerator.path}")
private String destinationFileToSave;
/*
@PostConstruct
public void init() {
System.out.println(destinationFileToSave);
}
*/
@Override
public Map<String, Long> process(ByteArrayOutputStream outputStream) throws IOException {
System.out.println(destinationFileToSave);
// Some data processing in here
return null;
}
}
I use it from
@Service
public class ReportService {
@Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
@Scheduled(cron = "*/10 * * * * *")
public void processReport() {
InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
My confusion comes from the fact that @Value in Service works fine but in @Component it returns null unless call in @PostConstruct. Also, if call @PostConstruct the value is still remains null in the rest of the class code.
I found similar Q&A and I did research in Srping docs but so far no single idea why it works this way and what can be a solution?
Field injection is done after objects are constructed since obviously the container cannot set a property of something which doesn't exist.
at the time System.out.println(destinationFileToSave); triggers values are not being injected;
if you want to see it working try something like this
@Autowired
InventoryReportProcessor pross;
pross.process(ByteArrayOutputStream outputStream);
@PostConstruct works as it is being called after the object creation.
You need to Autowire the component to make your spring application aware of the component.
@Service
public class ReportService {
@Value("${mws.appVersion}")
private String appVersion;
/* Other initialization and public API methods*/
@Autowired
private ReportProcessor reportProcessor;
@Scheduled(cron = "*/10 * * * * *")
public void processReport() {
//InventoryReportProcessor reportProcessor = new InventoryReportProcessor();
Map<String, Long> skus = reportProcessor.process(new ByteArrayOutputStream());
}
}
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