I am trying to use annotated TX Spring support.
Application context XML:
<?xml ...>
<tx:annotation-driven/>
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource">
...
</bean>
<bean id="repository" class="Repository">
<constructor-arg ref="dataSource"/>
</bean>
</beans>
Actual code:
public class Repository {
#Transactional
public void save(Op op) {
System.out.println("Transaction active:::: " + TransactionSynchronizationManager.isActualTransactionActive());
...
}
}
Calling code:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/integration-context.xml"})
public class RepositoryTest {
#Autowired
private Repository repository;
#Test
public void testRepositoryPersistence() {
Op op = mock(Op.class);
repository.save(op);
}
}
And it gives FALSE.
What am I doing wrong?
You should add this in your configuration
<context:annotation-config/>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
add an interface on your RepositoryClass
public class Repository implements IRepository{
#Transactional
public void save(Op op) {
System.out.println("Transaction active:::: " + TransactionSynchronizationManager.isActualTransactionActive());
...
}
}
and this in your test class
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:/integration-context.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = false)
public class RepositoryTest extends AbstractTransactionalJUnit4SpringContextTests{
#Autowired
private IRepository repository;
#Test
public void testRepositoryPersistence() {
Op op = mock(Op.class);
repository.save(op);
}
}
see this tutorial.
Related
I'm trying to apply formatter-annotation to the field "phone" in next model-class:
public class User {
#ContactNumberFormate
private String phone;
}
Interface for annotation:
#Target({ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
public #interface ContactNumberFormate {
}
Formatter:
#Component
public class PhoneFormatter implements Formatter<String> {
#Override
public String parse(String phoneNum, Locale locale) throws ParseException {
phoneNum = phoneNum.trim();
String regex = "^\\(?(\\+*1)?[-.\\s*]?([0-9]{3})\\)?[-.\\s*]?([0-9]{3})[-.\\s*]?([0-9]{4})$";
Pattern.compile(regex).matcher(phoneNum);
return phoneNum;
}
#Override
public String print(String phone, Locale locale) {
return phone;
}
}
Annotation-factory:
public class PhoneFormatAnnotationFormatterFactory implements
AnnotationFormatterFactory<ContactNumberFormate> {
#Override
public Set<Class<?>> getFieldTypes() {
return Collections.singleton(String.class);
}
#Override
public Printer<?> getPrinter(ContactNumberFormate contactNumberFormate, Class<?> aClass) {
return new PhoneFormatter();
}
#Override
public Parser<?> getParser(ContactNumberFormate contactNumberFormate, Class<?> aClass) {
return new PhoneFormatter();
}
}
FormatterRegistrar:
public class ApplicationFormatterRegister implements FormatterRegistrar {
#Override
public void registerFormatters(FormatterRegistry formatterRegistry) {
formatterRegistry.addFormatterForFieldAnnotation(new PhoneFormatAnnotationFormatterFactory());
}
}
config:
<mvc:annotation-driven conversion-service="conversionService">
<mvc:message-converters>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper" ref="objectMapper"/>
</bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="applicationConversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatterRegistrars">
<set>
<ref bean="applicationFormatterRegistrar"/>
</set>
</property>
</bean>
<bean id="applicationFormatterRegistrar" class="ru.spb.dreamwhite.util.phoneUtil.ApplicationFormatterRegister"/>
And it does not work: phone-values saved in database, but in non-formatted form.
Note: when I run test in debug with breakpoint on PhoneFormatter, test passes susseccfully. That means, that my Formatter is out of process. But when I set breakpoint on PhoneFormatAnnotationFormatterFactory.getFieldTypes, test interrupted.
In particular, debug with breakpoint on return Collections.singleton(String.class); in
public Set<Class<?>> getFieldTypes() {
return Collections.singleton(String.class);
}
shows that the class PhoneFormatAnnotationFormatterFactory has no fields...
I am trying to make a simple Spring MVC application using Spring Data, hibernate and H2 database. But spring cannot find the repository as a bean.
The error when application start:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'taskService': Unsatisfied dependency expressed through method 'setTaskRepository' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spring.intership.repositories.TaskRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.spring.intership.repositories.TaskRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
TaskRepository.java
#Repository
public interface TaskRepository extends JpaRepository<Task, Long> {
}
TaskSerice.java
public interface TaskService {
public List<Task> getAll();
public void save(Task t);
}
TaskServiceImpl.java
public class TaskServiceImpl implements TaskService {
private TaskRepository taskRepository;
#Override
public void add(Task task) {
taskRepository.save(task);
}
#Override
public List<Task> getAll() {
LinkedList<Task> tasks = new LinkedList<>();
taskRepository.findAll().forEach(tasks::add);
return tasks;
}
#Autowired
public void setTaskRepository(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
}
BeanConfiguration.java
#Configuration
public class BeanConfiguration {
#Bean
MemoryService memoryService() {
return new MemoryServiceImpl();
}
#Bean
TimeService timeService() {
return new TimeServiceImpl();
}
#Bean
NameService nameService() {
return new NameServiceImpl();
}
#Bean
TaskService taskService() {return new TaskServiceImpl(); }
}
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:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.jdbc.datasource.SimpleDriverDataSource" id="dataSource">
<property name="driverClass" value="${db.driverClass}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="com.spring.intership.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.connection.driver_class">org.h2.Drive</prop>
</props>
</property>
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server" factory-method="createWebServer"
init-method="start" destroy-method="stop">
<constructor-arg value="-web,-webAllowOthers,-webDaemon,-webPort,8082" />
</bean>
<jpa:repositories base-package="com.spring.intership.repositories"/>
</beans>
And i have this in my web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
WEB-INF/config/application-context.xml
WEB-INF/config/application.properties
</param-value>
</context-param>
I have very little experience in MVC spring (a little more in boot) so please consider the most obvious mistakes too;
P.S. My Task.java
#Entity
#Transactional
public class Task {
private long number;
private String description;
private Date date;
#Id
#Column(name = "ID")
public long getNumber()
{
return number;
}
#Basic
#Column(name = "DESCRIPTION")
public String getDescription()
{
return description;
}
#Basic
#Column(name = "DATE")
public Date getDate()
{
return date;
}
public void setNumber(long number)
{
this.number = number;
}
public void setDate(Date date) {
this.date = date;
}
public void setDescription(String description) {
this.description = description;
}
}
try this tips:
Use "#ComponentScan" annotation in "BeanConfiguration" class. Note that you can use "#ComponentScan(basePackages = "com.example.package")" to force scan of the package when your repositories are.
You can use "#EnableJpaRepository(basePackages = "package.of.repositories")" to scan specific package to find ONLY repositories.
Let's check if "Task" class is annoted with "#Entity"
Consider to convert you context to class and try to use annotation instead of xml bean definition.
If you choose to use #ComponentScan annotation consider to scan all packages' tree. If your packages are "com.example.repository", "com.example.controller", "com.example.service" let's scan "com.example" in order to scan also future packages' you will add
I agree with #Luke.
Also you should autowire TaskRepository in TaskService.
public class TaskServiceImpl implements TaskService {
#Autowired
private TaskRepository taskRepository;
....
I am trying to use #Autowired Annotation in Spring for Dependency Injection
through a simple program but i give me following error
Exception in thread "main" java.lang.NullPointerException
at Customer.d(Customer.java:8)
at Main.main(Main.java:12)
Through xml configuration it give me correct result.
My xml file
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd">
<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
<bean id="person" class="Person">
<property name="name" value="khan"/>
</bean>
<bean id="cust" class="Customer"></bean>
</beans>
Customer Class
public class Customer {
#Autowired
private Person p;
public void display(){
System.out.println(p.getName());
}
}
Person Class
public class Person {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
}
Main Class
public class Main {
public static void main(String[] a) {
Resource r=new ClassPathResource("SpringXml.xml");
BeanFactory factory=new XmlBeanFactory(r);
Customer c=(Customer)factory.getBean("cust");
c.display();
}
}
Try like this
public static void main(String[] args) throws Exception {
ApplicationContext context= new ClassPathXmlApplicationContext("SpringXml.xml");
Customer c = (Customer) context.getBean("cust");
c.display();
}
try this :
<bean id="person" class="com.yourpackage.Person">
<property name="name" value="khan"/>
</bean>
<bean id="cust" class="com.yourpackage.Customer">
<property name="p" ref="person"/>
</bean>
dont forget to add your fullpath class package
when i use hibernate to save entity i found that session can't save it in Transaction. i must flush and clear session.but i have not to do like this before in other projects,is there anything wrong with the transaction configs in my xml files?Any answers are appreciated : )
hibernate.cfg.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
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/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:property-placeholder location="classpath:application.properties"/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="username" value="${db.userName}"></property>
<property name="password" value="${db.password}"></property>
</bean>
<bean id="sessionFactory" name="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<!--<prop key="current_session_context_class">thread</prop>-->
</props>
</property>
<property name="packagesToScan" value="com.gtis"/>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<!--<bean id="transactionProxy"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager"></property>
<property name="transactionAttributes">
<props>
<prop key="save*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-myException</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>-->
<!--<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="create*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="del*" propagation="REQUIRED" />
<tx:method name="import*" propagation="REQUIRED" />
<tx:method name="*" propagation="NOT_SUPPORTED" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceOperation" expression="execution(* com.gtis.service.*Service.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>-->
</beans>
Dao
package com.gtis.dao;
import com.gtis.model.Student;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.util.List;
/**
* Created by u on 2016/3/15.
*/
#Repository
public class StudentDao {
#Resource
private SessionFactory sessionFactory;
private Session getSession(){
return sessionFactory.getCurrentSession();
}
public Student query(String id) throws Exception{
if(StringUtils.isBlank(id)){
return (Student)getSession().get(Student.class,id);
}else{
throw new Exception("id is required");
}
}
public List<Student> queryAll(){
String hql = "from com.gtis.model.Student";
Query query = getSession().createQuery(hql);
return query.list();
}
public void save(Student student)throws Exception{
if(student!=null){
System.out.println("sessionFactory="+sessionFactory);
System.out.println("session="+getSession());
// Session session = getSession();
getSession().save(student);
// session.flush();
// session.clear();
// session.close();
}else{
throw new Exception("object is required");
}
}
public void delete(Student student)throws Exception{
if(student!=null){
getSession().delete(student);
}else{
throw new Exception("object is required");
}
}
}
Service
package com.gtis.service;
import com.gtis.dao.StudentDao;
import com.gtis.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/**
* Created by u on 2016/3/15.
*/
#Service
public class StudentService {
#Autowired
StudentDao studentDao;
public Student getStudent(String id) throws Exception {
return studentDao.query(id);
}
public List<Student> getAll() throws Exception{
return studentDao.queryAll();
}
#Transactional
public void save(Student student)throws Exception{
studentDao.save(student);
}
#Transactional
public void delete(Student student) throws Exception{
studentDao.delete(student);
}
}
> Controller
package com.gtis.controller;
import com.gtis.model.Student;
import com.gtis.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* Created by u on 2016/3/15.
*/
#Controller
public class StudentController {
#Autowired
StudentService studentService;
#RequestMapping("get")
public String get(){
Student student = new Student();
student.setName("avc");
try {
studentService.save(student);
} catch (Exception e) {
e.printStackTrace();
}
return "somwhere";
}
}
Your DAO should implement an interface and inject that interface via Autowired to your Service which uses the #Transactional annotation in order to work.
So:
#Repository
public class StudentDao implements StudentDaoInterface {
//your rest code here
}
And:
#Service
public class StudentService {
#Autowired
StudentDaoInterface studentDao;
public Student getStudent(String id) throws Exception {
return studentDao.query(id);
}
public List<Student> getAll() throws Exception{
return studentDao.queryAll();
}
#Transactional
public void save(Student student)throws Exception{
studentDao.save(student);
}
#Transactional
public void delete(Student student) throws Exception{
studentDao.delete(student);
}
}
And of course dont forget to declare your public methods of your DAO to the interface.
Oh and do the same for your Service class (interface, autowire the interface instead of the class etc).
You should Autowired the sessionfactory to give spring a full control to commit your transactions.
This here is a little test class that I have. Problem is that it is not rolling back the transaction after each test run. What have I done wrong? :)
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/META-INF/catalog-spring.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class TermTest
{
#Autowired
private CatalogService service;
#Rollback(true)
#Test
public void testSimplePersist()
{
Term term = new Term();
term.setDescription("Description");
term.setName("BirdSubject8");
term.setIsEnabled("F");
term.setIsSystem("F");
term.setTermType("TERM");
service.createTerm(term);
}
}
and my spring config
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="catalog2"></property>
</bean>
<bean id="catalogService" class="com.moo.catalog.service.CatalogService">
<property name="termDao" ref="termDao"></property>
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven />
You need #Transactional in addition to #TransactionConfiguration:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "/META-INF/catalog-spring.xml" })
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class TermTest { ... }
in spring 4.0 later because TransactionConfiguration is deprecated
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/config/spring-config.xml")
#Transactional
public class UserTest {
#Rollback
public void test(){
}
}