which context.getBean to use when get the bean from spring - java

In the following link
http://docs.spring.io/spring-amqp/reference/html/quick-tour.html
It defined a bean in XML like
<rabbit:template id="amqpTemplate" connection-factory="connectionFactory"/>
Then in the calling code, it used
AmqpTemplate template = context.getBean(AmqpTemplate.class);
Why it used
context.getBean(AmqpTemplate.class);
instead of
context.getBean("amqpTemplate");
What's the getBean(AmqpTemplate.class) means? I can't find it defined by xml.

getBean()
is an overloaded method. You can call with the bean name or a bean type. Calling with the class returns the single instance of this class type. If there are more than one throws an exception. If there are none again throws an exception.
See here.

If you used context.getBean("amqpTemplate") you would need to cast the result to AmqpTemplate while getBean(AmqpTemplate.class) does it automatically. Note that getBean(AmqpTemplate.class) can only work if you have only one bean with AmqpTemplate class in the context

Related

Spring Integration service-activator referencing Hibernate JPA repository method

I'm trying to use a Hibernate JPA repository method as the method for a service-activator. The definition within the chain looks like the following.
<int:chain input-channel="bootstrapLineupCdsStart" output-channel="bootstrapLineupItemCdsStart">
<int:service-activator ref="lineupRepository" method="findByIntegrationStatusNew" />
<int:filter expression="!payload.isEmpty()" discard-channel="bootstrapLineupItemCdsStart"/>
<int:splitter expression="payload"/>
<int:service-activator ref="lineupServicePipeline" method="createLineup"/>
<int:aggregator/>
</int:chain>
The offending line is the first service-activator, specifically this line <int:service-activator ref="lineupRepository" method="findByIntegrationStatusNew" />
For the sake of completeness here is the repository class itself
#Repository( "lineupRepository" )
public interface LineupRepository extends JpaRepository<LineupEntity, Integer> {
#Query("select l from LineupEntity l where l.integrationStatus = 0")
List<LineupEntity> findByIntegrationStatusNew();
}
Now because of the magic of spring/hibernate I don't actually implement the findByIntegrationStatusNew myself; this is dynamically implemented by the framework at runtime. I also don't need to explicitly define the lineupRepository bean as the #Repository annotation handles this for me.
As a result of the above I get the following exeption.
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.integration.handler.MessageHandlerChain#9$child#0.handler': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: Target object of type [class com.sun.proxy.$Proxy79] has no eligible methods for handling Messages.
Finally, I do have a work around in place that seems to get the job done; it is an obvious work around and I suspect shouldn't be necessary. The work around consists of creating a new bean, explicitly defining the bean in the context XML and calling that method instead of the method on repository. So my work around looks a bit like this; first the workaround's context looks like this instead.
<int:chain input-channel="bootstrapLineupCdsStart" output-channel="bootstrapLineupItemCdsStart">
<int:service-activator ref="lineupRepositoryService" method="findByIntegrationStatusNew" />
<int:filter expression="!payload.isEmpty()" discard-channel="bootstrapLineupItemCdsStart"/>
<int:splitter expression="payload"/>
<int:service-activator ref="lineupServicePipeline" method="createLineup"/>
<int:aggregator/>
</int:chain>
<bean id="lineupRepositoryService" class="com.mypackage.LineupRepositoryService"/>
Notice the first service-activator now references LineupRepositoryService instead of LineupRepository, and I also added a new bean definition.
Second in the work around, of course, I also defined a LineupRespositoryService class that looks like the following.
public class LineupRepositoryService {
#Autowired
private LineupRepository lineupRepository;
public List<LineupEntity> findByIntegrationStatusNew() {
return lineupRepository.findByIntegrationStatusNew();
}
}
The workaround works, but I'd rather do it the right way. So anyone know how I can get it to properly work or what is going on here?
#JeffreyPhillipsFreeman, we confirm with the test-cases that it is an issue from Spring Integration reflection method invocation perspective.
Need to fix it anyway: https://jira.spring.io/browse/INT-3820.
Mean while there is only a workaround like your service wrapper.

Why is that only messageSource is allowed as bean id for ResourceBundleMessageSource?

For Beans, usually we can customise the id attribute but for ResourceBundleMessageSource class, if we dont specify id="messageSource" then a exception is thrown.
<bean id="myMessageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="message" />
</bean>
It throws the Exception
Exception in thread "main" org.springframework.context.NoSuchMessageException:
for code
new ClassPathXmlApplicationContext("springconfig.xml").getMessage("code");
Short answer - because that's the way they designed it.
As described in the reference guide:
When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source.... If the ApplicationContext cannot find any source for messages, an empty DelegatingMessageSource is instantiated in order to be able to accept calls to the methods defined above.
This is just a hard-coded value that is searched for. If you don't supply a bean with that name, you'll end up with a DelegatingMessageSource instance that won't resolve any of your messages, giving you a NoSuchMessageException.
Excerpt from the documentation:
When an ApplicationContext is loaded, it automatically searches for a MessageSource bean defined in the context. The bean must have the name messageSource. If such a bean is found, all calls to the preceding methods are delegated to the message source. If no message source is found, the ApplicationContext attempts to find a parent containing a bean with the same name. If it does, it uses that bean as the MessageSource. If the ApplicationContext cannot find any source for messages, an empty DelegatingMessageSource is instantiated in order to be able to accept calls to the methods defined above.

ways to inject a object of a class in spring controller?

I need to inject a object of a java class in spring controller through applicaionContext.xml. My controller will be ,
#Controller
public class SpringController{
private MyClass obj;
}
I know I can do it with #Autowired annotation.
Is this really good to create a object for a controller through applicaionContext.xml ? Also can I inject a object of a class in controller using the <property> tag inside a <bean> tag ?
Is this really possible ? or please forgive me if it is a stupid question.
I need to know the possible ways for how to inject a object of a class in Spring controller ?
You can of course use #Autowired annotation to autowire the relationships, which can reduce the need to define the properties and constructor arguments for the controller in your applicationContext.xml file. And also to add a dependency to a class, you don't need to modify the configuration files.
But it has some disadvantages too, like if you use #Autowired, there will not be any explicit documentation for the wiring details between Spring managed beans. And to know the relationships between the beans, you have to go through your managed beans. But, if you use configuration files to define the relationships, the relationship details can be found in one place.
You can inject an object of a class into your controller through your applicaionContext.xml as below:
Constructor based injection:
#Controller
public class SpringController{
private MyClass obj;
public SpringController(MyClass obj){
this.obj=obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<constructor-arg ref="myClassImpl"></constructor-arg>
</bean>
Setter based injection:
#Controller
public class SpringController{
private MyClass obj;
public void setObj(MyClass obj){
this.obj=obj;
}
public MyClass getObj(){
return obj;
}
}
<bean id="myClassImpl" class="x.y.z.MyClassImpl"></bean>
<bean id="springController" class="x.y.z.web.controllers.SpringController">
<property name="obj" ref="myClassImpl"></property>
</bean>
If you want to inject an object in a controller and you particularly want to you use xml,then instead of component scanning of Controller you should create a bean of the controller class of singleton scope in the application context.
Your controller class need not be annotated with #Controller.
you then have to you extend some Controller also like AbstractCommandController, AbstractController, AbstractFormController, AbstractWizardFormController, BaseCommandController, CancellableFormController, MultiActionController SimpleFormController, UrlFilenameViewController
Now to inject a particular object you can use Either Constructor and Setter based injection.
or you can use Autowring by name or type to auto inject the object.
Make sure that you have also declared the bean of that object also in Application Context.
After a DispatcherServlet has received a request and has done its work to resolve locales, themes and suchlike, it then tries to resolve a Controller, using a HandlerMapping. When a Controller has been found to handle the request, the handleRequest method of the located Controller will be invoked; the located Controller is then responsible for handling the actual request and - if applicable - returning an appropriate ModelAndView.
Thats it.
Actually, injection with xml and annotation is same behind the scene. Xml is old fashion while annotations are newer.
Basically, there are 2 types of injection types.
byName
Autowiring by property name. Spring container looks at the properties
of the beans on which autowire attribute is set to byName in the XML
configuration file. It then tries to match and wire its properties
with the beans defined by the same names in the configuration file.
You can give explicit names to beans both with xml and annotation.
#Service("BeanName")
#Component("BeanName")
#Controller("BeanName")
<bean name="BeanName" class="someclass"></bean>
and inject beans by using #Qualifier annotation.
#Autowired
#Qualifier("BeanName")
and with xml
<bean id="MyBean2" class="MyBean2 class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
byType
Autowiring by property datatype. Spring container looks at the
properties of the beans on which autowire attribute is set to byType
in the XML configuration file. It then tries to match and wire a
property if its type matches with exactly one of the beans name in
configuration file. If more than one such beans exists, a fatal
exception is thrown.
Default auto wiring mode is byType, so spring will look for matching type in auto wiring. However, older versions of Spring has default behavior none on injection. If you want to inject byType using xml, you should tell spring contaioner explicitly.
For example MyBean2 has a reference to MyBean, by setting autowired attribute to byType it handles injection automatically.
<bean id="MyBean" class="MyBean class">
<property name="Property of MyBean2 which refers to injecting bean" ref="BeanName" />
</bean>
<bean id="MyBean2" class="MyBean2 class"
autowire="byType">
</bean>
It also depends on where the injection take place in your code. There are 2 types, setter getter injection and constructor injection.
Note : There is no difference in #Controller since they are already in spring context.
See also
Spring Beans Auto wiring
I ran into such problem. I was getting "Ambiguous mapping found". (I use xml configuration as well and i am injecting a bean into my controller)
Then looking at my console i realized that my controller was being instantiated twice.
In more detailed look i noticed that my annotation
#Controller(value = "aController")
(Note value = "aController")
was different from my xml configuration where i was instatiating the same controller with different bean id
<bean id="aControleRRRRR" class="package.ControllerClassName"
p:property-ref="beanToInject" />
(Note id="aControleRRRRR")
So in conclusion your #Controller name (value = "aController") needs to be exactly the same as the name you give in the XML configuration (id="aControleRRRRR"), so that Spring can manage to distinct that they refer to the same bean (instance)
Hope this helps

Spring set abstract bean property value

I need to chance spring bean property values on runtime. Currently I'm doing it this way
Object bean = context.getBean(beanName);
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(bean);
wrapper.setPropertyValue(propertyName, newValue);
But some beans are configured as abstract
<bean id="abstractFoo" abstract="true" class="com.Foo" />
<bean id="bar" class="com.Bar">
<constructor-arg><bean parent="abstractFoo" /></constructor-arg>
</bean>
and in that case context.getBean("abstractFoo") throws BeanIsAbstractException
This is really simplified example, but I hope you get the idea.
Any idea how to change property value of abstract bean (in this case 'abstractFoo')?
We're using spring 2.5.4
Edit
Changed a XML example to be more specific. abstractFoo is declared abstract because of security reasons.
Spring application context contains bean definitions, and Spring instantiates bean objects defined by these definitions.
Your current code obtains an object that was created from the named bean definition, and changes its property. However, abstract beans are never instantiated as objects, they exist only in the form of definitions which are inherited by definitions of concrete beans.
So, if you want to change properties of abstract beans, you need to change their definitions, that can be done using BeanFactoryPostProcessor. Note, however, that post-processors are applied during container startup, so if you want it to be actually "runtime", you this approach is not applicable.
Disclaimer: this is untested; off the top of my head. Not sure if it will work after the init phase.
You need to get in instance of a ConfigurableListableBeanFactory. Your appcontext probably is one, so you can probably cast it.
From there, get the bean definition and change the property.
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory)context;
BeanDefinition fooDefinition = clbf.getBeanDefinition("abstractFoo");
MutablePropertyValues pv = fooDefinition.getPropertyValues();
pv.add(propertyName, newValue);
Maybe you need to re-register your beandefinition with the ConfigurableListableBeanFactory after that. I'm not 100% sure; you'll have to test that.
Keep in mind that if it works, it will only work for beans that are instantiated after the change.

Constructor arguments in autowiring sources

What exactly causes this?
org.springframework.beans.factory.NoSuchBeanDefinitionException: \
No unique bean of type [fi.utu.keycard.business.KeyCardManager] \
is defined: expected single matching bean but found 2: \
[dataBaseTarget, database]
// etc. (rest of Stack Trace is irrelevant)
What I need is autowiring 3 things: validator, ldap connection and database connection.
I call it:
#Controller
Controller(KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator)
The error seems to cause by another bean, if I change the order of these parameters. I have no signing-in, so I dont have UserDetails or so.
The fix is probably something like this:
public Controller(
#Qualifier("beanQualifier") KeyCardManager database,
LdapPersonDao personManager,
GiveFormValidator validator
)
Since there are apparently two beans of type KeyCardManager in your application context, you need to tell the context which one to wire.
Unfortunately the #Qualifier mechanism doesn't work with bean names, you must either annotate the actual bean with a corresponding #Qualifier or add a <qualifier> element to the XML bean definition.
The #Resource annotation works with bean names, but it doesn't support Constructor parameters (that's not Spring's fault, it's a JSR-250 standard annotation with #Target({TYPE, FIELD, METHOD}))
Reference:
Autowiring Collaborators
Fine-tuning annotation-based
autowiring with qualifiers
Troubleshooting
If you don't know why there are two beans of the same type in the context, first of all navigate to the bean interface (I assume KeyCardManager is an interface, if not, do the same thing for the class anyway) and if you use Eclipse select Navigate > Open Type Hierarchy. If you find more than one concrete class that inherits from KeyCardManager (including KeyCardManager itself), then there's probably your problem.
If that is not the case, you probably have two beans of the same type in your application context. One way that can happen is when you define a bean through both XML and classpath scanning. I.e. if you have this line in your XML:
<context:component-scan base-package="org.example"/>
Make sure you don't manually wire any beans from the org.example package (or you will have double beans, which can lead to the problem you have).
org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [fi.utu.keycard.business.KeyCardManager] is defined: expected single matching bean but found 2: [dataBaseTarget, database]
It seems you are autowiring by class type. but there are multiple bean available in the context with same class. which are dataBase & dataBaseTarget
byType
Allows a property to be autowired if
there is exactly one bean of the
property type in the container. If
there is more than one, a fatal
exception is thrown, and this
indicates that you may not use byType
autowiring for that bean. If there are
no matching beans, nothing happens;
the property is not set. If this is
not desirable, setting the
dependency-check="objects" attribute
value specifies that an error should
be thrown in this case.
Document

Categories