RESOLVED - issue BATCH-1340: Add Support for Native Queries to Jpa/Hibernate readers

This commit is contained in:
dsyer
2010-01-13 14:18:17 +00:00
parent 2977c2076c
commit 6c30182e03
16 changed files with 992 additions and 21 deletions

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.batch.item.database;
import java.util.Map;
import org.hibernate.Query;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
@@ -25,6 +27,7 @@ import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
import org.springframework.batch.item.database.support.AbstractHibernateQueryProvider;
import org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@@ -68,6 +71,10 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
private String queryName = "";
private Map<String, Object> parameterValues;
private HibernateQueryProvider queryProvider;
private boolean useStatelessSession = true;
private boolean initialized = false;
@@ -77,29 +84,53 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
public HibernateCursorItemReader() {
setName(ClassUtils.getShortName(HibernateCursorItemReader.class));
}
/**
* The parameter values to apply to a query (map of name:value).
*
* @param parameterValues the parameter values to set
*/
public void setParameterValues(Map<String, Object> parameterValues) {
this.parameterValues = parameterValues;
}
/**
* Open appropriate type of hibernate session and create the query.
*/
private Query createQuery() {
if (useStatelessSession) {
statelessSession = sessionFactory.openStatelessSession();
if (StringUtils.hasText(queryName)) {
return statelessSession.getNamedQuery(queryName);
if (queryProvider != null) {
queryProvider.setStatelessSession(statelessSession);
}
else {
return statelessSession.createQuery(queryString);
if (StringUtils.hasText(queryName)) {
return statelessSession.getNamedQuery(queryName);
}
else {
return statelessSession.createQuery(queryString);
}
}
}
else {
statefulSession = sessionFactory.openSession();
if (StringUtils.hasText(queryName)) {
return statefulSession.getNamedQuery(queryName);
if (queryProvider != null) {
queryProvider.setSession(statefulSession);
}
else {
return statefulSession.createQuery(queryString);
if (StringUtils.hasText(queryName)) {
return statefulSession.getNamedQuery(queryName);
}
else {
return statefulSession.createQuery(queryString);
}
}
}
// if queryProvider is set use it to create a query
return queryProvider.createQuery();
}
/**
@@ -110,10 +141,21 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
}
public void afterPropertiesSet() throws Exception {
Assert.notNull(sessionFactory, "session factory must be set");
Assert.isTrue(fetchSize >= 0, "fetchSize must not be negative");
Assert.isTrue(StringUtils.hasText(queryString) ^ StringUtils.hasText(queryName),
"exactly one of queryString or queryName must be set");
Assert.state(sessionFactory!=null, "A SessionFactory must be provided");
Assert.state(fetchSize >= 0, "fetchSize must not be negative");
if (queryProvider == null) {
Assert.notNull(sessionFactory, "session factory must be set");
Assert.state(StringUtils.hasText(queryString) ^ StringUtils.hasText(queryName),
"queryString or queryName must be set");
}
// making sure that the appropriate (Hibernate) query provider is set
else {
Assert.state(queryProvider instanceof AbstractHibernateQueryProvider,
"Hibernate query provider must be set");
}
}
/**
@@ -130,6 +172,13 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
this.queryString = queryString;
}
/**
* @param queryProvider Hibernate query provider
*/
public void setQueryProvider(HibernateQueryProvider queryProvider) {
this.queryProvider = queryProvider;
}
/**
* Can be set only in uninitialized state.
*
@@ -193,24 +242,27 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
/**
* Open hibernate session and create a forward-only cursor for the
* {@link #setQueryString(String)}.
* query.
*/
protected void doOpen() throws Exception {
Assert.state(!initialized, "Cannot open an already opened ItemReader, call close first");
cursor = createQuery().setFetchSize(fetchSize).scroll(ScrollMode.FORWARD_ONLY);
Query query = createQuery();
if (parameterValues!=null) {
query.setProperties(parameterValues);
}
cursor = query.setFetchSize(fetchSize).scroll(ScrollMode.FORWARD_ONLY);
initialized = true;
}
@Override
protected void jumpToItem(int itemIndex) throws Exception {
for(int i = 0; i < itemIndex; i++){
for (int i = 0; i < itemIndex; i++) {
cursor.next();
}
}
/**
* Close the cursor and hibernate session.
*/
@@ -220,6 +272,7 @@ public class HibernateCursorItemReader<T> extends AbstractItemCountingItemStream
if (cursor != null) {
cursor.close();
}
if (useStatelessSession) {
if (statelessSession != null) {
statelessSession.close();

View File

@@ -0,0 +1,78 @@
/*
* Copyright 2006-2008 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.batch.item.database;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.springframework.batch.item.ItemReader;
/**
* <p>
* Interface defining the functionality to be provided for generating queries
* for use with Hibernate {@link ItemReader}s or other custom built artifacts.
* </p>
*
* @author Anatoly Polinsky
* @author Dave Syer
*
* @since 2.1
*
*/
public interface HibernateQueryProvider {
/**
* <p>
* Create the query object which type will be determined by the underline
* implementation (e.g. Hibernate, JPA, etc.)
* </p>
*
* @return created query
*/
Query createQuery();
/**
* <p>
* Inject a {@link Session} that can be used as a factory for queries. The
* state of the session is controlled by the caller (i.e. it should be
* closed if necessary).
* </p>
*
* <p>
* Use either this method or {@link #setStatelessSession(StatelessSession)}
* </p>
*
* @param session the {@link Session} to set
*/
void setSession(Session session);
/**
* <p>
* Inject a {@link StatelessSession} that can be used as a factory for
* queries. The state of the session is controlled by the caller (i.e. it
* should be closed if necessary).
* </p>
*
* <p>
* Use either this method or {@link #setSession(Session)}
* </p>
*
* @param session the {@link StatelessSession} to set
*/
void setStatelessSession(StatelessSession session);
}

View File

@@ -26,6 +26,7 @@ import javax.persistence.EntityTransaction;
import javax.persistence.Query;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.database.support.AbstractJpaQueryProvider;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -90,12 +91,27 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
private String queryString;
private JpaQueryProvider queryProvider;
private Map<String, Object> parameterValues;
public JpaPagingItemReader() {
setName(ClassUtils.getShortName(JpaPagingItemReader.class));
}
/**
* Create a query using an appropriate query provider (entityManager OR
* queryProvider).
*/
private Query createQuery() {
if (queryProvider == null) {
return entityManager.createQuery(queryString);
}
else {
return queryProvider.createQuery();
}
}
public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory) {
this.entityManagerFactory = entityManagerFactory;
}
@@ -112,8 +128,15 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
Assert.notNull(entityManagerFactory);
Assert.hasLength(queryString);
if (queryProvider == null) {
Assert.notNull(entityManagerFactory);
Assert.hasLength(queryString);
}
// making sure that the appropriate (JPA) query provider is set
else {
Assert.isTrue(queryProvider instanceof AbstractJpaQueryProvider, "JPA query provider must be set");
}
}
/**
@@ -123,13 +146,27 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
this.queryString = queryString;
}
/**
* @param queryProvider JPA query provider
*/
public void setQueryProvider(JpaQueryProvider queryProvider) {
this.queryProvider = queryProvider;
}
@Override
protected void doOpen() throws Exception {
super.doOpen();
entityManager = entityManagerFactory.createEntityManager(jpaPropertyMap);
if (entityManager == null) {
throw new DataAccessResourceFailureException("Unable to obtain an EntityManager");
}
// set entityManager to queryProvider, so it participates
// in JpaPagingItemReader's managed transaction
if (queryProvider != null) {
queryProvider.setEntityManager(entityManager);
}
}
@Override
@@ -142,8 +179,7 @@ public class JpaPagingItemReader<T> extends AbstractPagingItemReader<T> {
entityManager.flush();
entityManager.clear();
Query query = entityManager.createQuery(queryString).setFirstResult(getPage() * getPageSize()).setMaxResults(
getPageSize());
Query query = createQuery().setFirstResult(getPage() * getPageSize()).setMaxResults(getPageSize());
if (parameterValues != null) {
for (Map.Entry<String, Object> me : parameterValues.entrySet()) {

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2006-2008 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.batch.item.database;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.batch.item.ItemReader;
/**
* <p>Interface defining the functionality to be provided for generating queries
* for use with JPA {@link ItemReader}s or other custom built artifacts.</p>
*
* @author Anatoly Polinsky
* @author Dave Syer
* @since 2.1
*
*/
public interface JpaQueryProvider {
/**
* <p>Create the query object.</p>
*
* @return created query
*/
public Query createQuery();
/**
* Provide an {@link EntityManager} for the query to be built.
*
* @param entityManager
*/
void setEntityManager(EntityManager entityManager);
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.springframework.batch.item.database.HibernateQueryProvider;
/**
* <p>Abstract Hibernate Query Provider to serve as a base class for all
* Hibernate {@link Query} providers.</p>
*
* <p>The implementing provider can be configured to use either
* {@link StatelessSession} sufficient for simple mappings without the need
* to cascade to associated objects or standard Hibernate {@link Session}
* for more advanced mappings or when caching is desired.</p>
*
* @author Anatoly Polinsky
* @author Dave Syer
*
* @since 2.1
*
*/
public abstract class AbstractHibernateQueryProvider implements HibernateQueryProvider {
private StatelessSession statelessSession;
private Session statefulSession;
public void setStatelessSession(StatelessSession statelessSession) {
this.statelessSession = statelessSession;
}
public void setSession(Session statefulSession) {
this.statefulSession = statefulSession;
}
public boolean isStatelessSession() {
return this.statefulSession==null && this.statelessSession!=null;
}
protected StatelessSession getStatelessSession() {
return statelessSession;
}
protected Session getStatefulSession() {
return statefulSession;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.batch.item.database.JpaQueryProvider;
import org.springframework.batch.item.database.HibernateQueryProvider;
import org.springframework.beans.factory.InitializingBean;
/**
* <p>
* Abstract JPA Query Provider to serve as a base class for all JPA
* {@link Query} providers.
* </p>
*
* @author Anatoly Polinsky
* @author Dave Syer
*
* @since 2.1
*/
public abstract class AbstractJpaQueryProvider implements JpaQueryProvider, InitializingBean {
private EntityManager entityManager;
/**
* <p>
* Public setter to override the entityManager that was created by this
* {@link HibernateQueryProvider}. This is currently needed to allow
* {@link HibernateQueryProvider} to participate in a user's managed transaction.
* </p>
*
* @param entityManager
*/
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/**
* <p>
* Getter for {@link EntityManager}
* </p>
*
* @return entityManager the injected {@link EntityManager}
*/
protected EntityManager getEntityManager() {
return entityManager;
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* <p>
* This query provider creates Hibernate {@link Query}s from injected native SQL
* queries. This is useful if there is a need to utilize database-specific
* features such as query hints, the CONNECT keyword in Oracle, etc.
* </p>
*
* @author Anatoly Polinsky
*
* @param <E> entity returned by executing the query
*/
public class HibernateNativeQueryProvider<E> extends AbstractHibernateQueryProvider {
private String sqlQuery;
private Class<E> entityClass;
/**
* <p>
* Create an {@link SQLQuery} from the session provided (preferring
* stateless if both are available).
* </p>
*/
public SQLQuery createQuery() {
if (isStatelessSession()) {
return getStatelessSession().createSQLQuery(sqlQuery).addEntity(entityClass);
}
else {
return getStatefulSession().createSQLQuery(sqlQuery).addEntity(entityClass);
}
}
public void setSqlQuery(String sqlQuery) {
this.sqlQuery = sqlQuery;
}
public void setEntityClass(Class<E> entityClazz) {
this.entityClass = entityClazz;
}
public void afterPropertiesSet() throws Exception {
Assert.isTrue(StringUtils.hasText(sqlQuery), "Native SQL query cannot be empty");
Assert.notNull(entityClass, "Entity class cannot be NULL");
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import javax.persistence.Query;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* <p>
* This query provider creates JPA {@link Query}s from injected native SQL
* queries. This is useful if there is a need to utilize database-specific
* features such as query hints, the CONNECT keyword in Oracle, etc.
* </p>
*
* @author Anatoly Polinsky
*
* @param <E> entity returned by executing the query
*/
public class JpaNativeQueryProvider<E> extends AbstractJpaQueryProvider {
private Class<E> entityClass;
private String sqlQuery;
public Query createQuery() {
return getEntityManager().createNativeQuery(sqlQuery, entityClass);
}
public void setSqlQuery(String sqlQuery) {
this.sqlQuery = sqlQuery;
}
public void setEntityClass(Class<E> entityClazz) {
this.entityClass = entityClazz;
}
public void afterPropertiesSet() throws Exception {
Assert.isTrue(StringUtils.hasText(sqlQuery), "Native SQL query cannot be empty");
Assert.notNull(entityClass, "Entity class cannot be NULL");
}
}

View File

@@ -0,0 +1,47 @@
package org.springframework.batch.item.database;
import org.hibernate.SessionFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.support.HibernateNativeQueryProvider;
import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
public class HibernateCursorItemReaderNativeQueryIntegrationTests extends HibernateCursorItemReaderIntegrationTests {
public ItemReader<Foo> createItemReader() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject();
HibernateCursorItemReader<Foo> hibernateReader = new HibernateCursorItemReader<Foo>();
String nativeQuery = "select * from T_FOOS";
//creating a native query provider as it would be created in configuration
HibernateNativeQueryProvider<Foo> queryProvider =
new HibernateNativeQueryProvider<Foo>();
queryProvider.setSqlQuery(nativeQuery);
queryProvider.setEntityClass(Foo.class);
queryProvider.afterPropertiesSet();
hibernateReader.setQueryProvider(queryProvider);
//hibernateReader.setUseStatelessSession(isUseStatelessSession());
hibernateReader.setSessionFactory(sessionFactory);
hibernateReader.setSaveState(true);
hibernateReader.afterPropertiesSet();
return hibernateReader;
}
}

View File

@@ -0,0 +1,54 @@
package org.springframework.batch.item.database;
import java.util.Collections;
import org.hibernate.SessionFactory;
import org.hibernate.StatelessSession;
import org.junit.runner.RunWith;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.sample.Foo;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* Tests for {@link HibernateCursorItemReader} using {@link StatelessSession}.
*
* @author Robert Kasanicky
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "data-source-context.xml")
public class HibernateCursorItemReaderParametersIntegrationTests extends AbstractDataSourceItemReaderIntegrationTests {
protected ItemReader<Foo> createItemReader() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
SessionFactory sessionFactory = (SessionFactory) factoryBean.getObject();
HibernateCursorItemReader<Foo> hibernateReader = new HibernateCursorItemReader<Foo>();
setQuery(hibernateReader);
hibernateReader.setSessionFactory(sessionFactory);
hibernateReader.setUseStatelessSession(isUseStatelessSession());
hibernateReader.afterPropertiesSet();
hibernateReader.setSaveState(true);
return hibernateReader;
}
protected void setQuery(HibernateCursorItemReader<?> reader) {
reader.setQueryString("from Foo where name like :name");
reader.setParameterValues(Collections.singletonMap("name", (Object)"bar%"));
}
protected boolean isUseStatelessSession() {
return true;
}
}

View File

@@ -1,5 +1,7 @@
package org.springframework.batch.item.database;
import java.util.Collections;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.ContextConfiguration;
@@ -28,10 +30,11 @@ public class JpaPagingItemReaderIntegrationTests extends AbstractDataSourceItemR
EntityManagerFactory entityManagerFactory = factoryBean.getObject();
String jpqlQuery = "select f from Foo f";
String jpqlQuery = "select f from Foo f where name like :name";
JpaPagingItemReader<Foo> inputSource = new JpaPagingItemReader<Foo>();
inputSource.setQueryString(jpqlQuery);
inputSource.setParameterValues(Collections.singletonMap("name", (Object)"bar%"));
inputSource.setEntityManagerFactory(entityManagerFactory);
inputSource.setPageSize(3);
inputSource.afterPropertiesSet();

View File

@@ -0,0 +1,47 @@
package org.springframework.batch.item.database;
import java.util.Collections;
import javax.persistence.EntityManagerFactory;
import org.junit.runner.RunWith;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.database.support.JpaNativeQueryProvider;
import org.springframework.batch.item.sample.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"JpaPagingItemReaderParameterTests-context.xml"})
public class JpaPagingItemReaderNativeQueryIntegrationTests extends AbstractPagingItemReaderParameterTests {
@Autowired
private EntityManagerFactory entityManagerFactory;
protected ItemReader<Foo> getItemReader() throws Exception {
String sqlQuery = "select * from T_FOOS where value >= :limit";
JpaPagingItemReader<Foo> reader = new JpaPagingItemReader<Foo>();
//creating a native query provider as it would be created in configuration
JpaNativeQueryProvider<Foo> queryProvider= new JpaNativeQueryProvider<Foo>();
queryProvider.setSqlQuery(sqlQuery);
queryProvider.setEntityClass(Foo.class);
queryProvider.afterPropertiesSet();
reader.setParameterValues(Collections.<String, Object>singletonMap("limit", 3));
reader.setEntityManagerFactory(entityManagerFactory);
reader.setPageSize(3);
reader.setQueryProvider(queryProvider);
reader.afterPropertiesSet();
reader.setSaveState(true);
return reader;
}
}

View File

@@ -0,0 +1,103 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.item.sample.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.orm.hibernate3.LocalSessionFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "../data-source-context.xml")
public class HibernateNativeQueryProviderIntegrationTests {
protected DataSource dataSource;
protected HibernateNativeQueryProvider<Foo> hibernateQueryProvider;
private SessionFactory sessionFactory;
@Autowired
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public HibernateNativeQueryProviderIntegrationTests() {
hibernateQueryProvider = new HibernateNativeQueryProvider<Foo>();
hibernateQueryProvider.setEntityClass(Foo.class);
}
@Before
public void setUp() throws Exception {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setDataSource(dataSource);
factoryBean.setMappingLocations(new Resource[] { new ClassPathResource("../Foo.hbm.xml", getClass()) });
factoryBean.afterPropertiesSet();
sessionFactory = (SessionFactory) factoryBean.getObject();
}
@Test
@Transactional
public void shouldRetrieveAndMapAllFoos() throws Exception {
String nativeQuery = "select * from T_FOOS";
hibernateQueryProvider.setSqlQuery(nativeQuery);
hibernateQueryProvider.afterPropertiesSet();
hibernateQueryProvider.setSession(sessionFactory.getCurrentSession());
Query query = hibernateQueryProvider.createQuery();
List<Foo> expectedFoos = new ArrayList<Foo>();
expectedFoos.add(new Foo(1, "bar1", 1));
expectedFoos.add(new Foo(2, "bar2", 2));
expectedFoos.add(new Foo(3, "bar3", 3));
expectedFoos.add(new Foo(4, "bar4", 4));
expectedFoos.add(new Foo(5, "bar5", 5));
@SuppressWarnings("unchecked")
List<Foo> actualFoos = query.list();
assertEquals(actualFoos, expectedFoos);
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import org.hibernate.SQLQuery;
import org.hibernate.StatelessSession;
import org.hibernate.classic.Session;
import org.junit.Test;
import org.springframework.util.Assert;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
public class HibernateNativeQueryProviderTests {
protected HibernateNativeQueryProvider<Foo> hibernateQueryProvider;
public HibernateNativeQueryProviderTests() {
hibernateQueryProvider = new HibernateNativeQueryProvider<Foo>();
hibernateQueryProvider.setEntityClass(Foo.class);
}
@Test
public void testCreateQueryWithStatelessSession() {
String sqlQuery = "select * from T_FOOS";
hibernateQueryProvider.setSqlQuery(sqlQuery);
StatelessSession session = createMock(StatelessSession.class);
SQLQuery query = createMock(SQLQuery.class);
expect(session.createSQLQuery(sqlQuery)).andReturn(query);
expect(query.addEntity(Foo.class)).andReturn(query);
replay(session, query);
hibernateQueryProvider.setStatelessSession(session);
Assert.notNull(hibernateQueryProvider.createQuery());
verify(session, query);
}
@Test
public void shouldCreateQueryWithStatefulSession() {
String sqlQuery = "select * from T_FOOS";
hibernateQueryProvider.setSqlQuery(sqlQuery);
Session session = createMock(Session.class);
SQLQuery query = createMock(SQLQuery.class);
expect(session.createSQLQuery(sqlQuery)).andReturn(query);
expect(query.addEntity(Foo.class)).andReturn(query);
replay(session, query);
hibernateQueryProvider.setSession(session);
Assert.notNull(hibernateQueryProvider.createQuery());
verify(session, query);
}
private static class Foo {
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.item.sample.Foo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "../JpaPagingItemReaderCommonTests-context.xml" })
public class JpaNativeQueryProviderIntegrationTests {
@Autowired
private EntityManagerFactory entityManagerFactory;
private JpaNativeQueryProvider<Foo> jpaQueryProvider;
public JpaNativeQueryProviderIntegrationTests() {
jpaQueryProvider = new JpaNativeQueryProvider<Foo>();
jpaQueryProvider.setEntityClass(Foo.class);
}
@Test
@Transactional
public void shouldRetrieveAndMapAllFoos() throws Exception {
String sqlQuery = "select * from T_FOOS";
jpaQueryProvider.setSqlQuery(sqlQuery);
jpaQueryProvider.afterPropertiesSet();
jpaQueryProvider.setEntityManager(entityManagerFactory.createEntityManager());
Query query = jpaQueryProvider.createQuery();
List<Foo> expectedFoos = new ArrayList<Foo>();
expectedFoos.add(new Foo(1, "bar1", 1));
expectedFoos.add(new Foo(2, "bar2", 2));
expectedFoos.add(new Foo(3, "bar3", 3));
expectedFoos.add(new Foo(4, "bar4", 4));
expectedFoos.add(new Foo(5, "bar5", 5));
@SuppressWarnings("unchecked")
List<Foo> actualFoos = query.getResultList();
assertEquals(actualFoos, expectedFoos);
}
@Test
@Transactional
public void shouldExecuteParameterizedQuery() throws Exception {
String sqlQuery = "select * from T_FOOS where value >= :limit";
jpaQueryProvider.setSqlQuery(sqlQuery);
jpaQueryProvider.afterPropertiesSet();
jpaQueryProvider.setEntityManager(entityManagerFactory.createEntityManager());
Query query = jpaQueryProvider.createQuery();
query.setParameter("limit", 3);
List<Foo> expectedFoos = new ArrayList<Foo>();
expectedFoos.add(new Foo(3, "bar3", 3));
expectedFoos.add(new Foo(4, "bar4", 4));
expectedFoos.add(new Foo(5, "bar5", 5));
@SuppressWarnings("unchecked")
List<Foo> actualFoos = query.getResultList();
assertEquals(actualFoos, expectedFoos);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2006-2008 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.batch.item.database.support;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.junit.Test;
import org.springframework.batch.item.sample.Foo;
import org.springframework.util.Assert;
/**
* @author Anatoly Polinsky
* @author Dave Syer
*/
public class JpaNativeQueryProviderTests {
private JpaNativeQueryProvider<Foo> jpaQueryProvider;
public JpaNativeQueryProviderTests() {
jpaQueryProvider = new JpaNativeQueryProvider<Foo>();
jpaQueryProvider.setEntityClass(Foo.class);
}
@Test
public void testCreateQuery() {
String sqlQuery = "select * from T_FOOS where value >= :limit";
jpaQueryProvider.setSqlQuery(sqlQuery);
EntityManager entityManager = createMock(EntityManager.class);
Query query = createMock(Query.class);
expect(entityManager.createNativeQuery(sqlQuery, Foo.class)).andReturn(query);
replay(entityManager);
jpaQueryProvider.setEntityManager(entityManager);
Assert.notNull(jpaQueryProvider.createQuery());
verify(entityManager);
}
}