Moving from xml to Annotations - java

I am migrating to Spring 3 from 2.5 and would like to use annotations to inject my beans. I could not figure out how do I create use annotations to achieve the following
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="#{configLoader.getSmtpServer()}" />
<property name="username" value="#{configLoader.getSmtpUsername()}" />
<property name="password" value="#{configLoader.getSmtpPassword()}" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
<!-- A properties file based configuration bean -->
<bean id="propConfiguration" class="org.apache.commons.configuration.PropertiesConfiguration">
<property name="delimiterParsingDisabled" value="true"/>
<property name="file" value="classpath:configuration.#{systemProperties.CONFIG_MODE}.properties"/>
<property name="reloadingStrategy" ref="reloadingStrategy"/>
</bean>
<!-- The managed reloading strategy for the configuration bean -->
<bean id="reloadingStrategy" class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy">
<property name="refreshDelay" value="30000"/>
</bean>

Simply create a bean or beans annotated with #Configuration. Then instantiate everything in Java just as our ancestors did before Spring.
So for example:
#Configuration
public class MyConfig {
#Bean
public ReloadingStrategy reloadingStrategy() {
strategy = new FileChangedReloadingStrategy();
strategy.setRefreshDelay(30000);
return strategy;
}
}
Then do the same for your other dependencies.
To reference a bean defined in one configuration class in another, just use #Autowired.

Related

Multiple datasources throwing errors with JPA

I m trying to use multiple datasources using Springboot and JPA, but I m having errors when trying to start my server.
The problem only occurs when I try to use my second data source. I m having the following error when trying to start my application :
Not an managed type: class com.company.app.backoffice.modelDocument.Category
All is working great for the first data source. But it seems that my second entity manager doesn't track the good package. For example, I need my first datasource to manage my model package, and my second to manage modelDocument package :
<!-- Configure the data source bean -->
<!-- Website datasource -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- Doc base datasource -->
<bean id="docDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.doc.url}"/>
<property name="username" value="${jdbc.doc.username}"/>
<property name="password" value="${jdbc.doc.password}"/>
</bean>
<!-- Configure the entity manager factory bean -->
<!-- Website Entity manager -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.company.app.backoffice.model"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Doc base Entity manager -->
<bean id="docEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="docDataSource"/>
<property name="packagesToScan" value="com.company.app.backoffice.modelDocument"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<!-- Configure the transaction manager bean -->
<!-- Website transation manager -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<!-- Doc base transaction manager -->
<bean id="docTransactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="docEntityManagerFactory"/>
</bean>
Here's the class I need to manage in the second data source, which is in the modelDocument package :
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column
private String name;
public Long getId() {
return id;
}
public String getName() {
return name;
}
}
Does anybody knows what's going wrong with this ?
EDIT : Implicit repository to manage entity persistence
package com.company.app.backoffice.repository;
import com.company.app.backoffice.modelDocument.Category;
import org.springframework.data.jpa.repository.JpaRepository;
public interface CategoryRepository extends JpaRepository<Category, Long> {
}
EDIT 2 : The controller where the repository is injected :
#Controller
public class CategoryController {
#Autowired
private CategoryRepository categoryRepository;
#RequestMapping(value = "/categories", method = RequestMethod.GET, produces = "application/json")
#ResponseBody
public List<Category> categories() {
return categoryRepository.findAll();
}
}
add package scan containing the entities
<jpa:repositories base-package="your.package.enties" />
The main problem is that you have two different datasources and entity managers to work with JPARepository. I think Spring get lost when you work this way. Is is working only with one datasource/em. I have looked for a solution to set in Spring the em/datasource to one specific JPARepository, and I havent found. Despite that, you could follow this tutorial to create your own JPARepository implementation and define two classes. Each one to work with different datasource and EntityManager. Doing this, you should achieve what you want.
When you have multiple datasources, you will have to declare separate transaction manager (PlatformTransactionManager) and entity manager (LocalContainerEntityManagerFactoryBean). So Springboot gets confused. To resolve this use #Primary annotation. Put this annotation on any one of the transaction manager and on any one of the entity manager
Cheers

Obtaining a sessionFactory in hibernate

I just created two small crud applications one is a web application and the other I am running from a main method.
I am confused about how the sessionFactory object is being obtained in both the applications.
In my web application in DAOImpl I am just injecting the sessionFactory object and doing
#Repository
public class ContactDaoImpl implements ContactDao {
#Autowired
private SessionFactory sessionFactory;
public void addContact(Contact contact) {
//save: Persist the given transient instance
sessionFactory.getCurrentSession().save(contact);
}
My Spring Application Context
<!-- <context:property-placeholder> XML element automatically registers a new PropertyPlaceholderConfigurer
bean in the Spring Context. -->
<context:property-placeholder location="classpath:database.properties" />
<context:component-scan base-package="com.contactmanager"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<!-- View Resolver Configured -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!-- Creating DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<!-- To persist the object to database, the instance of SessionFactory interface is created.
SessionFactory is a singleton instance which implements Factory design pattern.
SessionFactory loads hibernate.cfg.xml and with the help of TransactionFactory and ConnectionProvider
implements all the configuration settings on a database. -->
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<!-- Configuring Hibernate Transaction Manager -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
But in the other application In which I don't use Spring I only use hibernate. I have to get the sessionFactory from annotationConfiguration then open the session and begin transaction.
AnnotationConfiguration().configure().buildSessionFactory();
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("4715");
stock.setStockName("GENM");
session.save(stock);
session.getTransaction().commit();
Can anyone tell me why I do have to written more lines of code to persist an object here. Is the Spring configuration doing everything in the first application?
This part of your Spring configuration is configuring the sessionFactory bean:
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
You can read more about setting up the Hibernate session factory with Spring here
This part of your DAO code is responsible for asking Spring to inject the session factory:
#Autowired
private SessionFactory sessionFactory;
You can read more about autowiring in Spring here

Why is Spring's Transaction Management not working with this configuration?

There are terribly many questions about this on SO, but I've tried some of them that sound correct, but I'm still getting
org.hibernate.HibernateException: No Session found for current thread
My Service layer classes are annotated as such:
#Service
public class MyService {
#Autowired
public SomeDao someDao;
#Transactional
public void performSomeTransaction() {/* ... */}
}
My application context XML has the following relevant declarations:
<context:component-scan base-package = "com.myapp.business.dao.impl" />
<context:component-scan base-package = "com.myapp.business.services" />
<context:annotation-config />
<tx:annotation-driven transaction-manager = "transactionManager" />
<!-- Hibernate -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="connection.url">jdbc:mysql://localhost:3306/bidapp</prop>
<prop key="connection.username">bidapp</prop>
<prop key="connection.password">pennyfss</prop>
<prop key="connection.driver_class">com.mysql.jdbc.Driver</prop>
<prop key="hibernate.connection.pool_size">10</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="c3p0.acquireIncrement">1</prop>
<prop key="c3p0.max_size">50</prop>
<prop key="c3p0.max_statement">0</prop>
<prop key="c3p0.min_size">10</prop>
<prop key="c3p0.timeout">0</prop>
</props>
</property>
<property name="dataSource" ref="dataSource"></property>
<property name="packagesToScan">
<list>
<value>com.bidapp.business.domain</value>
</list>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/bidapp" />
<property name="username" value="bidapp" />
<property name="password" value="pennyfss" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I also have my dispatcher-servlet.xml file with
<mvc:annotation-driven />
<mvc:default-servlet-handler />
<context:component-scan base-package="com.myapp.presentation.controllers" />
<context:annotation-config />
<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine" />
</bean>
Why doesn't spring wrap my services with transactions?
So it appears that the issue has to do with not getting instances correctly. I have the following Shiro Security config:
<bean id = "hibernateRealm" class = "com.bidapp.presentation.shiro.HibernateRealm" >
<property name = "credentialsMatcher" ref = "credentialsMatcher" />
</bean>
<bean id = "credentialsMatcher" class = "com.bidapp.presentation.shiro.JasyptCredentialsMatcher" />
<bean id = "securityManager" class = "org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name = "realm" ref = "hibernateRealm" />
</bean>
HibernateRealm is the service class with the #Transactional annotation. Shouldn't Spring be wrapping it in a proxy since it is creating it here.
The most common causes of this problem are
Incorrectly obtaining a service instance: for instance, instantiating it yourself rather than getting an instance from Spring.
Incorrectly configuring the root and child application contexts in a Spring MVC application. I've answered quite a number of these questions here. Here are some of the more educational ones:
Spring XML file configuration hierarchy help/explanation
Declaring Spring Bean in Parent Context vs Child Context
Showing the code where you obtain and use the service instance will help define the problem.
Add the property hibernate.current_session_context_class=thread during session factory creation in hibernate-persistance.xml file it will work.

Spring 3 injecting #Required field as NULL

I am having some trouble with setting up my Spring environment properly. In my applicationContext.xml I have:
...
<context:annotation-config />
<context:component-scan base-package="com.company.server" />
<import resource="databaseConfig.xml" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
and in my databaseConfig:
<tx:annotation-driven />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${jdbc.driver.className}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="packagesToScan" value="org.adit.spring.hibernate.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
Now my problem starts. If you look at the following class:
#Service
public class ViewContactsServiceImpl extends RemoteServiceServlet implements ViewContactsService {
private ContactDao contactDao;
#Autowired
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
#Override
public ArrayList<Contact> getAllContacts() {
return contactDao.getAllContacts();
}
}
During application startup everything is fine. Spring does not complain that it cannot create the bean or that it cannot inject the property. However, whenever I try to access the contactDao field, it is null.
Thanks!
UPDATE
I should also mention my ContactDaoImpl.java is defined as:
#Repository("contactDao")
#Transactional
public class ContactDaoImpl implements ContactDao { ... }
UPDATE 2
NB. This is a GWT application.
ViewContactServiceImpl.java:
package com.company.server.service.viewcontacts;
ViewContactsService.java:
package com.company.client.viewcontacts;
ContactDaoImpl.java
package com.company.server.contact;
ContactDao.java
package com.company.server.contact;
I thins ViewContactsServiceImpl is being instantiated by GWT (guessing based on RemoteServiceServlet) - so it is not spring managed bean.
You need to invoked auto-wire manually by overriding and implementing the init method. Similar to the code shown below (from this article). As explained in that article create an AbstractRemoteServlet that all your GWTService can extend.
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(config.getServletContext());
AutowireCapableBeanFactory beanFactory = ctx
.getAutowireCapableBeanFactory();
beanFactory.autowireBean(this);
}
Look at GWT-SL library for another approach to exposing spring managed beans as GWT remote services.

Get Dialect within some class inside Spring MVC + Hibernate application

I have Hibernate Transaction manager configured inside Spring MVC controller.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.postgresql.Driver" />
<property name="url" value="jdbc:postgresql://127.0.0.1/doolloop2" />
<property name="username" value="doolloop2" />
<property name="password" value="doolloop" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingLocations">
<list>
<value>WEB-INF/mapping/User.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
In Addition, I have some class which needs to get Hibernate Dialect inside on of it method.
Is class is not Configured as bean inside Spring Framework.
How can I access Hibernate Dialect property from this class? I believe it should be some static class,but I don't know how can I do it. Please help.
You could separate the properties from the spring config. Put them in a properties file, then reference that in a PropertyPlaceholderConfigurer bean ( http://almaer.com/blog/spring-propertyplaceholderconfigurer-a-nice-clean-way-to-share ). Then you could inject that value into whatever bean it is that you need the value in the same way you are injecting it into the sessionFactory bean.

Categories

Resources