[BAEL-2048] Introduction to Spring Data JPA article
This commit is contained in:
parent
b5a2fea255
commit
784d99eeb3
|
@ -0,0 +1,30 @@
|
|||
package org.baeldung.persistence;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
public interface IOperations<T extends Serializable> {
|
||||
|
||||
// read - one
|
||||
|
||||
T findOne(final long id);
|
||||
|
||||
// read - all
|
||||
|
||||
List<T> findAll();
|
||||
|
||||
Page<T> findPaginated(int page, int size);
|
||||
|
||||
// write
|
||||
|
||||
T create(final T entity);
|
||||
|
||||
T update(final T entity);
|
||||
|
||||
void delete(final T entity);
|
||||
|
||||
void deleteById(final long entityId);
|
||||
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.baeldung.persistence.dao;
|
||||
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
public interface IFooDao extends JpaRepository<Foo, Long> {
|
||||
|
||||
@Query("SELECT f FROM Foo f WHERE LOWER(f.name) = LOWER(:name)")
|
||||
Foo retrieveByName(@Param("name") String name);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package org.baeldung.persistence.model;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity
|
||||
public class Foo implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
public Foo() {
|
||||
super();
|
||||
}
|
||||
|
||||
public Foo(final String name) {
|
||||
super();
|
||||
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(final long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final Foo other = (Foo) obj;
|
||||
if (name == null) {
|
||||
if (other.name != null)
|
||||
return false;
|
||||
} else if (!name.equals(other.name))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append("Foo [name=").append(name).append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package org.baeldung.persistence.service;
|
||||
|
||||
import org.baeldung.persistence.IOperations;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
public interface IFooService extends IOperations<Foo> {
|
||||
|
||||
Foo retrieveByName(String name);
|
||||
|
||||
Page<Foo> findPaginated(Pageable pageable);
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package org.baeldung.persistence.service.common;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.baeldung.persistence.IOperations;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
@Transactional
|
||||
public abstract class AbstractService<T extends Serializable> implements IOperations<T> {
|
||||
|
||||
// read - one
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public T findOne(final long id) {
|
||||
return getDao().findById(id).orElse(null);
|
||||
}
|
||||
|
||||
// read - all
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<T> findAll() {
|
||||
return Lists.newArrayList(getDao().findAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<T> findPaginated(final int page, final int size) {
|
||||
return getDao().findAll(new PageRequest(page, size));
|
||||
}
|
||||
|
||||
// write
|
||||
|
||||
@Override
|
||||
public T create(final T entity) {
|
||||
return getDao().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T update(final T entity) {
|
||||
return getDao().save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(final T entity) {
|
||||
getDao().delete(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(final long entityId) {
|
||||
getDao().deleteById(entityId);
|
||||
}
|
||||
|
||||
protected abstract PagingAndSortingRepository<T, Long> getDao();
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.baeldung.persistence.service.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.baeldung.persistence.dao.IFooDao;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.persistence.service.IFooService;
|
||||
import org.baeldung.persistence.service.common.AbstractService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class FooService extends AbstractService<Foo> implements IFooService {
|
||||
|
||||
@Autowired
|
||||
private IFooDao dao;
|
||||
|
||||
public FooService() {
|
||||
super();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
protected PagingAndSortingRepository<Foo, Long> getDao() {
|
||||
return dao;
|
||||
}
|
||||
|
||||
// custom methods
|
||||
|
||||
@Override
|
||||
public Foo retrieveByName(final String name) {
|
||||
return dao.retrieveByName(name);
|
||||
}
|
||||
|
||||
// overridden to be secured
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Foo> findAll() {
|
||||
return Lists.newArrayList(getDao().findAll());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Foo> findPaginated(Pageable pageable) {
|
||||
return dao.findAll(pageable);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
package org.baeldung.spring;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.jdbc.datasource.DriverManagerDataSource;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
@PropertySource({ "classpath:persistence-${envTarget:h2}.properties" })
|
||||
@ComponentScan({ "org.baeldung.persistence" })
|
||||
// @ImportResource("classpath*:springDataPersistenceConfig.xml")
|
||||
@EnableJpaRepositories(basePackages = "org.baeldung.persistence.dao")
|
||||
public class PersistenceConfig {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
public PersistenceConfig() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
|
||||
em.setDataSource(dataSource());
|
||||
em.setPackagesToScan(new String[] { "org.baeldung.persistence.model" });
|
||||
|
||||
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
|
||||
// vendorAdapter.set
|
||||
em.setJpaVendorAdapter(vendorAdapter);
|
||||
em.setJpaProperties(additionalProperties());
|
||||
|
||||
return em;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
|
||||
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
|
||||
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
|
||||
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
|
||||
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PlatformTransactionManager transactionManager() {
|
||||
final JpaTransactionManager transactionManager = new JpaTransactionManager();
|
||||
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
|
||||
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
|
||||
return new PersistenceExceptionTranslationPostProcessor();
|
||||
}
|
||||
|
||||
final Properties additionalProperties() {
|
||||
final Properties hibernateProperties = new Properties();
|
||||
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
|
||||
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
|
||||
// hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
|
||||
return hibernateProperties;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,252 @@
|
|||
package org.baeldung.persistence.service;
|
||||
|
||||
import org.baeldung.persistence.IOperations;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.util.IDUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public abstract class AbstractServicePersistenceIntegrationTest<T extends Serializable> {
|
||||
|
||||
// tests
|
||||
|
||||
// find - one
|
||||
|
||||
@Test
|
||||
/**/public final void givenResourceDoesNotExist_whenResourceIsRetrieved_thenNoResourceIsReceived() {
|
||||
// When
|
||||
final Foo createdResource = getApi().findOne(IDUtil.randomPositiveLong());
|
||||
|
||||
// Then
|
||||
assertNull(createdResource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenResourceExists_whenResourceIsRetrieved_thenNoExceptions() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
getApi().findOne(existingResource.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenResourceDoesNotExist_whenResourceIsRetrieved_thenNoExceptions() {
|
||||
getApi().findOne(IDUtil.randomPositiveLong());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenResourceExists_whenResourceIsRetrieved_thenTheResultIsNotNull() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
final Foo retrievedResource = getApi().findOne(existingResource.getId());
|
||||
assertNotNull(retrievedResource);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void givenResourceExists_whenResourceIsRetrieved_thenResourceIsRetrievedCorrectly() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
final Foo retrievedResource = getApi().findOne(existingResource.getId());
|
||||
assertEquals(existingResource, retrievedResource);
|
||||
}
|
||||
|
||||
// find - one - by name
|
||||
|
||||
// find - all
|
||||
|
||||
@Test
|
||||
/**/public void whenAllResourcesAreRetrieved_thenNoExceptions() {
|
||||
getApi().findAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void whenAllResourcesAreRetrieved_thenTheResultIsNotNull() {
|
||||
final List<Foo> resources = getApi().findAll();
|
||||
|
||||
assertNotNull(resources);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void givenAtLeastOneResourceExists_whenAllResourcesAreRetrieved_thenRetrievedResourcesAreNotEmpty() {
|
||||
persistNewEntity();
|
||||
|
||||
// When
|
||||
final List<Foo> allResources = getApi().findAll();
|
||||
|
||||
// Then
|
||||
assertThat(allResources, not(Matchers.<Foo> empty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void givenAnResourceExists_whenAllResourcesAreRetrieved_thenTheExistingResourceIsIndeedAmongThem() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
|
||||
final List<Foo> resources = getApi().findAll();
|
||||
|
||||
assertThat(resources, hasItem(existingResource));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void whenAllResourcesAreRetrieved_thenResourcesHaveIds() {
|
||||
persistNewEntity();
|
||||
|
||||
// When
|
||||
final List<Foo> allResources = getApi().findAll();
|
||||
|
||||
// Then
|
||||
for (final Foo resource : allResources) {
|
||||
assertNotNull(resource.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// create
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
/**/public void whenNullResourceIsCreated_thenException() {
|
||||
getApi().create(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void whenResourceIsCreated_thenNoExceptions() {
|
||||
persistNewEntity();
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void whenResourceIsCreated_thenResourceIsRetrievable() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
|
||||
assertNotNull(getApi().findOne(existingResource.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void whenResourceIsCreated_thenSavedResourceIsEqualToOriginalResource() {
|
||||
final Foo originalResource = createNewEntity();
|
||||
final Foo savedResource = getApi().create(originalResource);
|
||||
|
||||
assertEquals(originalResource, savedResource);
|
||||
}
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void whenResourceWithFailedConstraintsIsCreated_thenException() {
|
||||
final Foo invalidResource = createNewEntity();
|
||||
invalidate(invalidResource);
|
||||
|
||||
getApi().create(invalidResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* -- specific to the persistence engine
|
||||
*/
|
||||
@Test(expected = DataAccessException.class)
|
||||
@Ignore("Hibernate simply ignores the id silently and still saved (tracking this)")
|
||||
public void whenResourceWithIdIsCreated_thenDataAccessException() {
|
||||
final Foo resourceWithId = createNewEntity();
|
||||
resourceWithId.setId(IDUtil.randomPositiveLong());
|
||||
|
||||
getApi().create(resourceWithId);
|
||||
}
|
||||
|
||||
// update
|
||||
|
||||
@Test(expected = RuntimeException.class)
|
||||
/**/public void whenNullResourceIsUpdated_thenException() {
|
||||
getApi().update(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void givenResourceExists_whenResourceIsUpdated_thenNoExceptions() {
|
||||
// Given
|
||||
final Foo existingResource = persistNewEntity();
|
||||
|
||||
// When
|
||||
getApi().update(existingResource);
|
||||
}
|
||||
|
||||
/**
|
||||
* - can also be the ConstraintViolationException which now occurs on the update operation will not be translated; as a consequence, it will be a TransactionSystemException
|
||||
*/
|
||||
@Test(expected = RuntimeException.class)
|
||||
public void whenResourceIsUpdatedWithFailedConstraints_thenException() {
|
||||
final Foo existingResource = persistNewEntity();
|
||||
invalidate(existingResource);
|
||||
|
||||
getApi().update(existingResource);
|
||||
}
|
||||
|
||||
@Test
|
||||
/**/public void givenResourceExists_whenResourceIsUpdated_thenUpdatesArePersisted() {
|
||||
// Given
|
||||
final Foo existingResource = persistNewEntity();
|
||||
|
||||
// When
|
||||
change(existingResource);
|
||||
getApi().update(existingResource);
|
||||
|
||||
final Foo updatedResource = getApi().findOne(existingResource.getId());
|
||||
|
||||
// Then
|
||||
assertEquals(existingResource, updatedResource);
|
||||
}
|
||||
|
||||
// delete
|
||||
|
||||
// @Test(expected = RuntimeException.class)
|
||||
// public void givenResourceDoesNotExists_whenResourceIsDeleted_thenException() {
|
||||
// // When
|
||||
// getApi().delete(IDUtil.randomPositiveLong());
|
||||
// }
|
||||
//
|
||||
// @Test(expected = RuntimeException.class)
|
||||
// public void whenResourceIsDeletedByNegativeId_thenException() {
|
||||
// // When
|
||||
// getApi().delete(IDUtil.randomNegativeLong());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// public void givenResourceExists_whenResourceIsDeleted_thenNoExceptions() {
|
||||
// // Given
|
||||
// final Foo existingResource = persistNewEntity();
|
||||
//
|
||||
// // When
|
||||
// getApi().delete(existingResource.getId());
|
||||
// }
|
||||
//
|
||||
// @Test
|
||||
// /**/public final void givenResourceExists_whenResourceIsDeleted_thenResourceNoLongerExists() {
|
||||
// // Given
|
||||
// final Foo existingResource = persistNewEntity();
|
||||
//
|
||||
// // When
|
||||
// getApi().delete(existingResource.getId());
|
||||
//
|
||||
// // Then
|
||||
// assertNull(getApi().findOne(existingResource.getId()));
|
||||
// }
|
||||
|
||||
// template method
|
||||
|
||||
protected Foo createNewEntity() {
|
||||
return new Foo(randomAlphabetic(6));
|
||||
}
|
||||
|
||||
protected abstract IOperations<Foo> getApi();
|
||||
|
||||
private final void invalidate(final Foo entity) {
|
||||
entity.setName(null);
|
||||
}
|
||||
|
||||
private final void change(final Foo entity) {
|
||||
entity.setName(randomAlphabetic(6));
|
||||
}
|
||||
|
||||
protected Foo persistNewEntity() {
|
||||
return getApi().create(createNewEntity());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package org.baeldung.persistence.service;
|
||||
|
||||
import org.baeldung.persistence.IOperations;
|
||||
import org.baeldung.persistence.model.Foo;
|
||||
import org.baeldung.spring.PersistenceConfig;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.context.support.AnnotationConfigContextLoader;
|
||||
|
||||
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = { PersistenceConfig.class }, loader = AnnotationConfigContextLoader.class)
|
||||
public class FooServicePersistenceIntegrationTest extends AbstractServicePersistenceIntegrationTest<Foo> {
|
||||
|
||||
@Autowired
|
||||
private IFooService service;
|
||||
|
||||
// tests
|
||||
|
||||
@Test
|
||||
public final void whenContextIsBootstrapped_thenNoExceptions() {
|
||||
//
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void whenEntityIsCreated_thenNoExceptions() {
|
||||
service.create(new Foo(randomAlphabetic(6)));
|
||||
}
|
||||
|
||||
@Test(expected = DataIntegrityViolationException.class)
|
||||
public final void whenInvalidEntityIsCreated_thenDataException() {
|
||||
service.create(new Foo());
|
||||
}
|
||||
|
||||
@Test(expected = DataIntegrityViolationException.class)
|
||||
public final void whenEntityWithLongNameIsCreated_thenDataException() {
|
||||
service.create(new Foo(randomAlphabetic(2048)));
|
||||
}
|
||||
|
||||
// custom Query method
|
||||
|
||||
@Test
|
||||
public final void givenUsingCustomQuery_whenRetrievingEntity_thenFound() {
|
||||
final String name = randomAlphabetic(6);
|
||||
service.create(new Foo(name));
|
||||
|
||||
final Foo retrievedByName = service.retrieveByName(name);
|
||||
assertNotNull(retrievedByName);
|
||||
}
|
||||
|
||||
// work in progress
|
||||
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
@Ignore("Right now, persist has saveOrUpdate semantics, so this will no longer fail")
|
||||
public final void whenSameEntityIsCreatedTwice_thenDataException() {
|
||||
final Foo entity = new Foo(randomAlphabetic(8));
|
||||
service.create(entity);
|
||||
service.create(entity);
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
@Override
|
||||
protected final IOperations<Foo> getApi() {
|
||||
return service;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package org.baeldung.util;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public final class IDUtil {
|
||||
|
||||
private IDUtil() {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
public static String randomPositiveLongAsString() {
|
||||
return Long.toString(randomPositiveLong());
|
||||
}
|
||||
|
||||
public static String randomNegativeLongAsString() {
|
||||
return Long.toString(randomNegativeLong());
|
||||
}
|
||||
|
||||
public static long randomPositiveLong() {
|
||||
long id = new Random().nextLong() * 10000;
|
||||
id = (id < 0) ? (-1 * id) : id;
|
||||
return id;
|
||||
}
|
||||
|
||||
private static long randomNegativeLong() {
|
||||
long id = new Random().nextLong() * 10000;
|
||||
id = (id > 0) ? (-1 * id) : id;
|
||||
return id;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue