in my resources/application.properties, I have:
classa.keypath=${user.home}/App/jsonfile.json
classa.attribute=TEST
in my ClassAConfig() class, I have
#Component
#PropertySource(value="classpath:application.properties")
#ConfigurationProperties(prefix="classa")
public class ClassAConfig{
public static String keypath;
public static String attribute;
//getters
}
and in my ClassA(), I have:
#Service
#EnableConfigurationProperties(ClassAConfig.class)
#Component
#AutoConfigureAfter(ClassAConfig.class)
public class ClassA{
#Autowired
private ClassAConfig ClassAConfig;
private static String keypath;
private static String attribute;
#Autowired
public ClassA(ClassAConfig ClassAConfig){
this.keypath=ClassAConfig.getKeypath();
this.attribute=ClassAConfig.getAttribute();
System.out.println(keypath);
//prints out null
}
}
Why is it printing null?
Related
This is what I want:
import com.abc.ClassA;
public class TestClass {
private ClassA firstClass;
private com.xyz.ClassA secondClass;
}
This is what I got:
public class TestClass {
private com.abc.ClassA firstClass;
private com.xyz.ClassA secondClass;
}
I am using com.helger.jcodemodel with CodeModel.ref("com.abc.ClassA") and CodeModel.ref("com.xyz.ClassA")
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have an abstract class with some configuration properties value which are set using #Value. I want to reuse the abstract class but with another set of configuration properties. The issue is that, those properties value have already been set in the abstract class and all of the concrete classes have inherited it.
I have thought about:
creating another set of config values in the abstract class, but that seems to be creating duplicate, but this is not quite extensible when in future there is yet a third set of config values.
changing the accessibly of the config value in the abstract class from private to protected and have the concrete class to override it. But I'm not sure this kind of overriding is good as it seems create confusion as to what is the actual config value.
create another abstract class which is similar as "AbstractService" but injecting the different set of config value using #Value. This also seems to create duplication.
public abstract class AbstractService {
#Value("${config1}")
private String config1;
#Value("${config2}")
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class concreteServiceA extends AbstractService {
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class concreteServiceB extends AbstractService {
public void serviceB() {
// using serviceMethod in the abstract class
}
}
Would it be a good way if using constructor to pass the required parameters in the abstract class, and let the concrete classes to use constructor injection and #Value to set those values ? though if there are long list of config values this may not scale well.
public abstract class AbstractService {
private String config1;
private String config2;
public AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
public void serviceMethod() {
//using config1 and config2 values
}
}
public concreteServiceA extends AbstractService {
public concreteServiceA(#Value("${config1}") String config1,
#Value("${config2}") String config2) {
super(config1, config2);
}
public void serviceA() {
//using serviceMethod in the abstract class
}
}
public concreteServiceB extends AbstractService {
public concreteServiceB(#Value("${configB1}") String config1,
#Value("${configB2}") String config2) {
super(config1, config2);
}
public void serviceB() {
//using serviceMethod in the abstract class
}
}
You can go like following:
public abstract class AbstractService {
public void serviceMethod() {
String config1 = getConfig1();
String config2 = getConfig2();
//using config1 and config 2 values
}
public abstract String getConfig1();
public abstract String getConfig2();
}
public class concreteServiceA extends AbstractService {
#Value("${config1}") private String config1;
#Value("${config2}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceA() { // using serviceMethod in the abstract class }
}
public class concreteServiceB extends AbstractService {
#Value("${config1.1}") private String config1;
#Value("${config2.1}") private String config2;
public String getConfig1(){
return config1;
}
public String getConfig2(){
return config2;
}
public void serviceB() { // using serviceMethod in the abstract class }
}
You could either use setter injection or (probably more elegant) constructor injection like this:
public abstract class AbstractService {
protected AbstractService(String config1, String config2) {
this.config1 = config1;
this.config2 = config2;
}
private String config1;
private String config2;
public void serviceMethod() {
//using config1 and config 2 values
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${config1a}") String config1, #Value("${config2a}") String config2) {
super(config1, config2);
}
public void serviceA() {
// using serviceMethod in the abstract class
}
}
public class ConcreteServiceB extends AbstractService {
public ConcreteServiceB(#Value("${config1b}") String config1, #Value("${config2b}") String config2) {
super(config1, config2);
}
public void serviceB() {
// using serviceMethod in the abstract class
}
}
But if you have lots of values you can also use setter injection and override the setters in each subclass. Or you can still use constructor injection but pass a container class holding the config like this:
public class ServiceConfig {
private String config1;
private String config2;
// getters, setters and more properties
}
Then pass it like this
public abstract class AbstractService {
private ServiceConfig config;
protected AbstractService(ServiceConfig config) {
this.config = config;
}
}
public class ConcreteServiceA extends AbstractService {
public ConcreteServiceA(#Value("${configA}") ServiceConfig config) {
super(config);
}
}
You can externalize your properties to specific beans which will be autowired to the concrete classes.
Spring annotation #ConfigurationProperties allows you to initialise simple POJO properties based on properties prefix.
First create your POJO which we will inject in the concrete services :
public class ServiceProperties {
private String config1;
private String config2;
//getters and setters
}
Then create a configuration class in a package scanned by spring :
#Configuration
public class ServicePropertiesConfiguration {
#Bean
#ConfigurationProperties(prefix = "service-a")
public ServiceProperties serviceAProperties() {
return new ServiceProperties();
}
#Bean
#ConfigurationProperties(prefix = "service-b")
public ServiceProperties serviceBProperties() {
return new ServiceProperties();
}
}
As you can see, prefix tells to spring where he has to search the properties. Your application.properties will look like this :
service-a.config1=serviceAConfig1
service-a.config2=serviceAConfig2
service-b.config1=serviceBConfig1
service-b.config2=serviceBConfig2
At this stage, you will have two beans of type ServiceProperties with specific values inside
The abstract service looks like this :
public abstract class AbstractService {
private final ServiceProperties serviceProperties;
protected AbstractService(ServiceProperties serviceProperties) {
this.serviceProperties = serviceProperties;
}
public void serviceMethod() {
//using config1 and config 2 values
// serviceProperties.getConfig1();
// serviceProperties.getConfig2();
}
}
In the concrete service, you have to use #Qualifier annotation with name of created bean
#Service
public class ConcreteServiceA extends AbstractService{
public ConcreteServiceA(#Qualifier("serviceAProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}
#Service
public class ConcreteServiceB extends AbstractService{
protected ConcreteServiceB(#Qualifier("serviceBProperties") ServiceProperties serviceProperties) {
super(serviceProperties);
}
}
I am dealing with multiple entity classes but they have the same attributes.
It's not a good data structure but according to my use case, I have to deal with two entities having the same attributes. As of now I am using multiple controllers, multiple request/response and multiple interfaces and implementations to do the logic part and save into the two corresponding tables.
Is there any efficient way that I could combine both into a single interface, with the DB operations happening in multiple DBs.
Following is a sample code:
#RestController
..
public class FooController {
#Autowired
private FooService fooService;
#GetMapping
public FooResponse findFoo(
#PathVariable(FOO_CONSTANT.PATH_VARIABLE_FOO_ID) String fooId)
throws FooException {
return fooService.findFoo(fooId));
}
}
public interface FooService{
FooResponse findFoo(String fooId);
}
#Service
public class ProspectAssetServiceImpl implements ProspectAssetService {
#Autowired
private FooRepository fooRepository;
#Override
public FooResponse findFoo(String fooId){
FooEntity fooEntity = fooRepository.findByFooId(fooId));
return convertBomToMessaging(fooEntity);
}
}
public class Foo {
private String fooId;
private String fooName;
//getters and setters
}
#Entity
#Table(name = "foo_table")
public class FooEntity {
private String fooId;
private String fooName;
//getters and setters
}
Second Service:
#RestController
..
public class ZooController {
#Autowired
private ZooService ZooService;
#GetMapping
public ZooResponse findZoo(
#PathVariable(Zoo_CONSTANT.PATH_VARIABLE_Zoo_ID) String ZooId)
throws ZooException {
return ZooService.findZoo(ZooId));
}
}
public interface ZooService{
ZooResponse findZoo(String ZooId);
}
#Service
public class ProspectAssetServiceImpl implements ProspectAssetService {
#Autowired
private ZooRepository ZooRepository;
#Override
public ZooResponse findZoo(String ZooId){
ZooEntity ZooEntity = ZooRepository.findByZooId(ZooId));
return convertBomToMessaging(ZooEntity);
}
}
public class Zoo {
private String ZooId;
private String ZooName;
//getters and setters
}
#Entity
#Table(name = "Zoo_table")
public class ZooEntity {
private String ZooId;
private String ZooName;
//getters and setters
}
Suggest me an efficient way to combine these two together?
Using Powermock 2.0.7 (powermock-api-mockito2, powermock-core, powermock-module-junit4) and mockito-core (3.3.3). I thought I had created a comparable test scenario in a separate project (which worked), but something else must be missing.
Library class to be mocked:
public class CommonConstants {
private ConfigurationDataImpl configurationData;
private static Properties sysProperties;
private static Map<String, String> sysPermissions;
public CommonConstants(ConfigurationDataImpl configurationData) {
this.configurationData = configurationData;
}
public void init() {
sysProperties = this.configurationData.getSysParams();
sysPermissions = this.configurationData.getSysPermissions();
}
public static String getSysProperties(String key) {
return sysProperties.getProperty(key);
}
public static String getSysPermissions(String key) {
return (String)sysPermissions.get(key);
}
}
In my test, I have:
#RunWith(PowerMockRunner.class)
#PrepareForTest({CommonConstants.class}) <==== class that evidently is not modified!
class MyServiceTest {
public MyServiceTest() {}
#Mock
private MyDao myDao;
#InjectMocks
private MyService myService;
#Test
void retrieveUsers() {
RequestPayload rp = returnPayload();
PowerMockito.mockStatic(CommonConstants.class); <==== EXCEPTION
when(CommonConstants.getSysProperties(HOURS_TO_REGISTER)).thenReturn("24");
...
In the service code, I have:
#Service
#Slf4j
public class MyService {
MyDao myDao;
public MyService(MyDao myDao) {
this.myDao = myDao;
}
public UserListResponse retrieveUsers(RequestPayload requestPayload, String customer) {
List<User> users = myDao.getPtdUsers(queryParams, customer, totalRecords);
int hoursToExpire = Integer.parseInt(CommonConstants.getSysProperties(HOURS__TO_REGISTER));
...
Am I leaving out something? All help appreciated.
I have a class ResourcesProperties.java
#NoArgsConstructor
#PropertySource("classpath:config.properties")
#Component
public class ResourcesProperties {
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConf() {
return new PropertySourcesPlaceholderConfigurer();
}
public static ResourcesProperties instance;
#Bean
public static ResourcesProperties getInstance() {
if (instance == null)
instance = new ResourcesProperties();
return instance;
}
#Getter
#Value("${room.rightStatusRoom}")
private static boolean rightStatusRoom;
#Getter
#Value("${room.countGuests}")
private static int countGuests;
}
There is a "config.properties" property file
room.rightStatusRoom=true
room.countGuests=101
Why, when accessing the of fields with #Value annotation, they don't return the specified values from property file?
Example:
if(ResourcesProperties.getInstance().isRightStatusRoom()) { //returned false instead true
//business-logic
}
My solution:
#NoArgsConstructor
#PropertySource("classpath:config.properties")
#Component
public class ResourcesProperties {
#Getter
#Value("${room.rightStatusRoom}")
private boolean rightStatusRoom;
#Getter
#Value("${room.countGuests}")
private int countGuests;
}
Spring doesn't allow to inject value into a static object.
So you have 2 options, get rid of the static or call a non-static setter that sets the static variable.
More info can be found here: https://mkyong.com/spring/spring-inject-a-value-into-static-variables/
So these are the solutions.
Solution 1:
#NoArgsConstructor
#PropertySource("classpath:config.properties")
#Component
public class ResourcesProperties {
#Getter
#Value("${room.rightStatusRoom}")
private boolean rightStatusRoom;
#Getter
#Value("${room.countGuests}")
private int countGuests;
}
Solution 2:
#NoArgsConstructor
#PropertySource("classpath:config.properties")
#Component
public class ResourcesProperties {
#Getter
private static boolean rightStatusRoom;
#Getter
private static int countGuests;
#Value("${room.rightStatusRoom}")
public void setRightStatusRoom(boolean rightStatusRoom) {
this.rightStatusRoom = rightStatusRoom
}
#Value("${room.countGuests}")
public void setCountGuests(int countGuests) {
this.countGuests = countGuests
}
}