Reputation: 615
I am having an issue when I am autowiring my properties class.
The following is my properties class which behaves fine when I autowire it in my @service class.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
public class SMSHistoryProperties {
@Autowired
Environment env;
/**
* Return the property value associated with the given key, or null if the
* key cannot be resolved.
*
* @param propName
* @return
*/
public String getProperty(String propName){
return env.getProperty(propName);
}
but when I autowire it in my SQLConstants class (which only has static constant variables) I am getting an exception.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.vzw.onem.search.properties.SMSHistoryProperties;
@Component
public class SQLConstants {
@Autowired
private static SMSHistoryProperties prop;
//~ Static fields/initializers ------------------------------------------
private static final String SMS_SCHEMA = prop.getProperty("sms.schema");
The exception I get is the following:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'SQLConstants' defined in file
[...\SQLConstants.class]: Instantiation of bean failed; nested
exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.search.constants.SQLConstants]: Constructor
threw exception; nested exception is java.lang.NullPointerException
EDIT:
I took the static final reference out but I am still getting a null pointer exception.
@Autowired
private SMSHistoryProperties prop;
private String BATCH_SMS_SQL = "SELECT ACK_CODE FROM "
+ prop.getProperty("sms.schema");
The nullpointer
is occurring on prop.getProperty("sms.schema")
.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'SMSController': Unsatisfied dependency expressed through field 'smsBuilder'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'SMSBuilder': Unsatisfied dependency expressed through field 'searchHelper'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'smsJdbcSearchHelper': Unsatisfied dependency expressed through field 'cccDao'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'smsSearchDAOImpl' defined in file [..\SmsSearchDAOImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.vzw.onem.search.dao.impl.SmsSearchDAOImpl]: Constructor threw exception; nested exception is java.lang.NullPointerException
Upvotes: 1
Views: 2527
Reputation: 131496
You could not make your static
fields with initializer that depend on a spring bean as beans are initialized only after the instantiation of the class by Spring while the static
field is initialized before any instantiation of the class.
Instead make these fields instance fields and use @PostConstruct
to init constant values after the dependency injection was done.
@Component
public class SQLConstants {
@Autowired
private SMSHistoryProperties prop;
//~ Static fields/initializers ------------------------------------------
private String SMS_SCHEMA;
@PostConstruct
public void init(){
SMS_SCHEMA = prop.getProperty("sms.schema");
}
}
Consequently, you could not keep them final
field. But you can guarantee that these be not updated from client classes by not providing setters for them. Which may be an acceptable workaround.
An alternative 1, inject directly the values in the String fields such as :
private final String schema;
public SQLConstants(@Value("${sms.schema}")String schema){
this.schema = schema;
}
or :
@Value("${sms.schema}")
private String schema;
The field injection way is shorter but makes the class API less testable without a Spring container and the field cannot be final
either.
An alternative 2 (my preference for your use case) make SMSHistoryProperties
less generic by providing methods for each value that you need to retrieve. It eliminate the needs to declare String constants and it will make your code more meaningful.
You could also unit test each retrieval method to ensure no regression issues if properties are changed.
@Component
@RefreshScope
public class SMSHistoryProperties {
@Autowired
Environment env;
public String getSchema(){
return env.getProperty("sms.schema");
}
public String getOtherValue(){
return env.getProperty("sms.otherValue");
}
}
Upvotes: 4
Reputation: 7235
You can't Autowired
static field in Spring
. So, Your SMSHistoryProperties prop
will set to null
. And you are using prop
to call getProperty("sms.schema");
and obviously, it will give you NullPointerException
.
Upvotes: 2