How to get values from bootstrap.yml file from static instance - java

I have a classes CosmosConnection and SupplierGetResponseFeed
I am calling the method of CosmosConnection from SupplierGetResponseFeed
The method of SupplierGetResponseFeed from which I am calling CosmosConnection method is static
Example : public static SupplierResponseDataEntity prepareSupplierAzureData(Map<String, Object> row, String[] columnNames) {
So , When I create the object of CosmosConnection in SupplierGetResponseFeed I can not use #Autowired as a reason I am not able to pick the value from bootstrap.yml file in CosmosConnection
Though I create the object using #Autowired in SupplierGetResponseFeed I am not able to pick the values from bootstrap
#Autowired
static CosmosConnection cosmos;
Below is the code for SupplierGetResponseFeed
public class SupplierGetResponseFeed {
static CosmosConnection cosmos= new CosmosConnection(); //creating object
public static SupplierResponseDataEntity prepareSupplierAzureData(Map<String, Object> row, String[] columnNames) {
//Some code
cosmos.connectToDB(); //calling the method of CosmosConnection class
}
The code for is CosmosConnection
#Configuration
#ComponentScan
public class CosmosConnection {
#Value("${cosmos.connectionuri}") private String uri;
#Value("${cosmos.primarykey}") private String primarykey;
public String connectToDB() throws DocumentClientException, IOException, ParseException {
System.out.println("URI is " + uri); //getting this as null
What changes I need to do for picking the values from bootstrap.yml ??

A annotation called PostConstruct in package javax.annotation with spring framework can be used to solve the problem. As described in the source code:
The PostConstruct annotation is used on a method that needs to be executed
after dependency injection is done to perform any initialization
And code below is a example:
#Configuration
public class ComosConfig {
#Value("${cosmos.connectionuri}") private String uri;
#Value("${cosmos.primarykey}") private String primarykey;
//get and set methods here
}
public class CosmosConnection {
private String uri;
private String primaryKey;
public CosmosConnection(String uri, String primaryKey) {
this.uri = uri;
this.primaryKey = primaryKey;
}
public String connectToDB() {
//do something here
}
}
#Component
public class SupplierGetResponseFeed {
private static CosmosConnection cosmos;
private CosmosConfig config;
public SupplierGetResponseFeed(CosmosConfig config) {
this.config = config;
}
#PostConstruct
public void init() {
String uri = config.getUri();
String primaryKey = config.getprimaryKey();
cosmos = new cosmos(uri, primaryKey);
}
public static SupplierResponseDataEntity prepareSupplierAzureData() {
cosmos.connectToDB(); //calling the method of CosmosConnection class
}
}
After all, it's not recommended in view of code analysis utils to write to static from instance method, so you may need suppress-warning-annotation used with init method to eliminate warnings.

Related

How to inject value to a bean in spring test?

i have a question here, please give some ideas.
I have two beans. FaceComparisonServerImpl depends on FaceServer.
When i want to test. I want to change the String in my 'FaceServer' bean.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
#Autowired
private FaceServer faceServer;
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
...
}
}
#Component
public class FaceServer {
#Autowired
private RestTemplate restTemplate;
//Not final, just to test.
private String version = "1.0";
private static final String CODE = "code";
private static final String MESSAGE = "message";
//Final
private static final String SERVER_URL = "http://127.0.0.1:8066/api/ZKComparison";
}
Bellow is my test code.
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
#Test
public void getServerInfo(){
//How can i modify the value of SERVER_URL in faceServer?
FaceComparsionInfo serverInfo = faceComparisonServer.getServerInfo();
System.out.println(serverInfo);
}
}
My question is:
How can i modified the value of 'version' and 'SERVER_URL' in #Bean(faceServer)?
Thanks you!
You need create FaceServer mock bean for test configuration.
And override required methods
#Configuration
Class TestConfig{
#Bean
#Primary
public FaceServer faceServer() {
return new FaceServer() {
#override
public String getServerInfo(){
return "required info";
}
};
}
}
The easiest way to customize the values is to make them Spring properties:
#Component
public class FaceServer {
#Value("${faceServer.version}")
private String version;
#Value("${faceServer.url}")
private String serverUrl;
// ...
}
You can either have default values for the #Value annotations or use some default property values in application.yml.
Now just override those properties in your test with the values you want:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = TestConfig.class)
#TestPropertySource(properties = {
"faceServer.version=1.0",
"faceServer.url=http://127.0.0.1:8066/api/ZKComparison"
})
public class FaceServerTestByTyler {
#Autowired
private FaceComparisonServer faceComparisonServer;
// ...
}
However...
The second option is to make your classes more unit-testable. Prefer construction injection over field injection, and you can test your classes more independently.
#Service
public class FaceComparisonServerImpl implements FaceComparisonServer {
private final FaceServer faceServer;
public FaceComparisonServerImpl(FaceServer faceServer) {
this.faceServer = faceServer;
}
#Override
public FaceComparsionInfo getServerInfo() {
String serverInfo = faceServer.getServerInfo();
// ...
}
}
This now becomes unit-testable:
public class FaceServerTestByTyler {
private FaceComparisonServer faceComparisonServer;
private FaceServer faceServer;
#BeforeEach
public setup() {
faceServer = mock(FaceServer.class);
faceComparisonServer = new FaceComparisonServer(faceServer);
}
#Test
public void getServerInfo() {
when(faceServer.getServerInfo()).thenReturn(xxx);
// ...
}
}
The second option ends up with a test that runs much faster than any solutions that suggest to create a mock bean through a test configuration.

Autowired NullPointerException [duplicate]

Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

Getting null pointer in static method Junit

I have following service
public UserActivityLog save(UserActivityLog userActivityLog){
LOGGER.debug("User activity save called.");
userActivityLog.setCreatedByUser(User.getUser().getUserId());
userActivityLog.setCreationTime(new Date());
return activityLogRepository.save(userActivityLog);
}
I had written following Junit for test this but getting null pointer for User
#RunWith(MockitoJUnitRunner.class)
public class ActivityHistoryServiceTest {
#InjectMocks
private ActivityHistoryService activityHistoryService;
#Mock
private ActivityLogRepository activityLogRepository;
#Test
public void testSave() {
UserActivityLog userActivityLog = new UserActivityLog();
/* Called some setter methods to set value here*/
UserProfile profile = new UserProfile();
Mockito.when(User.getUser()).thenReturn(profile);
Assert.assertNotNull(activityLogRepository.save(userActivityLog));
}
}
User class is like
public class User {
private User(){}
public static UserProfile getUser(){
/*some logic*/
return userProfile;
}
}
Please help for this. thanks in advance.
Static methods are useful when they are useful. Use them as a replace for singletons is not a very good practice. Instead of what you have your code could look like this:
public class MyClass {
private final Logger logger;
private final UserProvider userProvider;
private final DateProvider dateProvider;
/** Constructor that sets all attributes */
public MyClass(...) {...}
public UserActivityLog save(UserActivityLog userActivityLog){
LOGGER.debug("User activity save called.");
userActivityLog.setCreatedByUser(userProvider.get().getUserId());
userActivityLog.setCreationTime(dateProvider.get());
return activityLogRepository.save(userActivityLog);
}
}
Provider classes are quite simple. They just have a get() method that returns an instance of required type:
public class DateProvider {
public Date get() {
return new Date();
}
}
public class UserProvider {
public User get() {
...
}
}
With this setup you can easily mock the dependencies
You need PowerMock to mock the static methods.
Refer:
https://blog.codecentric.de/en/2016/03/junit-testing-using-mockito-powermock/

Spring: Use application property inside an autowired constructor that instantiate a final field

I've created the MCVE below. The service should get a message and replace the vowels with a predefined ugly.char coming from application.properties.
application.properties:
ugly.char=x
UglifyService.java:
public interface UglifyService {
String uglifyMessage(String message);
}
UglifyServiceImpl.java:
#Service
public class UglifyServiceImpl implements UglifyService {
#Value("${ugly.char}")
private char uglyCharFromAppProp;
private final char uglyChar;
#Autowired
public UglifyServiceImpl() {
this.uglyChar = uglyCharFromAppProp;
}
#Override
public String uglifyMessage(String message) {
return message.replaceAll("[aeiouAEIOU]", String.valueOf(uglyChar));
}
}
UglyCharController.java:
#Controller
public class UglyCharController {
private final UglifyService uglifyService;
#Autowired
public UglyCharController(UglifyService uglifyService) {
this.uglifyService = uglifyService;
}
#Value("${ugly.char}")
private char uglyChar;
#RequestMapping("/")
#ResponseBody
public String index() {
return "Usage: http://localhost:8080/some-message";
}
#GetMapping("/{message:.+}")
#ResponseBody
public String uglifyMessage(#PathVariable String message) {
String uglyMessage = uglifyService.uglifyMessage(message);
return "The ugly char is: '"+ uglyChar +"'." +
"<br>The uglifyed message is: "+ uglyMessage;
}
}
Application.java:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
The problem is that, instead of replacing the vowels, the service is just removing them.
When requesting localhost:8080/mymessage the response should be mymxssxgx, but I am getting mymssg.
My questions are:
Why the service is not working as expected?
What would be the right way to make it work, considering that I would like the uglyChar to be final inside the singleton service and to come from application.properties?
Note: The service starts to work if I replace String.valueOf(uglyChar) with String.valueOf(uglyCharFromAppProp), but uglyChar would not be final, as I would like it to be.
When object is instantiated, first the constructor is executed and then the values of the properties are set and #Value is executed. For this reason the value of uglyChar does not have the value of the property.
You can do it with:
private final char uglyChar;
#Autowired
public UglifyServiceImpl(#Value("${ugly.char}") final char uglyCharFromAppProp){
this.uglyChar = uglyCharFromAppProp;
}

Can you use #Autowired with static fields?

Is there some way to use #Autowired with static fields. If not, are there some other ways to do this?
In short, no. You cannot autowire or manually wire static fields in Spring. You'll have to write your own logic to do this.
#Component("NewClass")
public class NewClass{
private static SomeThing someThing;
#Autowired
public void setSomeThing(SomeThing someThing){
NewClass.someThing = someThing;
}
}
#Autowired can be used with setters so you could have a setter modifying an static field.
Just one final suggestion... DON'T
Init your autowired component in #PostConstruct method
#Component
public class TestClass {
private static AutowiredTypeComponent component;
#Autowired
private AutowiredTypeComponent autowiredComponent;
#PostConstruct
private void init() {
component = this.autowiredComponent;
}
public static void testMethod() {
component.callTestMethod();
}
}
Create a bean which you can autowire which will initialize the static variable as a side effect.
Wanted to add to answers that auto wiring static field (or constant) will be ignored, but also won't create any error:
#Autowired
private static String staticField = "staticValue";
You can achieve this using XML notation and the MethodInvokingFactoryBean. For an example look here.
private static StaticBean staticBean;
public void setStaticBean(StaticBean staticBean) {
StaticBean.staticBean = staticBean;
}
You should aim to use spring injection where possible as this is the recommended approach but this is not always possible as I'm sure you can imagine as not everything can be pulled from the spring container or you maybe dealing with legacy systems.
Note testing can also be more difficult with this approach.
You can use ApplicationContextAware
#Component
public class AppContext implements ApplicationContextAware{
public static ApplicationContext applicationContext;
public AppBeans(){
}
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
then
static ABean bean = AppContext.applicationContext.getBean("aBean",ABean.class);
Disclaimer This is by no means standard and there could very well be a better spring way of doing this. None of the above answers address the issues of wiring a public static field.
I wanted to accomplish three things.
Use spring to "Autowire" (Im using #Value)
Expose a public static value
Prevent modification
My object looks like this
private static String BRANCH = "testBranch";
#Value("${content.client.branch}")
public void finalSetBranch(String branch) {
BRANCH = branch;
}
public static String BRANCH() {
return BRANCH;
}
We have checked off 1 & 2 already now how do we prevent calls to the setter, since we cannot hide it.
#Component
#Aspect
public class FinalAutowiredHelper {
#Before("finalMethods()")
public void beforeFinal(JoinPoint joinPoint) {
throw new FinalAutowiredHelper().new ModifySudoFinalError("");
}
#Pointcut("execution(* com.free.content.client..*.finalSetBranch(..))")
public void finalMethods() {}
public class ModifySudoFinalError extends Error {
private String msg;
public ModifySudoFinalError(String msg) {
this.msg = msg;
}
#Override
public String getMessage() {
return "Attempted modification of a final property: " + msg;
}
}
This aspect will wrap all methods beginning with final and throw an error if they are called.
I dont think this is particularly useful, but if you are ocd and like to keep you peas and carrots separated this is one way to do it safely.
Important Spring does not call your aspects when it calls a function. Made this easier, to bad I worked out the logic before figuring that out.
Generally, setting static field by object instance is a bad practice.
to avoid optional issues you can add synchronized definition, and set it only if private static Logger logger;
#Autowired
public synchronized void setLogger(Logger logger)
{
if (MyClass.logger == null)
{
MyClass.logger = logger;
}
}
:
Solution 1 : Using Constructor #Autowired For Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
public MyClass(MyService service) {
TestClass.service= service;
}
}
Solution 2 : Using #PostConstruct to set the value to Static Field
#Component
public class MyClass {
private static MyService service;
#Autowired
private MyService srv;
#PostConstruct
public void init() {
this.service= srv;
}
}
Refer here for more detail
I use private static inner Component: FieldSetter, to inject static field: MyBean, at last SelfDestroyBean will help me remove redundant FiledSetter bean
public final class MyClass {
private static MyBean myBean;
#Component
private static class FieldSetter extends SelfDestroyBean {
public FieldSetter(MyBean myBean) {
MyClass.myBean = myBean;
}
}
}
#SuppressWarnings("SpringJavaAutowiredMembersInspection")
public abstract class SelfDestroyBean {
#Autowired
private ApplicationContext context;
#PostConstruct
public void destroy() {
final String[] beanNames = context.getBeanNamesForType(this.getClass());
final BeanDefinitionRegistry registry =
((BeanDefinitionRegistry) context.getAutowireCapableBeanFactory());
for (String beanName : beanNames) {
registry.removeBeanDefinition(beanName);
}
}
}
private static UserService userService = ApplicationContextHolder.getContext().getBean(UserService.class);

Categories

Resources