I've this class:
@Slf4j
@Configuration
public class TxnIdGeneratorProperties {
@Bean
public TimeBasedTxnIdGenerator seqGenerator() {
if (log.isInfoEnabled())
log.info("{} Loading CustomProperties :: getTxnIdGeneratorAccounts....", BOOT_CONFIG);
TimeBasedTxnIdGenerator sequencer = new TimeBasedTxnIdGenerator();
sequencer.calculateLimit();
return sequencer;
}
}
Here I'm creating an object of TimeBasedTxnIdGenerator
, calling the calculateLimit()
method, and returning the same object as the bean that must be created during startup. This is the TimeBasedTxnIdGenerator
class:
@Service
public class TimeBasedTxnIdGenerator extends AbstractSequencer implements TransactionIdGenerator {
@Value("${qr.code.app.url}")
private String qrCodeAppUrl;
private static final int NODE_ID_BITS = 10;
private static final long maxNodeId = (1L << NODE_ID_BITS) - 1;
public TimeBasedTxnIdGenerator() {
super();
}
@Override
public synchronized String doExecute() {
return getSequenceId();
}
private static long createNodeId() {
long nodeId;
try {
StringBuilder sb = new StringBuilder();
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface networkInterface = networkInterfaces.nextElement();
byte[] mac = networkInterface.getHardwareAddress();
if (mac != null) {
for(byte macPort: mac) {
sb.append(String.format("%02X", macPort));
}
}
}
nodeId = sb.toString().hashCode();
} catch (Exception ex) {
nodeId = (new SecureRandom().nextInt());
}
nodeId = nodeId & maxNodeId;
return nodeId;
}
@Override
public void calculateLimit() {
System.out.println("MFS App param : " + qrCodeAppUrl);
long nodeId = createNodeId();
setSequencerLimit(nodeId);
}
}
The problem is when I try to read this qr.code.app.url
configuration value from the application.properties
file, when I print the value at the startup, it is getting printed as null
. But when I change the data type of qrCodeAppUrl
from String
to int
, I'm getting this startup error:
Caused by: org.springframework.beans.TypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; For input string: "digipay://pay?"
So, the application knows the value of that configuration before calling the calculateLimit()
method, but inside the method, its value is printed as null
. Why is that?
You're creating the class instance with new
, the @Value
annotation on the field is not going to get evaluated. EDIT: as pointed out by @SotiriosDelimanolis in the comment, the annotation is going to get evaluated, but only after the object is returned from the method.
You can create Beans either with the @Service
annotation or in the @Configuration
as a @Bean
. To inject the value that way, you can do
public class TimeBasedTxnIdGenerator extends AbstractSequencer implements TransactionIdGenerator {
private final String qrUrl;
public TimeBasedTxnIdGenerator(String url) {
qrUrl = url;
}
// ...
}
@Configuration
public class Config {
@Bean
public TimeBasedTxnIdGenerator seqGenerator(@Value("${qr.code.app.url}") String qrCodeAppUrl) {
if (log.isInfoEnabled())
log.info("{} Loading CustomProperties :: getTxnIdGeneratorAccounts....", BOOT_CONFIG);
TimeBasedTxnIdGenerator sequencer = new TimeBasedTxnIdGenerator(qrCodeAppUrl);
sequencer.calculateLimit();
return sequencer;
}
}