From 29327798c11c6631009ab91d1e49d263fd8c7553 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Sat, 11 Jul 2009 16:45:48 +0000 Subject: [PATCH] [SPR-5699] Investigating issues surrounding automatic flushing of the underlying ORM tool's session via TransactionalTestExecutionListener. --- org.springframework.test/.classpath | 4 + org.springframework.test/ivy.xml | 13 ++- .../HibernateSessionFlushingTests-context.xml | 39 +++++++ .../orm/HibernateSessionFlushingTests.java | 109 ++++++++++++++++++ .../test/context/junit4/orm/db-schema.sql | 16 +++ .../test/context/junit4/orm/db-test-data.sql | 3 + .../junit4/orm/domain/DriversLicense.hbm.xml | 14 +++ .../junit4/orm/domain/DriversLicense.java | 60 ++++++++++ .../context/junit4/orm/domain/Person.hbm.xml | 16 +++ .../context/junit4/orm/domain/Person.java | 76 ++++++++++++ .../orm/repository/PersonRepository.java | 33 ++++++ .../hibernate/HibernatePersonRepository.java | 51 ++++++++ .../junit4/orm/service/PersonService.java | 33 ++++++ .../service/impl/StandardPersonService.java | 53 +++++++++ 14 files changed, 515 insertions(+), 5 deletions(-) create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests-context.xml create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-schema.sql create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-test-data.sql create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.hbm.xml create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/PersonRepository.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/PersonService.java create mode 100644 org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/impl/StandardPersonService.java diff --git a/org.springframework.test/.classpath b/org.springframework.test/.classpath index 247b29a9f8b..b2fe691626b 100644 --- a/org.springframework.test/.classpath +++ b/org.springframework.test/.classpath @@ -27,6 +27,10 @@ + + + + diff --git a/org.springframework.test/ivy.xml b/org.springframework.test/ivy.xml index 9e4dfd64eda..c09ff16e058 100644 --- a/org.springframework.test/ivy.xml +++ b/org.springframework.test/ivy.xml @@ -25,12 +25,15 @@ - - + - + + + + + @@ -41,7 +44,7 @@ - + - + \ No newline at end of file diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests-context.xml b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests-context.xml new file mode 100644 index 00000000000..d1f5ca7849a --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests-context.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + org.hibernate.dialect.HSQLDialect + false + + + + + org/springframework/test/context/junit4/orm/domain/Person.hbm.xml + org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml + + + + + + + diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java new file mode 100644 index 00000000000..78d9e58e9cb --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/HibernateSessionFlushingTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.springframework.test.transaction.TransactionTestUtils.assertInTransaction; + +import org.hibernate.SessionFactory; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.GenericJDBCException; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests; +import org.springframework.test.context.junit4.orm.domain.DriversLicense; +import org.springframework.test.context.junit4.orm.domain.Person; +import org.springframework.test.context.junit4.orm.service.PersonService; + +/** + * Transactional integration tests regarding automatic vs. manual session + * flushing with Hibernate. + * + * @author Sam Brannen + * @since 3.0 + */ +@ContextConfiguration +public class HibernateSessionFlushingTests extends AbstractTransactionalJUnit4SpringContextTests { + + private static final String SAM = "Sam"; + private static final String JUERGEN = "Juergen"; + + @Autowired + private PersonService personService; + + @Autowired + private SessionFactory sessionFactory; + + + @Before + public void setUp() { + assertInTransaction(true); + assertNotNull("PersonService should have been autowired.", personService); + assertNotNull("SessionFactory should have been autowired.", sessionFactory); + } + + @Test + public void findSam() { + Person sam = personService.findByName(SAM); + assertNotNull("Should be able to find Sam", sam); + DriversLicense driversLicense = sam.getDriversLicense(); + assertNotNull("Sam's driver's license should not be null", driversLicense); + assertEquals("Verifying Sam's driver's license number", new Long(1234), driversLicense.getNumber()); + } + + @Test + public void saveJuergenWithDriversLicense() { + DriversLicense driversLicense = new DriversLicense(2L, 2222L); + Person juergen = new Person(JUERGEN, driversLicense); + personService.save(juergen); + assertNotNull("Should be able to save and retrieve Juergen", personService.findByName(JUERGEN)); + assertNotNull("Juergen's ID should have been set", juergen.getId()); + } + + @Ignore("Disabled until SPR-5699 is resolved") + @Test(expected = ConstraintViolationException.class) + public void saveJuergenWithNullDriversLicense() { + personService.save(new Person(JUERGEN)); + } + + private void updateSamWithNullDriversLicense() { + Person sam = personService.findByName(SAM); + assertNotNull("Should be able to find Sam", sam); + sam.setDriversLicense(null); + personService.save(sam); + } + + @Test(expected = GenericJDBCException.class) + // @IfProfileValue(name = "spring-compatibility", value = "2.5.6") + public void updateSamWithNullDriversLicenseSpring256() { + updateSamWithNullDriversLicense(); + sessionFactory.getCurrentSession().flush(); + } + + @Ignore("Disabled until SPR-5699 is resolved") + @Test(expected = GenericJDBCException.class) + // @Test(expected = UncategorizedSQLException.class) + // @IfProfileValue(name = "spring-compatibility", value = "3.0.0.M2") + public void updateSamWithNullDriversLicenseSpring300() { + updateSamWithNullDriversLicense(); + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-schema.sql b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-schema.sql new file mode 100644 index 00000000000..960b101e7fe --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-schema.sql @@ -0,0 +1,16 @@ +DROP TABLE drivers_license IF EXISTS; +DROP TABLE person IF EXISTS; + +CREATE TABLE person ( + id INTEGER NOT NULL IDENTITY PRIMARY KEY, + name VARCHAR(50) NOT NULL, + drivers_license_id INTEGER NOT NULL +); +CREATE UNIQUE INDEX person_name ON person(name); +CREATE UNIQUE INDEX person_drivers_license_id ON person(drivers_license_id); + +CREATE TABLE drivers_license ( + id INTEGER NOT NULL IDENTITY PRIMARY KEY, + license_number INTEGER NOT NULL +); +CREATE UNIQUE INDEX drivers_license_license_number ON drivers_license(license_number); diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-test-data.sql b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-test-data.sql new file mode 100644 index 00000000000..a174e3fbed7 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/db-test-data.sql @@ -0,0 +1,3 @@ +INSERT INTO drivers_license(id, license_number) values(1, 1234); + +INSERT INTO person(id, name, drivers_license_id) values(1, 'Sam', 1); diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml new file mode 100644 index 00000000000..025256301ad --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.java new file mode 100644 index 00000000000..cdb2b0f884d --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/DriversLicense.java @@ -0,0 +1,60 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.domain; + +/** + * DriversLicense POJO. + * + * @author Sam Brannen + * @since 3.0 + */ +public class DriversLicense { + + private Long id; + + private Long number; + + + public DriversLicense() { + } + + public DriversLicense(Long number) { + this(null, number); + } + + public DriversLicense(Long id, Long number) { + this.id = id; + this.number = number; + } + + public Long getId() { + return this.id; + } + + protected void setId(Long id) { + this.id = id; + } + + public Long getNumber() { + return this.number; + } + + public void setNumber(Long number) { + this.number = number; + } + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.hbm.xml b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.hbm.xml new file mode 100644 index 00000000000..aa6478b9891 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.java new file mode 100644 index 00000000000..e264f66e8e5 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/domain/Person.java @@ -0,0 +1,76 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.domain; + +/** + * Person POJO. + * + * @author Sam Brannen + * @since 3.0 + */ +public class Person { + + private Long id; + private String name; + private DriversLicense driversLicense; + + + public Person() { + } + + public Person(Long id) { + this(id, null, null); + } + + public Person(String name) { + this(name, null); + } + + public Person(String name, DriversLicense driversLicense) { + this(null, name, driversLicense); + } + + public Person(Long id, String name, DriversLicense driversLicense) { + this.id = id; + this.name = name; + this.driversLicense = driversLicense; + } + + public Long getId() { + return this.id; + } + + protected void setId(Long id) { + this.id = id; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public DriversLicense getDriversLicense() { + return this.driversLicense; + } + + public void setDriversLicense(DriversLicense driversLicense) { + this.driversLicense = driversLicense; + } +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/PersonRepository.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/PersonRepository.java new file mode 100644 index 00000000000..a0b7730d31c --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/PersonRepository.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.repository; + +import org.springframework.test.context.junit4.orm.domain.Person; + +/** + * Person Repository API. + * + * @author Sam Brannen + * @since 3.0 + */ +public interface PersonRepository { + + Person findByName(String name); + + Person save(Person person); + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java new file mode 100644 index 00000000000..702dfcae7e4 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/repository/hibernate/HibernatePersonRepository.java @@ -0,0 +1,51 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.repository.hibernate; + +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.test.context.junit4.orm.domain.Person; +import org.springframework.test.context.junit4.orm.repository.PersonRepository; + +/** + * Hibernate implementation of the {@link PersonRepository} API. + * + * @author Sam Brannen + * @since 3.0 + */ +@Repository +public class HibernatePersonRepository implements PersonRepository { + + private final SessionFactory sessionFactory; + + + @Autowired + public HibernatePersonRepository(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + public Person save(Person person) { + this.sessionFactory.getCurrentSession().save(person); + return person; + } + + public Person findByName(String name) { + return (Person) this.sessionFactory.getCurrentSession().createQuery( + "from Person person where person.name = :name").setString("name", name).uniqueResult(); + } +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/PersonService.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/PersonService.java new file mode 100644 index 00000000000..73aa29a5c31 --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/PersonService.java @@ -0,0 +1,33 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.service; + +import org.springframework.test.context.junit4.orm.domain.Person; + +/** + * Person Service API. + * + * @author Sam Brannen + * @since 3.0 + */ +public interface PersonService { + + Person findByName(String name); + + Person save(Person person); + +} diff --git a/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/impl/StandardPersonService.java b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/impl/StandardPersonService.java new file mode 100644 index 00000000000..dbd7fe6c22b --- /dev/null +++ b/org.springframework.test/src/test/java/org/springframework/test/context/junit4/orm/service/impl/StandardPersonService.java @@ -0,0 +1,53 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.junit4.orm.service.impl; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.test.context.junit4.orm.domain.Person; +import org.springframework.test.context.junit4.orm.repository.PersonRepository; +import org.springframework.test.context.junit4.orm.service.PersonService; +import org.springframework.transaction.annotation.Transactional; + +/** + * Standard implementation of the {@link PersonService} API. + * + * @author Sam Brannen + * @since 3.0 + */ +@Service +@Transactional(readOnly = true) +public class StandardPersonService implements PersonService { + + private final PersonRepository personRepository; + + + @Autowired + public StandardPersonService(PersonRepository personRepository) { + this.personRepository = personRepository; + } + + public Person findByName(String name) { + return this.personRepository.findByName(name); + } + + @Transactional(readOnly = false) + public Person save(Person person) { + return this.personRepository.save(person); + } + +}