How to use field in #Component class simultaneously? - java

Following this code:
#Component
public class ClassC extends ClassA<T> implements ClassB {
private String preferredDateTimeFormat = null;
My process is using this class after calling a request from client.
Per each request I want to keep the preferredDateTimeFormat value, what is actually being made that, the preferredDateTimeFormat variable is being used for all of my requests.
What can I do to solve it?

Use #Scope on your class with value = request
like this
#Component
#Scope(value="request", proxyMode =ScopedProxyMode.TARGET_CLASS)
public class ClassC extends ClassA<T> implements ClassB {
private String preferredDateTimeFormat = null;
You can find more information on Spring Bean Scopes here

There are multiple ways.
You can define a Request Scope bean and place the preferredDateTimeFormat there.
OR
You can define ThreadLocal property and place the value there.

I'm not entirely sure if you mean you want a ClassC instance per request or a new instance everytime it is used but you might want to look into the #Scope annotation with its values Prototype and Request.
See Spring Bean Scopes.

Related

How to initialize a variable in a Service class

I have a Spring Service class and I want to put a static variable in it that will be initialized with values once when the Service is created by Spring by Autowired.
I want to achieve something like this:
#Service
public class MyServiceImpl implements IService {
public static HashMap<String,String> settings = new HashMap<String,String>();
public MyServiceImpl() {
settings.put("key1","value1");
settings.put("key2","value2");
}
And then when I Autowired that Service the variable will be initialized just once.
Is there any solution how to achieve that?
You can use #PostConstruct:
#PostConstruct
private void init() {
//fill values into map here
}
Spring Beans' default scope is singleton, so you can use constructor and #PostConstruct as well as InitializingBean interfaces or static initializer.
Some suggestion: dont use static variable if not necessary, it is not a good practice, easy to create memory leak etc. If you try to get the map before spring container initialize the bean, it will be empty and other problems can occure.

Getting Spring beans by method invocation vs new operator

I am confused about this little topic. Somewhere I read that if a class is annotated with #Component, it is spring managed bean and whenever it is required, spring will provide it. I am confusing it with scope of a bean. Let me explain:
Let's say a class
#Component
public class Example{ }
If I instantiate this class in other class using new Example(), would container always provide me the same Example object all the time? Or would it return me new object every time?
Here comes the confusing part:
If in the same class I have two beans like this:
#Component
public class Example {
#Bean DataSource sqlDataSource() {
// some logic
}
#Bean #Scope("prototype") SomeObject getSomeObject() {
return new SomeObject(sqlDataSource()); //**
}
}
What will happen in this case? sqlDataSource() method invocation would return the same object again and again every time SomeObject bean is requested, or new instance of DataSource will be returned every time SomeObject is requested?
#Bean is a method-level annotation that indicates Spring to create a bean when that method is invoked. It means to have the same functionality thatn tag in XML config.
This annotation must be used inside of a #Configuration annotated class, otherwise if you invoke the method from another method it will be a normal java new operation, not spring's. See this post --> #Bean inside class with #Configuration and witout it
Bearing this in mind new SomeObject(sqlDataSource()); would be equal to new SomeObject(new SqlDataSource());
if you annotate Example with #Configuration what will happen is that you'll get always a new SomeObject instance with the same sqlDataSource object, this means that Spring will take care of creating ONLY ONE sqlDataSource because it is singleton.
#Bean DataSource sqlDataSource() {
// some logic
}
This defines a singleton instance of DataSource. So everytime you request an instance of SomeObject a new SomeObject will be created (while it is defined in the prototype scope) but all of them will share the same DataSource object (since it's a singleton bean).

How can I autowired attributes of object which I created manually?

I have class which I created manually using new, because I needed to pass it some objects (not beans). It has 2 objects tough which I want to be autowired by spring. This is my class:
#Component
#Scope("prototype")
public class DayLayout extends VerticalLayout {
#Autowired
private SchedulingService schedulingService;
#Autowired
private GeneralService generalService;
.
.
.
}
But after creation of the class those objects are still null. I think it is because I have not obtained that bean via spring container. But is there any way how can I create object manually and all it's objects will be still autowired ?
So if you need to inject Autowired properties to an object created via new you could do the following:
DayLayout dl = new DayLayout(<whatever parameters go here>);
ctx.getAutowireCapableBeanFactory().autowireBean(dl); // Where ctx is Spring's application context
But if you need to do such things I think you might rethink what you are actually doing in your application.
Assuming that GeneralService is not a class annotated with #Component or other Spring stereotypes annotations: yes, there is.
#Configuration
public class ConfigClasses{
#Bean
public GeneralService generalService(){
return new GeneralService();
}
}
Obviously the same for SchedulingService, just add another method which produces that class.
I think you are misunderstanding some part of managed objects, but I am not sure what part that is.
Since you annotated the bean as #Prototype I assume you realize Spring will instantiate a new instance for you every time you request one. It would then be a trivial matter to call setters for your non-managed objects. You could even add a belt and suspenders approach and have your bean throw a IllegalStateException if the setters have not been called.
#Ivan is exactly correct on how you can manually request a bean. He is also exactly correct that if you are resorting to that your design is probably not the best.
If you do : Object obj = new Object(); , it won't autowire. If you want to create manually your object, you can use a config file with #Configuration and return a #Bean. https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html . If that is not what you want, can you provide how you create those two objects ? What do you pass to them ?

Why in Spring I am not allowed to annotate a final class with #Configuration?

I am studying for the Spring Core certification and I have some doubts related to the answer of this question founded on the study material stuff.
Why are you not allowed to annotate a final class with #Configuration
My reasoning is the following one for substantiate this assertion:
Consider the following configuration class:
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository();
}
#Bean
public TransferService transferService() {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(accountRepository());
return service;
}
#Bean
public AccountService accountService() {
return new AccountServiceImpl(accountRepository());
}
At first look this situation could appear strange because the first method (accountRepository()) instantiates an JdbcAccountRepository object as a bean having id=AccountRepository that, following the Spring default behavior, is a singleton
The second and the third method call twice more time the accountRepository() method that should instantiate twice more JdbcAccountRepository objects and this is not possibile because it is singleton !!!
So, to solve this situation Spring use the Inheritance-based Proxies strategy that expect to create a child class of my configuration class (the one annoted by #Configuration) and it is does:
For each bean, an instance is cached in the child class
Child class only calls super at first instantiation
So the child class is the entry point because the following behavior is implemented by this child class:
public class AppConfig$$EnhancerByCGLIB$ extends AppConfig {
public AccountRepository accountRepository() {
// if bean is in the applicationContext
// return bean
// else call super.accountRepository() and store bean in context
}
public TransferService transferService() {
// if bean is in the applicationContext, return bean
// else call super.transferService() and store bean in context
}
.....................................................
.....................................................
.....................................................
}
So if I annotate a configuration class with final Spring can't have this behavior because in Java a final class cannot be subclassed
Is it correct?
Using the same reasoning can I also assert that in Spring I can't have a final method annoted with #Bean annotation?
Because, as shown in the previous example, I have that when at startup time is created the child class (the proxy) of my configuration class happens that for each bean, an instance is cached in the child class and if it is final it is not possible (but I am absolutly not sure about this assertion)
Am I missing something? Can you give me the exact explaination?
Tnx
Spring creates dynamic proxies for classes annotated with #Configuration classes. Spring uses CGLIB to extend your class to create proxy. Hence, configuration classes cannot be final.
Regarding accountRepository() being invoked twice:
If you invoke accountRepository() method to create an instance, it is no more a Spring managed bean. Spring will not have any idea of the instances created in this manner. Hence, you will end up with multiple instances of JdbcAccountRepository
You can preserve the singleton behavior if you configure as below:
#Bean
public TransferService transferService(JdbcAccountRepository jdbcAcctRepo) {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(jdbcAcctRepo);
return service;
}
#Bean
public AccountService accountService(JdbcAccountRepository jdbcAcctRepo) {
return new AccountServiceImpl(jdbcAcctRepo);
}

Losing Class Custom Annotation For Proxy Classes

I am using Seam to inject beans to my controller using #In annotation. The injected class has a custom annotation, when calling injectedClass.getClass().getAnnotation(annotationClass) it returns null.
When debug I found that Seam passes a proxy instance so getClass() returns InjectedClass_$$_javassist_seam_5 which doesn't have my custom annotation.
How I can get my custom annotation from the proxy class?
Here's how my classes look like:
#CustomAnnotation(value="myvalue")
#Name("myAnnotatedClass")
public class MyAnnotatedClass extends SuperClass {...}
#Scope(ScopeType.SESSION)
#Name("myController")
public class MyController {
#In("#{myAnnotatedClass}")
private MyAnnotatedClass myAnnotatedClass;
public void actionMethod(){
//call another class which call myAnnotatedClass.getClass().getAnnotation(CustomAnnotation.class)
//then do some reflection for MyAnnotatedClass fields
}
}
Good question.
When you call a method by using Seam, it is intercepted by a proxy. And this one enables #In or #Out-jection. But There is an exception to this rule: it does not work when you call an internal method
So try this code
#Name
public class Service {
#In
private MyAnnotatedClass myAnnotatedClass;
public void myInterceptedMethod() {
// internal method bypass interceptor
// So #In or #Out-jection is not enabled
internalMethod();
}
private void internalMethod() {
System.out.println(myAnnotatedClass.getClass().getAnnotation(annotationClass));
}
}
Added to original answer
You want to retrieve an annotation from your bean. But, because of method interceptor, myAnnotatedClass.getClass() returns a proxy object, not the bean class itself.
For each bean class, Seam creates a Component definition, in which is stored in the application context. The name of the attribute follows this pattern: component name plus .component. So if you have a bean like this one
#Name("myBean")
public class MyBean {
}
Its Componet definition is stored in the attribute myBean.component
So inside your method, you can use
Component myBeanComponentDefinition = (Component) Context.getApplicationContext().get("myBean.component");
Now you can call
myBeanComponentDefinition.getBeanClass().getAnnotation(CustomAnnotation.class);
regards,
If you want less "ComponentDefinition" overbloat, you could also use this which also works for CDI and Spring:
Class.forName(myBean.getClass().getCanonicalName().substring(0,myBean.getClass().getCanonicalName().indexOf("$"))).getAnnotation(MyAnnotation.class)

Categories

Resources