Autowired without component scan or setter/getter - java

Is it possible to #Autowired a field
#Repository( "categoryDao" )
public class SomeDaoImpl implements SomeDao {
#Autowired
private SessionFactory sessionFactory;
...
}
without using setter/getter or *component scan?
I have a config
<bean id="categoryDao" class="com.example.dao.SomeDaoImpl">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
...
</bean>

You can use constructor injection instead, so something like
#Repository( "categoryDao" )
public class SomeDaoImpl implements SomeDao {
private SessionFactory sessionFactory;
#Autowired
public SomeDaoImpl(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
}
There's a good discussion about the different types of injection, with a lot of refernce links available here
UPDATE after comment
Now that you explained, you should not change your code on accout of test. In your case you should use a test specific XML context, but reduce the packages being scanned to just enough
Also a handy construct is that inside your test context xml, you can redifine some injected beans by instantiating it first and using context:exclude-filter property, usefull for mocking, an example snippet
<!--Mock object -->
<bean id="beanDAO" name="beanDAO" class="org.mockito.Mockito" factory-method="mock">
<constructor-arg value="your.package.BeanDAO"/>
</bean>
<context:component-scan base-package="your.package">
<context:exclude-filter type="regex" expression="your\.package\.Bean*"/>
</context:component-scan>

Related

Spring dependency injection not working

I've got a problem in my standalone Java application. The thing is that I'm trying to Autowire both my Services and my DAOs, but I get a NullPointerException when I invoke service methods from the UI since dependency injection is not working properly. I've tried a lot of things, many of them from similar questions, but the problem is still there. I'm using Spring 4.0.6.RELEASE and Hibernate 4.3.11.Final. Here is my code:
1 - Invocation of service:
public class LoginView {
#Autowired
private UsuarioService usuarioService;
...
...
JButton btnAutenticarse = new JButton("Autenticar");
btnAutenticarse.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
Usuario usuario = usuarioService.login(textField.getText(),
String.valueOf(passwordField.getPassword()), false); // NullPointerException
} catch (InstanceNotFoundException e1) {
...
2 - Definition of service:
#Service("usuarioService")
public class UsuarioServiceImpl implements UsuarioService {
#Autowired
private UsuarioDao usuarioDao;
...
3 - Definition of DAO:
#Repository("usuarioDao")
public class UsuarioDaoHibernate extends GenericDaoHibernate <Usuario, Long>
implements UsuarioDao {
...
4 - Definition of GenericDAO:
public class GenericDaoHibernate<E, PK extends Serializable> implements
GenericDao<E, PK> {
#Autowired
private SessionFactory sessionFactory;
....
5 - AppConfig.java:
#Configuration
#ComponentScan(basePackages = "org.example.model")
public class AppConfig {
#Bean(name = "usuarioService")
public UsuarioService usuarioService() {
return new UsuarioServiceImpl();
}
#Bean(name = "usuarioDao")
public UsuarioDao usuarioDao() {
return new UsuarioDaoHibernate();
}
6 - spring-config.xml:
<!-- Enable usage of #Autowired. -->
<context:annotation-config/>
<!-- Enable component scanning for defining beans with annotations. -->
<context:component-scan base-package="org.example.model"/>
<!-- For translating native persistence exceptions to Spring's
DataAccessException hierarchy. -->
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/appdb" />
<property name="username" value="username" />
<property name="password" value="password"/>
</bean>
<bean id="dataSourceProxy" class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy"
p:targetDataSource-ref="dataSource"/>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>org.example.model</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<!-- Enable the configuration of transactional behavior based on
annotations. -->
<tx:annotation-driven transaction-manager="transactionManager" />
Spring will only inject Autowired fields in Spring managed beans. AKA if you are using new LoginView() Spring cannot inject dependencies.
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
should be
#Component
public class LoginView {
#Autowired
private UsuarioService usuarioService;
}
If you can't let Spring manage that class, you'll need to design it a different way.
I'd recommend you use constructor injection instead of field injection, by the way.
What I might do is make another class to be a Spring managed bean and do something like this:
#Component
public class InitClass{
private UsarioService usarioService;
#Autowired
public InitClass(UsarioService usarioService){
this.usarioService = usarioService;
}
#PostConstruct
public void init(){
new LoginView(usarioService);
}
}
Then this class will handle all the initialization you're doing now in #PostConstruct. It may be required to do this in #PostConstruct as Spring beans may not be fully initialized until then.
However, without seeing how everything is initialized, it's hard to tell what the best strategy would be.
Make explicit component scan in the application context file. I did like this and it worked for me.
<context:component-scan base-package="com.example" />
You can see more information in the link here

How can I use services in another service inside one and the same bundle(module)?

I have 2 budles in project. When first bundle is start second bundle use services from it. But How can I use service in service inside bundle?
<service ref="EMUtilService" interface="domain.access.EMUtil"/>
<bean id="EMUtilService" class="domain.access.impl.EMUtilImpl" scope="singleton">
<jpa:context unitname="access" property="entityManager"/>
<tx:transaction method="*" value="RequiresNew"/>
</bean>
<service ref="userService" interface="domain.access.UserService"/>
<bean id="userService" class="domain.access.impl.UserServiceImpl" scope="singleton">
</bean>
I want use EMUtilService in userService or in another simple classes.
my EMUtilService
public class EMUtilImpl implements EMUtil {
private EntityManager entityManager;
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public EntityManager getEntityManager() {
return entityManager;
}
}
I wan init EntityManager in this service and use it in another classes.
Blueprint is largely inspired by Spring (it's the successor of Spring DM) and as such, it supports the same syntax for injecting beans/services into other beans. You can put an id on a bean definition, and inject this bean into a property of another bean :
<bean id="mybean" class="my.package.MyClass"/>
<bean id="myService" class="my.package.MyService">
<property name="myProperty" ref="mybean"/>
</bean>

"Write operations are not allowed in read-only mode" error : confused with Spring #Service #transaction #Repository and Hibernate

I am working on an existing project using Spring and Hibernate and am getting confused because I get a
org.springframework.dao.InvalidDataAccessApiUsageException: Write
operations are not allowed in read-only mode (FlushMode.MANUAL): Turn
your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker
from transaction definition.
error when trying to save objects but I still can't find what exactly is wrong.
There is a service layer that is annotated using #Service and a save method that it should be transactional so it is annotated with #Transactional(readOnly = false). To me that means that spring should handle transactions itself.
#Service
public class LadyService {
Logger log = Logger.getLogger(LadyService.class);
#Autowired
private PictureDAO pictureDao;
#Autowired
private LadyDAO ladyDao;
#Autowired
private AddressDAO addressDao;
#Transactional(readOnly = false)
public void save(Lady lady) {
Address a = addressDao.getExistingAddress(lady.getAddress());
if (a == null) {
a = addressDao.save(lady.getAddress());
}
lady.setAddress(a);
ladyDao.save(lady);
pictureDao.savePictures(lady.getPictures());
}
The error happens when doing a save in the AddressDAO. It is annotated as #Repository.
#Repository
public class AddressDAO extends HibernateDaoSupport {
public Address save(Address address) {
getHibernateTemplate().save(address); <-- write not permitted error happens here
return address;
}
#SuppressWarnings({ "unchecked" })
public Address getExistingAddress(Address address) {
DetachedCriteria cd = DetachedCriteria.forClass(Address.class);
cd.add(Restrictions.eqOrIsNull("administrative_area_level_1",
address.getAdministrative_area_level_1()));
cd.add(Restrictions.eqOrIsNull("administrative_area_level_2",
address.getAdministrative_area_level_2()));
List<Address> result = (List<Address>) getHibernateTemplate()
.findByCriteria(cd);
if (result.isEmpty()) {
return null;
} else {
return (Address) result.get(0);
}
}
}
What I thought would happen was that #Transactional makes spring create a session and a transaction for the save on the service layer, and that in the DAOs, the hibernate template would get the current session and transaction that spring manages and use it to save the objects.
The error message, though, makes me think that my service method and dao methods are not in the same transaction.
In the servlet-context.xml there are these statements:
<annotation-driven />
<context:component-scan base-package="com.kog.fable" />
<beans:bean id="mySessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="myDataSource" />
<beans:property name="packagesToScan">
<beans:array>
<beans:value>com.kog.fable.**.*</beans:value>
</beans:array>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<!-- create, validate, update -->
<beans:prop key="hibernate.hbm2ddl.auto">create</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.connection.pool_size">10</beans:prop>
<beans:prop key="hibernate.connection.autocommit ">false</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="addressDAO" class="com.kog.fable.dao.AddressDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="ladyDAO" class="com.kog.fable.dao.LadyDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="pictureDAO" class="com.kog.fable.dao.PictureDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
Here I don't understand why, if component scan is used, the DAO beans are still declared explicitly. Shouldn't the component scan feature be able to create those by itself since the DAO classes are annotated with #Repository?
Since I thought this configuration could create duplicate beans, I tried deleting the xml entries, but then I started getting:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'addressController': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private com.kog.fable.dao.AddressDAO
com.kog.fable.controller.AddressController.addressDAO; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'addressDAO' defined in file
[***\com\kog\fable\dao\AddressDAO.class]: Invocation of init method
failed; nested exception is java.lang.IllegalArgumentException:
'sessionFactory' or 'hibernateTemplate' is required
Here I thought that the extension of HibernateDaoSupport for my DAOs would make them inherit the sessionFactory and related methods so I don't understand what happens.
I have read that I could set the flush mode to AUTO or set the setCheckWriteOperations on the template to FALSE to solve that kind of problems and it seems to work, but I guess that this would not ensure the transaction coherence in all cases as I would like it.
Any help would be appreciated as I am quite new to Spring and Hibernate and am a bit stuck here.
When extending HibernateDaoSupport you will not benefit from autowiring, you will have to override the setSessionFactory method and put an #Autowired annotation on it. Else it won't work.
I would also expect a <tx:annotation-driven /> without that the #Transactional is pretty much useless and doesn't do anything.
if your app is Spring MVC based...
in application-context try this..
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="yourSessionFactory"></property>
</bean>
but in dispatcher-servlet (not in appContext !!!)
<tx:annotation-driven />
Dont forget namespaces for tx, and jar libraries spring-tx,spring-orm,hibernate-core
In configuration file
do the change:-
#Configuration
#EnableTransactionManagement <-----Put this line
public PersistenceConfig{
//your code
}
(OR)
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory session) {
HibernateTemplate hb = new HibernateTemplate();
hb.setCheckWriteOperations(false);
hb.setSessionFactory(session);
return hb;
}

Spring - Inject bean from a factory class

I have the following in my class:
public class Manager {
private Apple apple = AppleFactory.createInstance();
// .....
}
appContext.xml:
<bean id="manager" class="Manager"/>
AppleFactory is an external library on which I do not have any control over. I use xml configuration(appContext.xml) for wiring the beans. How can I inject the field apple from appContext.xml?
<bean id="apple" class="AppleFactory" factory-method="createInstance" />
<bean id="manager" class="Manager"/>
<context:annotation-config />
Your manager
public class Manager {
#Autowired
private Apple apple;
}
Should do the trick.
See the reference guide and Initializing Spring bean from static method from another Class?
You can use following configuration :
<bean id="apple" class="jarpackagename.AppleFactory"
factory-method="createInstance">
</bean>
<bean id="manager" class="pkgname.Manager">
<property name="apple" ref="apple">
</bean>
You can configure Manager bean as follows
<bean class="xxx.Manager">
<property name="apple">
<bean class="yyy.AppleFactory" factory-method="createInstance" />
</property>
</bean>

LazyInitializationException with Hibernate 4.1, Spring 3.1 and JSF 1.2 (Myfaces)

I have a webapp using Hibernate 4.1 and Spring 3.1 and JSF 1.2 (myFaces).
I have this "LazyInitializationException" each time I try to access one of my pages
Caused by: org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at £org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:149)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:195)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at foo.data.bo.implementations.EOServiceType_$$_javassist_10.getTechKey(EOServiceType_$$_javassist_10.java)
at foo.converter.EOServiceTypeConverter.getAsString(EOServiceTypeConverter.java:36)
at org.apache.myfaces.shared_tomahawk.renderkit.RendererUtils.getConvertedStringValue(RendererUtils.java:648)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.getSubmittedOrSelectedValuesAsSet(HtmlRendererUtils.java:362)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.internalRenderSelect(HtmlRendererUtils.java:337)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils.renderMenu(HtmlRendererUtils.java:288)
at org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlMenuRendererBase.encodeEnd(HtmlMenuRendererBase.java:57)
at org.apache.myfaces.renderkit.html.ext.HtmlMenuRenderer.encodeEnd(HtmlMenuRenderer.java:70)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:649)
... 50 more
I think I missunderstood something because I don't know How to give the "session" to my classes.
For info, here are some of my configuration files :
spring-config.xml:
<context:annotation-config />
<context:component-scan base-package="foo" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="namingStrategy">
<ref bean="oracleNamingStrategy" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<alias name="jndiDataSource" alias="dataSource" />
<bean name="oracleNamingStrategy"
class="org.hibernate.cfg.ImprovedNamingStrategy">
</bean>
<bean name="jndiDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/fooDS</value>
</property>
</bean>
My java class EOServiceType
#Entity
#Table(name="EOSERVICETYPE")
public class EOServiceType implements IEOServiceType {
#Id
#Column(name="EOSERVICETYPE_ID")
private long techKey;
#Column(name="H_PROPERTY")
private String property;
#Column(name="H_DESCRIPTION")
private String description;
//... + all getters and setters
}
My DAO implementation for Hibernate EOServiceTypeDaoHibernateImpl
#Repository("eOServiceTypeDao")
public class EOServiceTypeDaoHibernateImpl implements IEOServiceTypeDao {
#Autowired
private SessionFactory sessionFactory;
public void save(IEOServiceType serviceType) {
sessionFactory.getCurrentSession().save(serviceType);
}
public void update(IEOServiceType serviceType) {
sessionFactory.getCurrentSession().update(serviceType);
}
//... and some other CRUD operations...
}
My POJO Service implementation for Hibernate EOWebStaffServicesImpl
#Service
public class EOWebStaffServicesImpl implements IEOWebStaffServices {
#Autowired
private SessionFactory sessionFactory;
//...
#Autowired
private IEOServiceTypeDao eoServiceTypeDao;
public void saveOrUpdateEOServiceType(IEOServiceType eoServiceType) {
try {
eoServiceTypeDao.saveOrUpdate(eoServiceType);
} catch (DataIntegrityViolationException e) {
DuplicateKeyException exception= new DuplicateKeyException("Duplicate business key for " + eoServiceType,e);
throw exception;
}
}
public void deleteEOServiceType(IEOServiceType eoServiceType) {
eoServiceTypeDao.delete(eoServiceType);
}
My Hibernate Config file :
<hibernate-configuration>
<session-factory>
<property name="hibernate.mapping.precedence">hbm, class</property>
<property name="show_sql">false</property>
<property name="format_sql">true</property>
<property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="jdbc.batch_size">20</property>
<mapping class="foo.data.bo.implementations.EOServiceType"/>
<!-- ... and other mappings -->
</session-factory>
</hibernate-configuration>
Does any body have a tip to help me ? I read some articles and post but did not really find a solution to my problem.
Best regards,
Kamran
I had the same kind of problem several weeks ago. I obviously forgot to annotate my method which is interacting with Hibernate.
I recommend you the
#Transactional
annotation. It should fix your problem.
Otherwise here is the related Hibernate documentation:
Sessions and Transactions
I think this happens because you don't use transactions in your DAO classes. Hibernate will not work with Spring outside of the transaction. You can define declarative transactions with Spring (annotate necessary classes with #Transactional annotation). Here is a link to Spring reference documentation about Transactions.
Also you should inject SessionFactory to your bean before using it:
#autowired
private SessionFactory sessionFactory;
What are you planing to archive with the SessionFactory in your service class?
Anyway, i think the problem is that you are trying to access a detached object with lazy properties. (That's usually the case when you see that exception)
Is that all the code there is of your POJOs?

Categories