I have a class which I want to be a bean
public class SomeBean{
public SomeBean(){
//default constructor
}
public SomeBean(String someStr){
//constructor with arguments.
}
}
In order to create manually CDI bean I do the following
Bean<?> bean = (Bean<?>) beanManager.resolve(beanManager.getBeans(SomeBean.class));
SomeBean someBean =(SomeBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
However the above method will create SomeBean instance wth default constructor. How can I create bean and pass String argument to construcot?
P.S. CDI - WELD
The standard way to define beans with given constructor arguments is via a producer method, e.g.
#Produces #ApplicationScoped #MyQualifier
public SomeBean myBean() {
return new SomeBean("foo");
}
Application code should not normally have to use the BeanManager, unless you want to create a CDI extension.
Related
I am using an ObjectProvider to create instances of a prototype scope bean using the getObject() method. Something like this
#Configuration
class Config {
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeOne() {
return new SomeType();
}
#Bean
#Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
SomeType typeTwo(String param) {
return new SomeType(param);
}
}
#Service
class Service {
private ObjectProvider<SomeType> objectProvider;
public Service(
ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
#Override
public String performAction() {
return getSomeType().doAction();
}
private SomeType getSomeType() {
return objectProvider.getObject();
}
}
But since there are two beans of the type that the ObjectProvider is trying to get (SomeType), I get a NoUniqueBeanDefinitionException. (And I do need the other bean of the same type, because that one I need to provide parameters using objectProvider.getObject(Object... params) )
Playing around and debugging Spring I saw that if you name your ObjectProvider exactly like your bean then it works, something like:
private ObjectProvider<SomeType> typeOne;
My question is, are there other ways to use an ObjectProvider and manage to resolve ambiguity, or is this approach the way to go?
Short answer is you just need to properly qualify the ObjectProvider you want injected, like this:
public Service(#Qualifier("typeOne") ObjectProvider<SomeType> objectProvider) {
this.objectProvider = objectProvider;
}
With Spring configuration, when you specify a bean via a method, and don't specify it's name with #Bean("NAME"), Spring uses the method name as the bean name.
Similarly, when injecting a bean that is not specified by #Qualifier("NAME"), Spring takes the injected variable as the name, if that don't exists or is not unique, you might get some exceptions informing you about this (like the NoUniqueBeanDefinitionException you facing).
So, if you match the bean name and the injected variable name you don't need to be more specific, but if you don't, #Qualifier is there to your rescue :D
I've got a Factory class in Java with some methods which return some Java Bean. All of these Java Beans have some DAO object as fields which are injected with the annotation #EJB. However in every case these DAO are all Null, so I suppose I've a problem with EJB injection. I use WebLogic for deploy. Any suggestions to resolve the issue?
//Factory class
public class Factory extends AbstractFactory {
#Override
public InterfaceService getService() {
return new ClassBean();
}
}
//Bean class
#Stateless(mappedName = "ClassBean")
#LocalBean
public class ClassBean implements IBeanService {
#EJB(beanName = "ClassDAO")
private ClassDAO classDAO;
public List<String> getList() throws ExpectedModelException {
return classDAO.getStringList(); //this one throws NullPointerException
}
Never create Enterprise-Beans using new.
The creation, caching, deletion,... is done by the container.
You must declare ClassDao as #Stateless or #Singleton, ... and the container will create and find it, hopefully if the names are correct.
The Factory is not necessary.
I'm defining a Java EE bean as follows:
#LocalBean
#Stateless
public class GreetingBean {
private HelloBean helloBean;
#Inject
public void setHelloBean(HelloBean helloBean) {
this.helloBean = helloBean;
}
// ...
}
And:
#Named
public class HelloBean {
public HelloBean() { // ... }
public HelloBean(String hello) { // ... }
}
Now, how can I inject the GreetingBean into another class by also setting an HelloBean instance for it?
Supposing that I've two different constructors for the HelloBean class (the one with an argument, for instance a String, the other without [default]), how can I properly inject either?
If you have two different constructors, this is very different question from this that you are asking here. In this case the default constructor (without arguments) will be called when HelloBean gets instantiated.
To inject a bean instance using arguments you have to use a producer method which will instantiate HelloBean. More info can be found here and here.
In Spring I have bean that should not be instantiated without a constructor argument which depend on user input. what is the correct way to instantiate the SessionScoped bean in a controller or another Singleton-Scopped bean ?
public class SingletonScoped{
...
}
public class SessionScoped{
#Autowired
SingletonScoped singletonScopped;
private SessionScoped(){
}
public SessionScoped(Object userInput){
}
}
public class AnotherSingletonScoped{
...
}
basically i should add spring argument in serverlet-context.xml then u can passing argument here. A more detail u can see in this post http://chiase.azurewebsites.net/?p=171
I know it's possible to inject a request scoped bean into a singleton bean in Spring so I know what I'm trying to do will work, I'm just wondering if there is a way to express it more concisely without so many extra unnecessary class definitions. I'm new to Spring annotations so maybe there's an annotation I don't know about.
I have an abstract class that will be extended maybe 100 times in my application as different singleton spring beans. Take this class definition for an example:
/** The abstract class with a field that needs to be request-specific **/
public abstract class AbstractSingletonBean {
private SampleState state;
public SampleState getState() { return state; }
public void setState(SampleState state) { this.state = state; }
// Other fields that are just singleton here
}
And an example of what one of the bean definitions might look like:
#Component
public class SampleSingletonBean extends AbstractSingletonBean {
#Resource(name="sampleState")
public void setState(SampleState state) { super.setState(state); }
}
Now of course we need a bean called sampleState. So I have to create two classes: a base class to define the fields in SampleState and then a request-scoped bean definition. This is because each extension of AbstractSingletonBean will need it's own request-scoped instance of the state field.
Here might be the base class:
public class SampleState {
private String fieldOne;
public String getFieldOne() { return fieldOne }
public void setFieldOne() { this.fieldOne = fieldOne }
}
And here is this silly bean definition:
#Component ("sampleState")
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public class SampleStateBean extends SampleState {}
The thing that bothers me is that if I have 100 extensions of AbstractSingletonBean, I'll need 100 extensions of SampleStateBean with just boilerplate code to make it request-scoped. Is there a way to just override setState() in the extensions of AbstractSingletonBean and indicate to spring that it should create a new request scoped bean on the fly and inject it here? So my SampleSingletonBean could look like this:
#Component
public class SampleSingletonBean extends AbstractSingletonBean {
#Resource
#Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)
public void setState(SampleState state) { super.setState(state); }
}
Of course this doesn't work because #Resource needs to refer to a bean that already exists. Is there another annotation to accomplish this without creating a new class for every SampleState bean?
Spring can inject into abstract classes too. So you can move the injection of the SampleState to the abstract class, if each AbstractSingletonBean descendant needs just a SampleState (as in your example).
It doesn't look like this was available out of the box so I created an annotation I call #AnonymousRequest that I put on the field I want, and a BeanDefinitionRegistryPostProcessor to do the work of creating the bean. It basically goes like this:
for each bean in the BeanFactory
if bean class has AnonymousRequest annotation
create request scoped bean from field class
create singleton bean to be request scoped bean wrapper
set the annotated property value to the singleton wrapper
This took a lot of work to figure out how Spring registers request scoped beans. You create the bean definition you want as a request scoped bean. Then you create a singleton bean of type RootBeanDefinition that acts as a wrapper to the request scope bean and set a property on the wrapper called "targetBeanName" to whatever you named the request scoped bean ("scopedTarget." + the singleton bean name by convention).
So this could probably be improved by someone who actually knows this stuff but here's what I came up with:
public void createRequestBeanFromSetterMethod(String containingBeanName, BeanDefinition containingBean, Method method, BeanDefinitionRegistry registry)
{
String fieldName = ReflectionUtil.getFieldNameFromSetter(method.getName());
String singletonBeanName = containingBeanName+"_"+fieldName;
String requestBeanName = "scopedTarget."+singletonBeanName;
BeanDefinition requestBean = createAnonymousRequestBean(ReflectionUtil.getFieldTypeFromSetter(method), containingBean);
RootBeanDefinition singletonBean = new RootBeanDefinition();
singletonBean.setBeanClass(ScopedProxyFactoryBean.class);
singletonBean.getPropertyValues().addPropertyValue("targetBeanName", requestBeanName);
registry.registerBeanDefinition(singletonBeanName, singletonBean);
registry.registerBeanDefinition(requestBeanName, requestBean);
beanDefinition.getPropertyValues().addPropertyValue(fieldName, new RuntimeBeanReference(singletonBeanName));
}
private BeanDefinition createAnonymousRequestBean(Class<?> beanType, BeanDefinition parentBean)
{
BeanDefinition newBean = null;
if (parentBean != null)
{
newBean = new GenericBeanDefinition(parentBean);
}
else
{
newBean = new GenericBeanDefinition();
}
if (beanType != null)
{
newBean.setBeanClassName(beanType.getName());
}
newBean.setScope("request");
newBean.setAutowireCandidate(false);
// This would have come from the Proxy annotation...could add support for different values
String proxyValue = "org.springframework.aop.framework.autoproxy.AutoProxyUtils.preserveTargetClass";
BeanMetadataAttribute attr = new BeanMetadataAttribute(proxyValue, true);
newBean.setAttribute(proxyValue, attr);
return newBean;
}
It seems to work! I effectively have now a request scoped bean created just before the context initialization that is localized to this one containing bean. It's a request-scoped property, more or less.
You can try defining single SampleState request scope bean and then use spring's lookup method to inject this bean wherever you want to.That's works just fine with prototype-scope beans. Fingers crosses it would work with request scope as well.
AFAIK, there is no annotation support for lookup method as of now, so either use it's xml vis-a-vis
or have a look at javax.inject.Provider relevant question here