So my problem is, I have a bean which I would like to inject dynamically based on runtime values. Lets say I have class A which has private variable B. I would like to inject my variable B (upon creation of the bean) via spring with value I got from user (for example). How can I do that ? Should I just use getBean() and then use setter method for my variable or is there any better way ?
EDIT:
#Bean
class A {
private int B;
...
}
main {
context = someContext("myConfigFileWhereBeansAreDefined");
int value = getIntFromUser();
// I want to have myNewBean injected with "value" i got from user
A myNewBean = context.getBean("A");
}
Is it possible to receive annotation value inside a field, that was annotated?
Imagine that I have this interface:
#Target(ElementType.FIELD)
#Retention(RetentionPolicy.RUNTIME)
public #interface MyAnnotation {
String value();
}
And I have such implementation:
class SomeClass {
#MyAnnotation("Annotation")
private MyClass myClass;
}
What I want to understand is: is it possible to receive value of MyAnnotation inside MyClass? I want to implement a method inside class MyClass, which will return a value of assigned annotation. So, that myClass.getAssignedAnnotationValue() will return "Annotation".
If it is not possible, please inform me.
is it possible to know annotation value inside annotated field
It's not possible.
You may have 2 different classes
class SomeClass {
#MyAnnotation("Annotation")
private MyClass myClass;
public SomeClass(MyClass myClass) {
this.myClass=myClass;
}
}
and
class SomeClassNo Annotation {
private MyClass myClass;
public SomeClassNo(MyClass myClass) {
this.myClass=myClass;
}
}
Then you create an instance of MyClass
MyClass instance = new MyClass();
then 2 classes instances
new SomeClass(instance) and new SomeClassNo(instance) both have reference to the same instance. So the instance does not know whether the reference field annotated or not.
The only case when it is possible is to pass somehow the container reference to MyClass.
There is no straight forward way of implementing what you are asking.
WorkAround:
Limitations:
This workaround doesn't enforce any kind of compile time check and it is completely your responsibility to handle it.
This only works if MyClass is going to be a spring bean.
class MyClass {
public String annotatedValue;
}
You can write a Spring BeanPostProcessor the following way.
public class SampleBeanPostProcessor implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field instanceof MyClass && field.isAnnotationPresent(MyAnnotation.class)) {
String value = field.getDeclaredAnnotation(MyAnnotation.class).value();
((MyClass) field).annotatedValue = value;
return bean;
}
}
return bean;
}
}
The above BeanPostProcessor will be called for every bean during the app start up. It will check all the fields of a given bean to see if the field is of type MyClass. If it is, it will extract the value from the annotation and set it in the annotatedValue field.
The problem with this approach is that you can use MyAnnotation on any property in any class. You cannot enforce the annotation to be used only on MyClass.
I'd like to create a bean based on "which instance of which class the field belongs to (or even, just to which class this field belongs to). Something like:
#Configuration
#ComponentScan
public class MyConfiguration {
#Bean
SomeClass getTheRightInstance(SomeContext someContext) {
if(someContext.getinjectedFieldHostInstance.getId() == 7) {
return new SpecificSomeClassImplForId7();
} else {
return new SomeClass();
}
}
Bean is to be injected into following field:
public class A {
private int final id;
#Inject private SomeClass field;
int getId();
public A() {
id = SerialIdGenerator.getNextID();
}
}
Select bean injected into A's field based on A instance's id
public staitc void main(String[] args) {
A a1 = new A(); // has id '1', gets field injected with SimpleClass
A a2 = new A(); // has id '2', gets field injected with SimpleClass
...
A a7 = new A(); // gets field injected with SpecificSomeClassImplForId7
...
A last= new A(); // has id!=7, gets field injected with SimpleClass
}
The general idea is to have the decision as to which implementation to inject to which field in which class be defined in code.
Can I inject different bean instances to the same field of different instances of the same class? How can you configure it through code?
The bean you define is a Singleton, so its created at Context-Initialization before the app know that anyone might autowire the value. You must create the Bean as Prototype to request the instance on autowire only.
This is still not possible to get infos about the autowire-target. You can use *Aware-interfaces to get
very own unique Beanname
Beanfactory
ApplicationContext
But neither the target of the autowire nor the class of the target.
Notice that: if the autowire-field has been marked as #Lazy and the Bean's scope is Prototype you can elaborate the exact time the bean autowires using the bean's #PostConstruct.
I'm not sure why you want to do that but it seems like a bad idea.
Classes should never configure their behaviour around their caller, it leads to code that is tightly coupled and not very portable.
Instead, you should find out what makes those 2 fields different and refactor them to use 2 different interfaces (which may even have a common super interface in case of shared functionality). Then you can easily provide 2 different implementations for those interfaces. In your case you could also write a class that handles the specific case for id == 7 and the other cases (maybe via delegation) and use another way of configuring the instance either after or while injecting it into A.
I'm not aware of any possibility to do what you want directly.
Edit: After discussing a bit further in the comments and understanding more what you want to accomplish I think having one factory to create A instances would be best:
#Service
class AFactory {
#Autowired
private SpecificSomeClassImplForId7 specificSomeClassImplForId7;
#Autowired
private SomeClass someClass;
public A makeA() {
if(isSpecialA()) {
return new A(specificSomeClassImplForId7);
} else {
return new A(someClass);
}
}
Then you can use this factory in other Spring Beans in your Application to make As.
I have a weird problem. I have created a public interface like this
public interface PricerBeanInterface
{
public static final double TAX = 37.99;
}
and a stateless session bean like this
#Stateless
public class PricerBean implements PricerBeanInterface
{
}
Into the servlet I inject through EJB annotation the interface in this way
#EJB
private PricerBeanInterface pricerBean;
and send the value to the page through the request object
request.setAttribute("tax", PricerBeanInterface.TAX);
In the jsp page I get the value simply doing ${tax}. Unfortunately I don't get the value. Why?
I want to reinject singleton-scoped dependencies into prototype Spring beans, after they have been deserialized.
Say I've got a Process bean, which depends on a Repository bean. The Repository bean is a scoped as a singleton, but the Process bean is prototype-scoped. Periodically I serialize the Process, and then later deserialize it.
class Process {
private Repository repository;
// getters, setters, etc.
}
I don't want to serialize and deserialize the Repository. Nor do I want to put "transient" on the member variable that holds a reference to it in Process, nor a reference to some kind of proxy, or anything other than a plain old member variable declared as a Repository.
What I think I want is for the Process to have its dependency filled with a serializable proxy that points (with a transient reference) to the Repository, and, upon deserialization, can find the Repository again. How could I customize Spring to do that?
I figure I could use a proxy to hold the dependency references, much like . I wish I could use that exact technique. But the proxy I've seen Spring generate isn't serializable, and the docs say that if I use it with a singleton bean, I'll get an exception.
I could use a custom scope, perhaps, on the singleton beans, that would always supply a proxy when asked for a custom-scoped bean. Is that a good idea? Other ideas?
I used this instead, without any proxy:
public class Process implements HttpSessionActivationListener {
...
#Override
public void sessionDidActivate(HttpSessionEvent e) {
ServletContext sc = e.getSession().getServletContext();
WebApplicationContext newContext = WebApplicationContextUtils
.getRequiredWebApplicationContext(sc);
newContext.getAutowireCapableBeanFactory().configureBean(this, beanName);
}
}
The example is for a web environment when the application server serializes the session, but it should work for any ApplicationContext.
Spring provides a solution for this problem.
Take a look at the spring documentation http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/aop.html#aop-atconfigurable.
7.8.1 Using AspectJ to dependency inject domain objects with Spring
...
The support is intended to be used for objects created outside
of the control of any container. Domain objects often fall into
this category because they are often created programmatically
using the new operator, or by an ORM tool as a result of a database query.
The trick is to use load time weaving. Just start the jvm with -javaagent:path/to/org.springframework.instrument-{version}.jar. This agent will recognize every object that is instantiated and if it is annotated with #Configurable it will configure (inject #Autowired or #Resource dependencies) that object.
Just change the Process class to
#Configurable
class Process {
#Autowired
private transient Repository repository;
// getters, setters, etc.
}
Whenever you create a new instance
Process process = new Process();
spring will automatically inject the dependencies.
This also works if the Process object is deserialized.
How about added using aspects to add an injection step when you deserialize the object?
You would need AspectJ or similar for this. It would work very similarly to the #Configurable function in Spring.
e.g. add some advice around the a "private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException" method
This article may also help: http://java.sun.com/developer/technicalArticles/Programming/serialization/
I think the idea of serializing a bean and then forcing a reinjection of dependencies is not the best architecture.
How about having some sort of ProcessWrapper bean instead which could be a singleton. It would be injected with the Repository and either manages the deserialization of the Process or has a setter for it. When a new Process is set in the wrapper, it would call setRepository() on the Process. The beans that use the Process could either be set with the new one by the wrapper or call the ProcessWrapper which would delegate to the Process.
class ProcessWrapper {
private Repository repository;
private Process process;
// getters, setters, etc.
public void do() {
process.do();
}
public void setProcess(Process process) {
this.process = process;
this.process.setRepository(repository);
}
}
Answering my own question: how I've solved the problem so far is to create a base class which serializes and deserializes using a cheap little proxy. The proxy contains only the name of the bean.
You'll note that it uses a global to access the Spring context; a more elegant solution might store the context in a thread-local variable, something like that.
public abstract class CheaplySerializableBase
implements Serializable, BeanNameAware {
private String name;
private static class SerializationProxy implements Serializable {
private final String name;
public SerializationProxy(CheaplySerializableBase target) {
this.name = target.name;
}
Object readResolve() throws ObjectStreamException {
return ContextLoader.globalEvilSpringContext.getBean(name);
}
}
#Override
public void setBeanName(String name) {
this.name = name;
}
protected Object writeReplace() throws ObjectStreamException {
if (name != null) {
return new SerializationProxy(this);
}
return this;
}
}
The resulting serialized object is 150 bytes or so (if I remember correctly).
The method applicationContext.getAutowireCapableBeanFactory().autowireBean(detachedBean); can be used to reconfigure a Spring-managed bean that was serialized and then de-serialized (whose #Autowired fields become null). See example below. The serialization details are omitted for simplicity.
public class DefaultFooService implements FooService {
#Autowired
private ApplicationContext ctx;
#Override
public SerializableBean bar() {
SerializableBean detachedBean = performAction();
ctx.getAutowireCapableBeanFactory().autowireBean(detachedBean);
return detachedBean;
}
private SerializableBean performAction() {
SerializableBean outcome = ... // Obtains a deserialized instance, whose #Autowired fields are detached.
return outcome;
}
}
public class SerializableBean {
#Autowired
private transient BarService barService;
private int value;
public void doSomething() {
barService.doBar(value);
}
}