Is static initialization happend after Bean initialization in spring - spring

I have created a Service to get bean by class name.
package com.ril.service.promise.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
#Component
public class BeanService {
private static ApplicationContext applicationContextStatic;
#Autowired
BeanService(ApplicationContext applicationContext) {
applicationContextStatic = applicationContext;
}
public static <T> T getBean(Class<T> className) {
return applicationContextStatic.getBean(className);
}
}
And I am initializing a static variable link this.
import java.time.LocalDateTime;
import java.util.*;
public class Mapper {
private static Logger LOGGER = LoggerFactory.getLogger(Mapper.class);
private static PEConfigService peConfigService = BeanService.getBean(PEConfigService.class);
}
In mapper, as you see I am getting Bean in Mapper which is not spring bean class and setting it to a static variable.
The above code is working fine for me.
But I want to know will it fine always?

When you fire up a JVM and load a class for the first time (this is done by the class loader when the class is first referenced in any way) any static blocks or fields are 'loaded' into the JVM and become accessible.
So in your case the Mapper class is not reference as part of spring initialization class hence the static variables defined is not yet loaded.
You can find this reference link which could be helpful.
How static Variables loaded at run time

Related

Is there any way to inject system variables into a Spring library?

I have created a Java library that I want to call from Spring applications.
The library has some #Value parameters, which are to be populated from system variables that we pass in to the calling application via -D arguments. In addition, it has an #EnableConfigurationProperties that points to some Autowired configuration beans.
However when I call the library from a consumer application with the appropriate system variables supplied, the Spring #Value parameters do not get populated, and the beans do not get wired; they all come up null.
How can I inject the system variables from the consumer application into the Spring library classes?
Here is the main library code:
Here is the library configuration class
Spring has support for Environment.
Injecting Environment bean
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class MyEnvironment{
#Autowired
private Environment env;
public String getProp() {
return env.getProperty("my.app.prop");
}
}
Implement EnvironmentAware
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
#Component
public class MyEnvironment implements EnvironmentAware {
private String prop;
#Override
public void setEnvironment(Environment env) {
this.prop= env.getProperty("my.app.prop);
}
public String getProp() {
return prop;
}
public void setProp(String prop) {
this.prop= prop;
}
}

How to make Spring IoC container available through out project

I feel stupid to even ask for this but I spent days looking for the answer and I'm still with nothing.
I wanna include simple Spring IoC container in my project. All I want it to do is to allow me Injecting/Autowiring some reusable objects in other classes. What I've done so far looks like this:
-> Project structure here <-
Configuration code:
package com.example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import java.util.Random;
#Configuration
#ComponentScan(basePackages = "com.example")
public class AppConfig {
#Bean
public Random rand() {
return new Random(42);
}
#Bean
public String string() {
return "Hello World!";
}
}
Main class code:
package com.example;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class Main {
#Autowired
Random rand;
#Autowired
String string;
public static void main(String[] args) {
// workflow
Main main = new Main();
System.out.println(main.string);
}
}
AnotherClass code:
package com.example.deeperpackage;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Random;
public class AnotherClass {
#Autowired
Random rand;
#Autowired
String string;
public void methodToBeCalled() {
// TODO
System.out.println(string);
}
}
How can I make these #Autowired annotations work? Do I have to instantiate container in every single class in which I want to autowire components? I've seen in work a oracle app which used Spring and #Inject to distribute objects to numerous classes and there was no container logic in any class available for me. Just fields with #Inject annotation. How to achieve that?
Simply add the annotation #Component on the classes you want to inject :
#Component
public class AnotherClass {
...
}
But you cannot inject static attributes and when you do new Main(), no Spring context is being created. If you use Spring Boot, you should look at how to write a main with it.
https://spring.io/guides/gs/spring-boot/

Autowire working in unit test but not in main java class

I've a domain class that I want to auto-populate from external config. Here is my domain class:
#Data
#Configuration
#PropertySource("classpath:application.properties")
public class StudioVo {
#Value("${studio.code}")
private code;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Here is my context xml:
<bean class="org.springframework.batch.core.scope.StepScope" />
<bean id="ItemReader" class="com.sdm.studio.reader.StudioReader" scope="step">
<property name="studioVo" ref="StudioVo" />
</bean>
<bean id="StudioConfigVo" class="com.sdm.studio.domain.StudioVo" />
</bean>
Here is the class where I want to use the vo:
#Slf4j
#Data
public class StudioReader implements ItemReader<List<Studio>> {
private StudioVo studioVo;
public List<Studio> read() throws Exception {
System.out.println("getCode: " + studioVo.getCode()); //code is null here
return null;
}
}
However when I run it via unit test by autowiring, it runs fine. Like this:
#RunWith(SpringRunner.class)
#SpringBootTest
public class StudioTest {
#Autowired
private StudioVo studioVo;
#Test
public void testAutoPopulationOfStudio(){
System.out.println("getCode: "+ studioVo.getCode()); // works!
// Assert.assertTrue(studioVo.getCode().equals("102"));
}
}
Not sure what's going on here - I'm working with an old Spring Batch application wrapped in Spring Boot (so there is a mix of XML based and Java based config - and may be that is the cause of this issue). What am I missing?
In your StudioTest, you are autowiring StudioReader where as you missed the #Autowired in your StudioReader code, so add it as shown below:
#Slf4j
#Data
public class StudioReader implements ItemReader<List<Studio>> {
#Autowired //add this so that studioVo can be injected
private StudioVo studioVo;
//add other code
}
Please be certain to note that using #Autowire requires a chain of Spring-managed beans below it from wherever you are using it including the class in which you are using #Autowire. That is because Spring needs the precedent references to match up the object-reference hierarchy. I.e., in business logic layer ClassA, you want to #Autowire a field. ClassA itself needs to be a managed bean. Further, if the field you want to #Autowire holds an object that has referential dependencies to other objects (and most do), these also must be Spring-managed.
For example, the following will work:
package com.example.demo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MessageRunner {
private static SetterMessage setterMessage;
public static void main(String[] args) {
setterMessage = (SetterMessage) (new AnnotationConfigApplicationContext(DemoConfiguration.class)).getBean("setterMessage");
setterMessage.setMessage("Finally it works.");
p(setterMessage.getMessage());
}
private static void p(String s) {
System.out.println(s);
}
}
DemoConfiguration.java looks like this:
package com.example.demo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration
#ComponentScan(basePackages = "com.example.demo")
public class DemoConfiguration {
}
SetterMessage.java, this:
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class SetterMessage {
private String message = null;
#Autowired
private SetterMessage2 setterMessage2;
public String getMessage(){
return message+setterMessage2.getSubMessage();
}
public void setMessage(String message) {
this.message = message;
setterMessage2.setSubMessage("("+message+")");
}
}
SetterMessage2.java:
package com.example.demo;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
#Service
#Scope("prototype")
public class SetterMessage2 {
private String subMsg = "";
public void setSubMessage(String msg) {
subMsg = msg;
}
public String getSubMessage() {
return subMsg;
}
}
Note that SetterMessage2.java is annotated as a Component (#Service) but no field in it is autowired. That is because it's the end of the object reference chain. But because it is a Component, it can be autowired into SetterMessage.java. However look at MessageRunner.java's main() method and field declarations. Note that the class field SetterMessage is NOT autowired. If it were annotated as #Autowired, main() would fail at runtime, throwing an NPE with the reference to setterMessage in main(). This is because MessageRunner.java is not marked as some kind of component. So we need to grab a valid instance of MessageSetter from the application context and use it.
To emphasize, the following version of MessageRunner.java's main() method WILL FAIL, throwing an NPE, if MessageRunner.java looked like this:
...
public class MessageRunner {
#Autowired // <-- This will not do the job for us
private static SetterMessage setterMessage;
public static void main(String[] args) {
setterMessage.setMessage("Finally it works."); // NPE here on ref to setterMessage
p(setterMessage.getMessage());
}
...
This is a real gotchya for people new to Spring. In fact, I'd place it among the Top Five Spring Newbie Discouragers and a really evil, pernicious detail that has caused new Spring programmers countless hours in aggravation and Google searches. So I do hope that noting this phenom here will save at least some newbies time and high blood pressure spikes.
Note: If you go to create the above classes in your IDE, bear in mind these were developed with Spring Boot enabled.

Spring JsonExceptionMapper ExceptionMapper handling.

I am getting following error in my weblogic console when i am starting my server.
SEVERE: Missing dependency for constructor
public com.test.mine.exception.JsonExceptionMapper(java.lang.String,com.fasterxml.jackson.core.JsonLocation) at parameter index 0
SEVERE: Missing dependency for constructor public com.test.mine.exception.JsonExceptionMapper(java.lang.String,com.fasterxml.jackson.core.JsonLocation) at parameter index 1
Below is my java code.
package com.test.mine.exception;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ExceptionMapper;
import javax.ws.rs.ext.Provider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;
#Provider
#Service
public class JsonExceptionMapper extends JsonParseException implements ExceptionMapper {
public JsonExceptionMapper(String msg, JsonLocation loc) {
super(msg, loc);
// TODO Auto-generated constructor stub
}
private static final Logger LOGGER = LoggerFactory.getLogger(JsonExceptionMapper.class);
protected Logger getLogger() {
return LOGGER;
}
public Status getStatus(JsonParseException thr) {
return Status.BAD_REQUEST;
}
#Override
public Response toResponse(Throwable arg0) {
// TODO Auto-generated method stub
return Response.status(Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).build();
}
}
The annotation #Service tells spring to create a singleton of the annotated class. At startup spring tries to create that instance and to provide the required constructor args String msg, JsonLocation loc which it does not find, so the exception.
JsonExceptionMapper does not look like a service, and it should not be a singleton. Instead it must be created whenever an exception is created.
I have never worked with that class, so sorry, cannot give you any advice on how to do that.
I bumped into a similar problem while configuring swagger to work with Jersey. After searching various forums found that Jersey scanning require a constructor without parameters. I added a a constructor and it worked for me.

Loading properties using #Value into a BeanFactory object using #Bean in Spring Boot

Can anyone help me with a Spring Boot problem?
I want to create a factory bean as part of my application context but I want to be able to instantiate it with injected property values. However it seems that Spring will load FactoryBeans before anything else as demonstrated here:
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
#EnableAutoConfiguration
public class TestClass
{
#Value("${test.value}")
String value;
#Bean
public Object test1()
{
System.out.println("test.value=" + value );
List<String> list = new ArrayList<String>();
ListFactoryBean factory = new ListFactoryBean();
factory.setSourceList(list);
return factory;
}
public static void main(String[] args)
{
SpringApplication.run(TestClass.class, args);
}
}
When run with
java -Dtest.value=HELLO -jar myTest.jar
It loads in the value correctly:
test.value=HELLO
However, when I specify that the bean to be loaded is in fact a factory bean, and run it in the same way:
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.AbstractFactoryBean;
import org.springframework.beans.factory.config.ListFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
#EnableAutoConfiguration
public class TestClass
{
#Value("${test.value}")
String value;
#Bean
public AbstractFactoryBean test1()
{
System.out.println("test.value=" + value );
List<String> list = new ArrayList<String>();
ListFactoryBean factory = new ListFactoryBean();
factory.setSourceList(list);
return factory;
}
public static void main(String[] args)
{
SpringApplication.run(TestClass.class, args);
}
}
The value is null because it hasn't been injected yet.
test.value=null
Is there any way around this?
Thanks
Spring often has to query bean definitions for the type of object they produce. Factory beans are always problematic because they can cause dependency cascades in a futile attempt to resolve all dynamic information available before asking for the type.
I think ListFactoryBean is insufficiently precise about its product type (getObjectType() can only return a non-generic List.class). You might be able to write your own factory that is parameterized with the correct generic type. Or you might get away with just declaring the #Bean to return a FactoryBean<List<String>.
Another tip is to move the #Bean definition to a separate class (e.g. a nested static one) so that it can be instantiated independently of the rest of the application context. E.g.
#EnableAutoConfiguration
public class TestClass
{
protected static class NestedConfiguration {
#Value("${test.value}")
String value;
#Bean
public FactoryBean<Properties> test1()
{
System.out.println("test.value=" + value );
// ...
return factory;
}
}
...
}
Not really a Boot question this one so you might consider changing the tags.
Take look at Empowering your apps with Spring Boot's property support
There is new annotation #EnableConfigurationProperties in Spring Boot Actuator
The Spring Environment is a collection of name-value pairs taken from (in order of decreasing precedence)
1) the command line,
2) the external configuration file,
3) System properties,
4) the OS environment.
There is also possible to define application properties (external configuration) in YAML format.

Resources