/*
* Copyright 2012-2017 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.boot.test.autoconfigure.orm.jpa;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnitUtil;
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
import org.springframework.util.Assert;
/**
* Alternative to {@link EntityManager} for use in JPA tests. Provides a subset of
* {@link EntityManager} methods that are useful for tests as well as helper methods for
* common testing tasks such as {@link #persistFlushFind(Object) persist/flush/find}.
*
* @author Phillip Webb
* @since 1.4.0
*/
public class TestEntityManager {
private final EntityManagerFactory entityManagerFactory;
/**
* Create a new {@link TestEntityManager} instance for the given
* {@link EntityManagerFactory}.
* @param entityManagerFactory the source entity manager factory
*/
public TestEntityManager(EntityManagerFactory entityManagerFactory) {
Assert.notNull(entityManagerFactory, "EntityManagerFactory must not be null");
this.entityManagerFactory = entityManagerFactory;
}
/**
* Make an instance managed and persistent then return it's ID. Delegates to
* {@link EntityManager#persist(Object)} then {@link #getId(Object)}.
* <p>
* Helpful when setting up test data in a test: <pre class="code">
* Object entityId = this.testEntityManager.persist(new MyEntity("Spring"));
* </pre>
* @param entity the source entity
* @return the ID of the newly persisted entity
*/
public Object persistAndGetId(Object entity) {
persist(entity);
return getId(entity);
}
/**
* Make an instance managed and persistent then return it's ID. Delegates to
* {@link EntityManager#persist(Object)} then {@link #getId(Object, Class)}.
* <p>
* Helpful when setting up test data in a test: <pre class="code">
* Long entityId = this.testEntityManager.persist(new MyEntity("Spring"), Long.class);
* </pre>
* @param <T> the ID type
* @param entity the source entity
* @param idType the ID type
* @return the ID of the newly persisted entity
*/
public <T> T persistAndGetId(Object entity, Class<T> idType) {
persist(entity);
return getId(entity, idType);
}
/**
* Make an instance managed and persistent. Delegates to
* {@link EntityManager#persist(Object)} then returns the original source entity.
* <p>
* Helpful when setting up test data in a test: <pre class="code">
* MyEntity entity = this.testEntityManager.persist(new MyEntity("Spring"));
* </pre>
* @param <E> the entity type
* @param entity the entity to persist
* @return the persisted entity
*/
public <E> E persist(E entity) {
getEntityManager().persist(entity);
return entity;
}
/**
* Make an instance managed and persistent, synchronize the persistence context to the
* underlying database and finally find the persisted entity by its ID. Delegates to
* {@link #persistAndFlush(Object)} then {@link #find(Class, Object)} with the
* {@link #getId(Object) entity ID}.
* <p>
* Helpful when ensuring that entity data is actually written and read from the
* underlying database correctly.
* @param <E> the entity type
* @param entity the entity to persist
* @return the entity found using the ID of the persisted entity
*/
@SuppressWarnings("unchecked")
public <E> E persistFlushFind(E entity) {
EntityManager entityManager = getEntityManager();
persistAndFlush(entity);
Object id = getId(entity);
entityManager.detach(entity);
return (E) entityManager.find(entity.getClass(), id);
}
/**
* Make an instance managed and persistent then synchronize the persistence context to
* the underlying database. Delegates to {@link EntityManager#persist(Object)} then
* {@link #flush()} and finally returns the original source entity.
* <p>
* Helpful when setting up test data in a test: <pre class="code">
* MyEntity entity = this.testEntityManager.persistAndFlush(new MyEntity("Spring"));
* </pre>
* @param <E> the entity type
* @param entity the entity to persist
* @return the persisted entity
*/
public <E> E persistAndFlush(E entity) {
persist(entity);
flush();
return entity;
}
/**
* Merge the state of the given entity into the current persistence context. Delegates
* to {@link EntityManager#merge(Object)}
* @param <E> the entity type
* @param entity the entity to merge
* @return the merged entity
*/
public <E> E merge(E entity) {
return getEntityManager().merge(entity);
}
/**
* Remove the entity instance. Delegates to {@link EntityManager#remove(Object)}
* @param entity the entity to remove
*/
public void remove(Object entity) {
getEntityManager().remove(entity);
}
/**
* Find by primary key. Delegates to {@link EntityManager#find(Class, Object)}.
* @param <E> the entity type
* @param entityClass the entity class
* @param primaryKey the entity primary key
* @return the found entity or {@code null} if the entity does not exist
* @see #getId(Object)
*/
public <E> E find(Class<E> entityClass, Object primaryKey) {
return getEntityManager().find(entityClass, primaryKey);
}
/**
* Synchronize the persistence context to the underlying database. Delegates to
* {@link EntityManager#flush()}.
*/
public void flush() {
getEntityManager().flush();
}
/**
* Refresh the state of the instance from the database, overwriting changes made to
* the entity, if any. Delegates to {@link EntityManager#refresh(Object)}.
* @param <E> the entity type
* @param entity the entity to refresh
* @return the refreshed entity
*/
public <E> E refresh(E entity) {
getEntityManager().refresh(entity);
return entity;
}
/**
* Clear the persistence context, causing all managed entities to become detached.
* Delegates to {@link EntityManager#clear()}
*/
public void clear() {
getEntityManager().clear();
}
/**
* Remove the given entity from the persistence context, causing a managed entity to
* become detached. Delegates to {@link EntityManager#detach(Object)}.
* @param entity the entity to detach.
*/
public void detach(Object entity) {
getEntityManager().detach(entity);
}
/**
* Return the ID of the given entity. Delegates to
* {@link PersistenceUnitUtil#getIdentifier(Object)}.
* @param entity the source entity
* @return the ID of the entity or {@code null}
* @see #getId(Object, Class)
*/
public Object getId(Object entity) {
return this.entityManagerFactory.getPersistenceUnitUtil().getIdentifier(entity);
}
/**
* Return the ID of the given entity cast to a specific type. Delegates to
* {@link PersistenceUnitUtil#getIdentifier(Object)}.
* @param <T> the ID type
* @param entity the source entity
* @param idType the expected ID type
* @return the ID of the entity or {@code null}
* @see #getId(Object)
*/
@SuppressWarnings("unchecked")
public <T> T getId(Object entity, Class<T> idType) {
Object id = getId(entity);
Assert.isInstanceOf(idType, id, "ID mismatch:");
return (T) id;
}
/**
* Return the underlying {@link EntityManager} that's actually used to perform all
* operations.
* @return the entity manager
*/
public final EntityManager getEntityManager() {
EntityManager manager = EntityManagerFactoryUtils
.getTransactionalEntityManager(this.entityManagerFactory);
Assert.state(manager != null, "No transactional EntityManager found");
return manager;
}
}