Why is this Spring map not injecting into my Scala object? - spring

I'm creating a Spring-based Scala project. One of my objects needs a simple Map[String, String] injected in to it. I have the following code:
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:device="http://www.springframework.org/schema/mobile/device"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/mobile/device http://www.springframework.org/schema/mobile/device/spring-mobile-device-1.0.xsd">
<util:map id="validHosts">
<entry key="host1.domain.com" value="queue-1" />
<entry key="host2.domain.com" value="queue-2" />
</util:map>
</beans>
HostMapper.Scala
import scala.collection.JavaConversions._
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
#Component
class HostMapper() {
#Autowired private var validHosts:java.util.Map[String, String] = null
}
When running this app, I get the following error on startup:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [java.lang.String] found for dependency [map with value type java.lang.String]: expected at least 1 bean which qualifies as autowire candidate for this dependency.
I attempted explicitly declaring the key and value types as java.lang.String, but that had no effect. Any ideas what I might be doing wrong?

I did not know this myself and found this actually:
As a specific consequence of this semantic difference, beans which are themselves defined as a collection or map type cannot be injected via #Autowired since type matching is not properly applicable to them. Use #Resource for such beans, referring to the specific collection/map bean by unique name
And I tested this and instead of
#Autowired
I used:
#Resource
private Map<String, String> validHosts;
<util:map id="validHosts" key-type="java.lang.String" value-type="java.lang.String">
<entry key="host1.domain.com" value="queue-1" />
<entry key="host2.domain.com" value="queue-2" />
</util:map>
And it worked.

Related

Problem with spring defined #ManagedProperty

I'm currently mantainning a Maven based JSF Web Application combined with Spring Framework and JPA and connected to a SQL Server database.
Inside the application, I created one #ManagedBean class defined with the #ViewScoped and #Scope("view") annotations.
This class is named AvisoRecaladaBean and it has 3 attributes defined with the #ManagedProperty annotation as follows:
#ManagedProperty("#{jsf2Util}")
private Jsf2Util jsf2Util;
#ManagedProperty("#{avisoRecaladaService}")
private ISigcueCertAvisoRecaladaService avisoRecaladaService;
#ManagedProperty("#{usuarioService}")
private IUsuarioService usuarioService;
The first and third attributes were used in other managed beans in the same application. Also, IUsuarioService and ISigcueAvisoRecaladaService are interfaces, each one implemented by one class defined with the #Service annotation. The class that implements the latter interface also has the #Transactional annotation. JsfUtil is a class also defined with #Service.
Also, I defined one Integer attribute named folioBusqueda and one List<SigcueCertAvisoRecalada> attribute named listado. SigcueCertAvisoRecalada is an entity class pointing to a table in the database mencioned in the beginning.
Each attribute mentioned above has it's getter and setter.
In the other hand, I created one XHTML page named avisoRecalada.xhtml, that works with the AvisoRecaladaBean managed Bean.
The XHTML page has, among other things, one Panel Grid defined as follows:
<h:panelGrid columns="3">
<label>Ingrese NĂºmero de Folio: *</label>
<p:inputNumber placeholder="Folio del Aviso Recalada"
value="#{avisoRecaladaBean.folioBusqueda}"
required="true"
id="numeroFolio"/>
<p:commandButton value="Obtener Certificado Aviso"
actionListener="#{avisoRecaladaBean.buscarRegistro()}"
update="idTablaAviso"/>
<h:message for="numeroFolio" style="color:red"/>
</h:panelGrid>
The actionListener inside the command button refeers to the following method in AvisoRecaladaBean
public void buscarRegistro() {
SigcueCertAvisoRecalada item = avisoRecaladaService.findByFolio(folioBusqueda);
listado.clear();
if(item!=null) {
listado.add(item);
}
}
The Spring configuration is defined in an XML file defined as follows (I show only the important part):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:drools="http://drools.org/schema/drools-spring"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://drools.org/schema/drools-spring http://anonsvn.jboss.org/repos/labs/labs/jbossrules/trunk/drools-container/drools-spring/src/main/resources/org/drools/container/spring/drools-spring-1.0.0.xsd
http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.2.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
">
<context:component-scan base-package="cl.sernapesca" />
<context:annotation-config />
<!-- Bean definitions -->
<tx:annotation-driven/>
<tx:jta-transaction-manager />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true" />
<property name="locations">
<list>
<value>classpath:singleSingOn.properties</value>
<value>classpath:revision.properties</value>
<value>classpath:ldapExternos.properties</value>
</list>
</property>
</bean>
<!-- View Scope para JSF2 -->
<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
<property name="scopes">
<map>
<entry key="view">
<bean class="cl.sernapesca.mantenedorcentral.arquitectura.ViewScope" />
</entry>
</map>
</property>
</bean>
<!-- More Bean definitions -->
</beans>
The faces-config.xml has only the following managed-beans defined:
<managed-bean>
<managed-bean-name>currentDate</managed-bean-name>
<managed-bean-class>java.util.Date</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
And it's resolver is defined as:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
<!-- More configurations -->
</application>
When I deploy the application using a WildFly 10 Application Server, I get no error messages. Also, I get no errors when I access the XHTML page.
However, when I input one value in the input text and push the command button, I get one NullPointerException. The stack trace indicates that the exception were launched when trying to execute the first line of buscarRegistro().
After some debugging, I found that the avisoRecaladaService attribute was null, but the other two managed properties weren't.
I tried the following solutions with no avail
Add and/or replace #ManagedProperty with #Autowired
Use the #Qualifier annotation to name the bean (I named it "avisoRecaladaService") and use the current ApplicationContext to get the bean (Source: Spring Bean never set as ManagedProperty in JSF Bean). I got a NoSuchBeanException with this solution:
WebApplicationContext webAppContext = ContextLoader.getCurrentWebApplicationContext();
avisoRecaladaService = (IAvisoRecaladaService) webAppContext.getBean("avisoRecaladaService");
EDIT: Instantiate avisoRecaladaService directly. Not desirable. Also, autowired attributes of SigcueCertAvisoRecaladaService are null:
public void buscarRegistro() {
if(avisoRecaladaService==null)
avisoRecaladaService=new SigcueCertAvisoRecaladaService();
SigcueCertAvisoRecalada item = avisoRecaladaService.findByFolio(folioBusqueda);
listado.clear();
if(item!=null) {
if(listado==null)
listado=new ArrayList<>();
listado.add(item);
}
}
EDIT: Replace #ManagedAttribute with #Resource (Source: #ManagedProperty equivalent in Spring)
Replace #ManagedAttribute with #Inject (same source as the previous solution)
Any advice for a definitive solution would be really much obligated.
EDIT
As requested by Kukeltje, according to the application's pom.xml, the involved libraries are the following:
jboss-jsf-api 2.2
jboss-el-api 3.0 spec
spring-core 4.2.8
spring-web 4.2.8
spring-expression 4.2.8
spring-context-support 4.2.8
spring-web-mvc 4.2.8
JDK 1.8.0_191
Developed in Eclipse Oxygen (if relevant)
SOLVED
Thanks to a partner of mine, We discovered that #ManagedProperty is very sensitive about names. The name of the bean must be exactly the same as the class, with it's first letter in lower case. If the object is an interface instance, like in my case, it must be the name of the class implementing it.
So, I had to change this:
#ManagedProperty("#{avisoRecaladaService}")
private ISigcueCertAvisoRecaladaService avisoRecaladaService;
Into this:
#ManagedProperty("#{sigcueCertAvisoRecaladaService}")
private ISigcueCertAvisoRecaladaService sigcueCertAvisoRecaladaService;
Thanks to all of you for reading this and I hope this helps to similar problems in the future

Spring Autowire JdbcDaoSupport

I'm receiving the an error when trying to autowire a class that extends JdbcDaoSupport. I have my DAO classes and Controller classes separated into 2 different spring contexts. DAO classes are in the root context and the Controller classes are in the servlet context. I've set up the component-scanning so that there is no overlap in beans between the 2 contexts (is that the correct pattern?). All these factors combined with the fact that my DAOs extend JdbcDaoSupport seems to be causing the issue, and I don't understand why. I'm just learning spring so I don't fully understand all the concepts yet.
EDIT: This behavior seems to be caused by the fact that JdbcDaoSupport/DaoSupport implements the InitializingBean interface. Still confused though.
Here is the error I am receiving:
Error creating bean with name 'homeController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: org.test.dao.CustomerDAO2 org.test.servlet.HomeController.customerDAO; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.test.dao.CustomerDAO2] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here are my files:
HomeController.java
package org.test.servlet;
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.test.dao.*;
#Controller
public class HomeController
{
#Autowired
CustomerDAO2 customerDAO;
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model)
{
model.addAttribute("customer", customerDAO.getCustomer());
return "home";
}
}
CustomerDAO2.java
package org.test.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.*;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.*;
import org.test.dto.Customer;
#Repository
public class CustomerDAO2 extends JdbcDaoSupport
{
public CustomerDAO2()
{
}
#Autowired
public CustomerDAO2(DataSource datasource)
{
this.setDataSource(datasource);
}
#Transactional
public Customer getCustomer()
{
JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
Customer customer = jdbcTemplate.queryForObject("select * from customer", new CustomerMapper());
return customer;
}
public static class CustomerMapper implements RowMapper<Customer>
{
public Customer mapRow(ResultSet rs, int rowNum) throws SQLException
{
Customer customer = new Customer();
customer.setCustomerId(rs.getInt("customerId"));
customer.setCustomerNumber(rs.getString("customerNumber"));
return customer;
}
}
}
application-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<!-- #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="org.test">
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation"/>
</context:component-scan>
<!-- Enables the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/crm?user=root&password=password" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans within the base package of the application for #Components to configure as beans -->
<!-- #Controller, #Service, #Configuration, etc. -->
<context:component-scan base-package="org.test.servlet"/>
<!-- Enables the Spring MVC #Controller programming model -->
<mvc:annotation-driven />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
</beans>
I found my answer in this post:
Spring expected at least 1 bean which qualifies as autowire candidate for this dependency
Basically, I need to create an interface for my DAO classes. Something like this:
public interface ICustomerDAO {
Customer getCustomer();
}
Note: it would probably be better to make a more generic CRUD interface.
Then you use the interface type for dependency injection instead of using the class type:
#Autowired
ICustomerDAO customerDAO;
The reason this is necessary is because Spring creates underlying proxy classes:
http://insufficientinformation.blogspot.com/2007/12/spring-dynamic-proxies-vs-cglib-proxies.html
http://docs.spring.io/spring/docs/2.5.x/reference/aop.html#aop-proxying

#Autowired doesn't work if component-scan removed

I'm facing the problem, that the annotation #Autowired doesn't work anymore (in all Java classes that uses this annotation) if I remove the component-scan tag from config
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="efco.auth" />
here are some beans...
There is only one class in the efco.auth package, and this one has no relation to the following class EfcoBasketLogic.
and a class that uses #Autowired:
package efco.logic;
public class EfcoBasketLogic extends BasketLogicImpl {
#Autowired
private EfcoErpService erpService;
This Bean is defined in an other spring config file:
<bean id="BasketLogic" class="efco.logic.EfcoBasketLogic">
<property name="documentLogic" ref="DocumentLogic" />
<property name="stateAccess" ref="StateAccess" />
<property name="contextAccess" ref="ContextAccess" />
</bean>
As you can see, erpService is not defined. The other three properties are on BasketLogicImpl and have setters.
What I'm doing wrong?
As Tomasz says, you need <context:annotation-config/> for #Autowired to work. When you had <context:component-scan/>, it implicitly included annotation-config for you.
Adding either autowire="byType" or autowire="byName" to your bean declaration should do the job.

Spring's #Autowired doesn't inject dependency

I have a project that consists of various modules.
Basically, I've worked with Spring MVC & JUnit 4, and everything was working good.
But Now, I added few classes which aren't related to testing or MVC, and the #Autowired annotation doesn't inject objects to them.
The same objects are injected to the MVC and JUnit classes, so I realy confused.
This is the Spring Context XML:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="com.justic.more" />
<mvc:annotation-driven />
<context:annotation-config />
<bean id="monkDAO" class="com.justic.more.data.monkDAO" />
<bean id="BidDAO" class="com.justic.more.data.BidDAO" />
</beans>
The Class that I want to inject to:
#Component
Public Class Tesser {
#Autowired
MonkDAO monkdao;
...
blablabla
...
}
From the chat with OP it became clear that he created the object like Tesser tesser = new Tesser() instead of injecting it into the test class.
Spring has no chance to autowire dependencies in beans that it does not create itself.
The solution is to autowire the Tesser object into the test class so Spring can inject the dependencies.
#Autowired
private Tesser tesser;
#Test
public void testSth() {
assertTrue(tesser.someBoolReturningMethodUtilizingMonkDAO());
}
Add qualifiers:
#Resource(name = "monkDAO")
If you start with annotations, go all the way.

How to initialized java bean with annotation in spring framework?

I have a Java bean:
public class User{
private Integer userid;
private String username;
private String password;
private boolean enable;
//getter and setter
}
I am able to initialize it as a spring bean at context.xml via:
<context:component-scan base-package="com.myCompany.myProject" />
But I don't want initialize it in xml. How can I initialize it with sring 3 annotation. I tried with the following:
#Component
public class User{
private Integer userid;
private String username;
private String password;
private boolean enable;
//getter and setter
}
But the above did not work for me. Any ideas?
I believe that is because you have enable component scan on the package com.myCompany.myProject and not on the package com.myCompany.myProject.db
Change your scan definition to this : <context:component-scan base-package="com.myCompany.myProject.db" /> (or add a new one, if you want classes from the other package as well) and you can remove the bean definition from XML and have your annotation work for you.
Silly, but still, ensure that the #Component annotation is that of Spring's. I've at times faced this silly issue of defining an annotation that is actually not from the desired library (owing to the same name of the annotation, by different libraries in my classpath).
You need to add
<context:annotation-config />
With this XML my Autowiring works flawless:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.vanilla.example"></context:component-scan>
</beans>
you shouldn't need to have both declared.
Use of context:annotation-config allows for autowiring of beans via annotations etc
Use of context:component-scan provides everything that context:annotation-config, but allows for autodiscovery of beans. The package you supply in context:component-scan will scan that package plus all sub packages.
Hope this helps
Be sure that the "User" class is the package or sub-package of the
"com.myCompany.myProject".
You do NOT need to include <context: annotation-config/>, it is
included with component-scan.
The bean is available with the name "user" by default, unless you
specify the bean name with #Component("myBeanName")
Once that is done, you can autowire the bean into another with:
#Autowired
User user;
OR
#Inject
User user;
NOTES:
#Inject is a javax.inject annotation the injection is NOT required.
#Autowired is a Spring annotation and the injection is required.
#Autowired can be used in one of the following ways:
just above the member variable
constructor that accepts a User bean
setter that accepts a User bean.
I have configured my xml file in this way , this will help you to solve the problem.
For Context-componentscan use
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.java.Controllers"></context:component-scan>
<context:component-scan base-package="com.java.dao"></context:component-scan>
<context:component-scan base-package="com.java.bean"></context:component-scan>
Or else u can use
<context:component-scan base-package="com.java.*"></context:component-scan>
next for annotation driven use
<mvc:annotation-driven />
For resources use this
<mvc:resources location="/" mapping="/**"/>

Resources