Read application.properties from non-component class like pojo or singleton - java

I'm using spring boot & for properties I've placed application.properties inside src/main/resources
From #Controllers & #Services, I'm able to read properties, but from my model pojo & a singleton class, I'm not able to read the values.
My #SpringBootApplication is in com.vehicle & I've not overriden #ComponentScan, so I belive it should read all the underlying packages.
Below is code:
application.properties
vehicle.lift.maxWeight=10
vehicle.lift.error.overWeight=Overweight
vehicle.battery.default=5.0
vehicle.battery.critical.limit=15
vehicle.walk.distance.error=Not able to move
WalkServiceImpl.java (able to read from here)
package com.vehicle.prototype.service.impl;
#Service
public class WalkServiceImpl implements CapabilityService {
#Value("${vehicle.walk.distance.error}")
private String mDistanceError;
#Override
public void performTask(VehicleData vehicleData) {
double distance = vehicleData.getWalkingDistance();
double remainingBattery = vehicleData.getRemainingBattery();
if (remainingBattery < distance) {
vehicleData.setErrorMessage(mDistanceError);
System.out.println(mDistanceError);
} else {
vehicleData.setRemainingBattery(remainingBattery - distance);
}
VehicleUtil.checkBatteryStatus(vehicleData);
}
}
VehicleData.java (Pojo - not able read from here)
package com.vehicle.prototype.model;
public class VehicleData {
private double walkingDistance;
private double liftWeight;
#Value("${vehicle.battery.default}")
private double remainingBattery;
// setters & getters ....
}
VehicleUtil.java (Singleton - not able to read from here)
package com.vehicle.prototype.utils;
public class VehicleUtil {
private static VehicleUtil mInstance = null;
private static Object mLock = new Object();
#Value("${vehicle.battery.critical.limit}")
private static double mCriticalLimit;
#Value("${vehicle.battery.default}")
private static double mTotalPower;
#Value("${vehicle.battery.critical.warning}")
private static String powerWarning;
private VehicleUtil() {
// empty private constructor.
}
public static VehicleUtil getInstance() {
if (mInstance == null) {
synchronized (mLock) {
if (mInstance == null)
mInstance = new VehicleUtil();
}
}
return mInstance;
}
public static void checkBatteryStatus(VehicleData vehicleData) {
double criticalMark = (mCriticalLimit * 100.0f) / mTotalPower;
if (vehicleData.getRemainingBattery() < criticalMark) {
vehicleData.setBatteryCritical(Boolean.TRUE);
System.out.println(powerWarning);
} else {
vehicleData.setBatteryCritical(Boolean.FALSE);
}
}
}
Please let me know how to fix this.
Thank You

You need to inject the properties into a spring-managed bean.
What you can do, is to bundle the properties in a bean like this (see documentation)
#ConfigurationProperties(prefix="vehicle")
public class VehicleProperties {
#Value("${battery.critical.limit}")
private double mCriticalLimit;
#Value("${battery.default}")
private double mTotalPower;
#Value("${battery.critical.warning}")
private String powerWarning;
}
Then, inject the Vehicle Properties into your service and passe them to VehicleUtil:
public class WalkServiceImpl {
#Autowired
private VehicleProperties vehicleProperties;
#Override
public void performTask(VehicleData vehicleData) {
...
VehicleUtil.checkBatteryStatus(vehicleProperties, vehicleData);
}
}
Better yet, I would convert VehicleUtil into a managed-bean
#Component
public class VehicleUtil {
#Autowired
private VehicleProperties vehicleProperties;
}
VehicleData
I'm assuming VehicleData is some business object, passed from the client or that you create yourself, for which they are many instances (not just one singleton). In this case, it wouldn't make sense to convert VehicleData into a managed-bean, and its external dependencies could just be provided to it through its setters:
public class VehicleData {
private double walkingDistance;
private double liftWeight;
private double remainingBattery;
// setters & getters ....
}

Only Instances controlled by Spring are able to get property values injected.
As you have a Spring application you should not write own singleton logic instead of simply annotation VehicleUtil by #Component. This would also make any usages more testable as you can mock it in a test when the util instance is injected.
You cannot inject a value directly to the VehicleData pojo. The property value is mostly a constant during runtime so it can be a default only. You should set the value before exposing in a repo or service or leave it null and use the value instead of the non set property wherever it is used.

Related

Inject dependency across a constructor with multiple constructors existing

public abstract class MainService<T extends Managed> {
private static final Logger logger = LoggerFactory.getLogger(ContentService.class);
protected final ExecutorService executor;
private final boolean idValidation;
#Autowired
private LockValidator lockValidator;
public MainService() {
this(null, true);
}
public MainService(boolean idValidation) {
this(null, idValidation);
}
public MainService(final ThreadConfig tpConfig) {
this(tpConfig, true);
}
protected MainService(final ThreadConfig tpConfig, final boolean idValidation) {
// Some code
}
The code above works fine. But I have to replace the #Autowired annotation and inject the component via constructor. The problem is when I create this constructor:
public MainService(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
Instantly, these attributes get errors:
protected final ExecutorService executor;
private final boolean idValidation;
Variable 'executor' might not have been initialized
And of course, I guess that I need to send some parameters into the new constructor. The question is: How Could I refactor this code, using a constructor to inject the component instead of the annotation?
Quick fix:
public MainService(LockValidation lockValidation,ThreadConfig tpConfig,boolean idValidation) {
this(tpConfig,idValidation);
this.lockValidation = lockValidation;
}
You are not following SOLID principles (Dependency Injection) here by initializing executor inside the constructor. Best approach would be to use all argument constructor.
protected MainService(ThreadConfig tpConfig,boolean idValidation,ExecutorService executor,LockValidation lockValidation) {
this.tpConfig=tpConfig;
this.idValidation=idValidation;
this.executor=executor;
this.lockValidation=lockValidation;
/// Some code
}
Finally, I could see that to create a constructor could be a headache because it's probable to make refactors in the constructors. So, I decided to implement an injection via set method like this:
#Autowired
public void setLockValidation(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
It worked fine

Spring Boot - Assign value to Class Member from YML file - Null Pointer Exception

I am using below annotations in my config class to get the values from properties file(yml).
Configuration
EnableConfigurationProperties
ConfigurationProperties (prefix = "notification")
I am able to get the values inside public methods without problem using the class . But I am getting 'Error Creating bean' Error when I try to assign value instance variable of the class using config class.
Below is my code. Can someone please throw some light.
This is my config class
#Configuration
#EnableConfigurationProperties
#ConfigurationProperties (prefix = "notification")
public class NotifyYaml {
private String subscriptionId;
public String getSubscriptionId() {
return subscriptionId;
}
public void setSubscriptionId(String subscriptionId) {
this.subscriptionId = subscriptionId;
}
Below is the class where I am getting error during startup.
#Component
public class PubSubController {
#Autowired
private NotifyYaml notify;
public PubSubController() {
// TODO Auto-generated constructor stub
}
String projectId = "ccc-g-pre-proj-cacdate";
//Error in this line
String subscriptionId = notify.getSubscriptionId();
The #Autowired object only gets filled in after the object is created.
This means that while the object is being created, it tries to call a method from a null object.
I would suggest using something like a #PostConstruct method. (Note: you will need to include javax.annotations into your project somehow.)
String subscriptions; // remove the value for now...
#PostConstruct
private void init() {
subscriptions = notify.getSubscriptionId(); // ...and add it back in here.
}

Using Mock for fields that are instances of one class

I have a classes:
public class Sender {
private final SomeClass firstField;
private final SomeClass secondField;
private Sender(SomeClass firtsField, SomeClass secondField){
this.firstField = firstField;
this.secondField = secondField;
}
}
#RunWith(MockitoJUnitRunner.class)
public class SenderTest{
#Mock
private firstField;
#Mock
private secondField;
}
Everything are looking grade, but looks like it injects the same objects in two fields or something like this. When I am trying to use when(..).thenReturn() for one field it sets data two another and vise verse; And the most strange that it works fine in debug mode. What can you say?
Mockito has some problems with constructor injection of two or more fields of the same type. But it works perfectly if you use setter injection.
So you can refactor "Sender" class like this:
public class Sender {
private SomeClass firstField;
private SomeClass secondField;
public void setFirstField(SomeClass firstField) {
this.firstField = firstField;
}
public void setSecondField(SomeClass secondField) {
this.secondField= secondField;
}
}
Remember that if class has both the constructor and setters, Mockito will choose the constructor for injection and completely ignore setters.
Edit: if you definitely need to use constructor for some reason, you can always mock fields manually instead of using Mockito annotations.
So in your case Sender would stay the same and SenderTest would be like this:
public class SenderTest {
private SomeClass firstField;
private SomeClass secondField;
private Sender sender;
#Before
public void setUp() {
firstField = Mockito.mock(SomeClass.class);
secondField = Mockito.mock(SomeClass.class);
sender = new Sender(firstField, secondField);
}
#Test
public void smokeTest() {
}
}
It depends what SomeClass is itself. It it a data (POJO) object, it's worth to create them in test (and i.e. fill with random generated values).
If it is a service. It can be sign for a architecture problem. why do you need two copies of the same service? Probably it makes sense to do some refactoring.

A known design pattern for dynamic factory

Does this have a proper name?
public class SomethingFactory {
private final String someParameter;
public SomethingFactory(String someParameter) {
this.someParameter = someParameter;
}
public Something create(String anotherParameter) {
return new Something(someParameter, anotherParameter);
}
}
public class Something {
public final String someParameter;
public final String anotherParameter;
public Something(String someParameter, String anotherParameter) {
this.someParameter = someParameter;
this.anotherParameter = anotherParameter;
}
}
What's different from a regular factory is that you have to specify a parameter at runtime to create() whenever you need to create an object.
That way you can make a singleton factory within Spring context for example, configuring first half of parameters there, and then finish with the rest of parameters at runtime when you call create().
Why I need that in the first place if you're curious:
I used to have regular singleton objects in Spring context and it was fine in thread-per-request applications, but now my whole app is non-blocking and I can't use ThreadLocal to keep stuff throughout entire request processing. For example, to keep info on timings with something like Apache StopWatch.
I needed to find a way to implement a "request scope" in a multithreading, non-blocking environment without having to supply the object representing the scope in every method (that would be silly) of my code.
So I thought let's make every (service) class take this scope object in constructor and let's create those classes on every request, but that goes against the singletons. The singletons we're talking are like, UserService that logs a user in, or a CryptoService that generates digital signatures. They're configured once in Spring, injected wheneven needed and everything's ok. But now I need to create those service classes in every method where they're needed, instead of just referencing an injected singleton instance.
So I thought let's call those singletons "templates" and whenever you need an actual instance you call create() supplying the said scope object. That way every class has the scope object, you just have to keep supplying it into other template service constructors. The full thing would look like this:
public class UserService {
private final Scope scope;
private final Template t;
private UserService(Template t, Scope scope) {
this.t = t;
this.scope = scope;
}
public void login(String username) {
scope.timings.probe("before calling database");
t.database.doSomething(username);
scope.timings.probe("after calling database");
}
public static class Template { /* The singleton configured in Spring */
private Database database;
public void setDatabase(Database database) { /* Injected by Spring */
this.database = database;
}
public UserService create(Scope scope) {
return new UserService(this, scope);
}
}
}
public class LoginHttpHandler { /* Also a Spring singleton */
private UserService.Template userServiceT;
public void setUserServiceT(UserService.Template userServiceT) { /* Injected by Spring */
this.userServiceT = userServiceT;
}
public void handle(HttpContext context) { /* Called on every http request */
userServiceT.create(context.scope).login("billgates");
}
}
In Spring you'd just describe a UserService.Template bean with the appropriate dependencies it needs and then inject that bean whenever a UserService is needed.
I just call that a "template". But like always I feel it's already been done. Does it have any name?
That is almost the example given for Guice's AssistedInject:
public class RealPaymentFactory implements PaymentFactory {
private final Provider<CreditService> creditServiceProvider;
private final Provider<AuthService> authServiceProvider;
#Inject
public RealPaymentFactory(Provider<CreditService> creditServiceProvider, Provider<AuthService> authServiceProvider) {
this.creditServiceProvider = creditServiceProvider;
this.authServiceProvider = authServiceProvider;
}
public Payment create(Date startDate, Money amount) {
return new RealPayment(creditServiceProvider.get(), authServiceProvider.get(), startDate, amount);
}
}
public class RealPayment implements Payment {
public RealPayment(
CreditService creditService, // from the Injector
AuthService authService, // from the Injector
Date startDate, // from the instance's creator
Money amount) // from the instance's creator
{
...
}
}
Assisted injection is used to "create classes that need extra arguments at construction time".
Also, this is similar to partial application, so you could have a PartialUserService that creates a UserService.

DeltaSpike custom ConfigSource with CDI

I am trying to define a custom DeltaSpike ConfigSource. The custom config source will have the highest priority and check the database for the config parameter.
I have a ConfigParameter entity, that simply has a key and a value.
#Entity
#Cacheable
public class ConfigParameter ... {
private String key;
private String value;
}
I have a #Dependent DAO that finds all config parameters.
What I am trying to do now, is define a custom ConfigSource, that is able to get the config parameter from the database. Therefore, I want to inject my DAO in the ConfigSource. So basically something like
#ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {
#Inject
private ConfigParameterDao configParameterDao;
....
}
However, when registering the ConfigSource via META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource, the class will be instantiated and CDI will not work.
Is there any way to get CDI working in this case?
Thanks in advance, if you need any further information, please let me know.
The main problem is, that the ConfigSource gets instantiated very early on when the BeanManager is not available yet. Even the JNDI lookup does not work at that point in time. Thus, I need to delay the injection/lookup.
What I did now, is add a static boolean to my config source, that I set manually. We have a InitializerService that makes sure that the system is setup properly. At the end of the initialization process, I call allowInitialization() in order to tell the config source, that the bean is injectable now. Next time the ConfigSource is asked, it will be able to inject the bean using BeanProvider.injectFields.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
#Inject
private ConfigParameterProvider configParameterProvider;
#Override
public int getOrdinal() {
return 500;
}
#Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
I have a request-scoped bean that holds all my config variables for type-safe access.
#RequestScoped
public class Configuration {
#Inject
#ConfigProperty(name = "myProperty")
private String myProperty;
#Inject
#ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
When injecting the Configuration class in a different bean, each ConfigProperty will be resolved. Since my custom DatabaseConfigSource has the highest ordinal (500), it will be used for property resolution first. If the property is not found, it will delegate the resolution to the next ConfigSource.
For each ConfigProperty the getPropertyValue function from the DatabaseConfigSource is called. Since I do not want to retreive the parameters from the database for each config property, I moved the config property resolution to a request-scoped bean.
#RequestScoped
public class ConfigParameterProvider {
#Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
#PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
I could sure change the request-scoped ConfigParameterProvider to ApplicationScoped. However, we have a multi-tenant setup and the parameters need to be resolved per request.
As you can see, this is a bit hacky, because we need to explicitly tell the ConfigSource, when it is allowed to be instantiated properly (inject the bean).
I would prefer a standarized solution from DeltaSpike for using CDI in a ConfigSource. If you have any idea on how to properly realise this, please let me know.
Even though this post has been answered already I'd like to suggest another possible solution for this problem.
I managed to load properties from my db service by creating an #Signleton #Startup EJB which extends the org.apache.deltaspike.core.impl.config.BaseConfigSource and injects my DAO as delegate which I then registered into the org.apache.deltaspike.core.api.config.ConfigResolver.
#Startup
#Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);
private #Inject PropertyService delegateService;
#PostConstruct
public void onStartup() {
ConfigResolver.addConfigSources(Collections.singletonList(this));
logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
}
#Override
public Map<String, String> getProperties() {
return delegateService.getProperties();
}
#Override
public String getPropertyValue(String key) {
return delegateService.getPropertyValue(key);
}
#Override
public String getConfigName() {
return DatabaseConfigSourceBean.class.getSimpleName();
}
#Override
public boolean isScannable() {
return true;
}
}
I know that creating an EJB for this purpose basically produces a way too big overhead, but I think it's a bit of a cleaner solution instead of handling this problem by some marker booleans with static accessors ...
DS is using the java se spi mechanism for this which is not CD'Injectable'. One solution would be to use the BeanProvider to get hold of your DatabaseConfigSource and delegate operations to it.

Categories