I'm trying to add some custom functionality to a Spring Data Repository using the Repository composing features documented here
https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behavior
Specifically, I'm trying to create a generic interface and implementation I can use with many of my repositories which seem to be a valid approach given "Example 34. Fragments overriding" in the link above which shows just this scenario.
I have got my generic interface DynamicEntityGraph
public interface DynamicEntityGraph<T> {
List<T> findAll(EntityGraph<T> entityGraph);
}
and the corresponding implementation
public class DynamicEntityGraphImpl<T> implements DynamicEntityGraph<T> {
#Autowired
private EntityManager em;
Logger logger = LoggerFactory.getLogger(getClass());
#Override
public List<T> findAll(EntityGraph<T> entityGraph) {
//EM Code Goes Here
return null;
}
}
which I then use in a repository like
#Repository
public interface SiteRepository extends CustomerScopedRepository<Site>, DynamicEntityGraph<Site> {
}
This part all works fine.
My issue is in the DynamicEntityGraphImpl I need to get the Class of T at runtime in order to create my Entity Manager queries. After extensive research, I've not been able to find a solution in which I can obtain the Class of T, despite it looking like a valid solution given it exists in the Spring Data JPA Docs.
I've read the source code of JpaRepositoryFactory and can see the class is injected into the repository when it's constructed, but I'm not sure how to access this from the fragment.
Any assistance would be greatly appreciated.
For my future self or other lost travellers on a similar path, I figured it out and here is the solution.
A similar question was asked on the Spring Data project and this clears up that fragments are actually initialised as singletons in the Spring context so it's not possible to pass the EntityInformation to them.
Note: If you're not trying to make a generic fragment then this isn't the right solution for you.
The solution is to then extend the JpaRepositoryFactory and JpaRepositoryFactoryBean with a little extra configuration.
public class MyJpaRepositoryFactory extends JpaRepositoryFactory {
private EntityManager entityManager;
public MyJpaRepositoryFactory(EntityManager entityManager) {
super(entityManager);
this.entityManager = entityManager;
}
#Override
protected RepositoryFragments getRepositoryFragments(RepositoryMetadata metadata) {
RepositoryFragments fragments = super.getRepositoryFragments(metadata);
if(DynamicEntityGraph.class.isAssignableFrom(metadata.getRepositoryInterface()))
{
JpaEntityInformation<?, Serializable> entityInformation = this.getEntityInformation(metadata.getDomainType());
fragments = fragments.append(RepositoryFragment.implemented(DynamicEntityGraph.class, new DynamicEntityGraphImpl(entityInformation, entityManager)));
}
return fragments;
}
}
this simply checks if the repository being instantiated implements our interface and if it does we construct a new instance of our class, passing it the EntityInformation and EntityManger.
public class MyJpaRepositoryFactoryBean<T extends JpaRepository<Object, Serializable>> extends JpaRepositoryFactoryBean<T , Object, Serializable> {
public MyJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
super(repositoryInterface);
}
#Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
return new MyJpaRepositoryFactory(entityManager);
}
}
and finally, we tell Spring Data to use this as our factory bean
#SpringBootApplication
#EnableJpaRepositories(repositoryFactoryBeanClass = MyJpaRepositoryFactoryBean.class)
public class ApplicationApiApplication {
public static void main(String[] args) {
SpringApplication.run(ApplicationApiApplication.class, args);
}
}
It's important to also mark your fragment interface as #NoRepositoryBean to prevent Spring from making a bean from it.
#NoRepositoryBean
public interface DynamicEntityGraph<T> {
List<T> findAll(EntityGraph<T> entityGraph);
}
I hope this saves you some time!
I am using a utility object SubGraphUtil. SubGraphUtil is used to build the graph.
I also have a specification object for the where part
public abstract class AbstractCustomRepository<T> {
private static final String FETCH_GRAPH = "javax.persistence.fetchgraph";
#PersistenceContext
protected EntityManager entityManager;
#Setter
private Class<T> entityClass;
/**
* Permet de recuperer une liste d entites en choisissant le graphe et la specification
*
* #param subGraphUtilList
* #param specification
* #return une liste d entites en choisissant le graphe
*/
public List<T> findAllWithGraphAndSpecification(List<SubGraphUtil> subGraphUtilList,
#Nullable Specification<T> specification) {
EntityGraph<T> graph = buildEntityGraphFromUtil(subGraphUtilList);
CriteriaQuery<T> criteriaQuery = getCriteriaQuery(specification);
return entityManager.createQuery(criteriaQuery)
.setHint(FETCH_GRAPH, graph)
.getResultList();
}
/**
* Permet de construire EntityGraph
*
* #param subGraphUtilList
* #return EntityGraph
*/
private EntityGraph<T> buildEntityGraphFromUtil(List<SubGraphUtil> subGraphUtilList) {
EntityGraph<T> graph = entityManager.createEntityGraph(entityClass);
if (isNotEmpty(subGraphUtilList)) {
subGraphUtilList.forEach(
subGraphUtil -> {
Subgraph<T> subgraph = graph.addSubgraph(subGraphUtil.getName());
if (isNotEmpty(subGraphUtil.getSubGraphUtilList())) {
subGraphUtil.getSubGraphUtilList()
.forEach(
childGraph -> addSubGraph(subgraph, childGraph)
);
}
}
);
}
return graph;
}
}
Example of use in a repository
public class ContratCustomRepositoryImpl extends AbstractCustomRepository<Contrat>
implements ContratCustomRepository {
public ContratCustomRepositoryImpl() {
super();
setEntityClass(Contrat.class);
}
}
public interface ContratCustomRepository {
List<Contrat> findAllWithGraphAndSpecification(List<SubGraphUtil> subGraphUtilList,
Specification<Contrat> specification);
}
Full code: Here
Related
I can't manage to inject a property from application.yml to a spring data #Query.
The following results in an EL1008E error:
public interface MyRepository extends JpaRepository<MyEntity, Long> {
#Query("select e from MyEntity e where e.foo = :foo and e.env= ?#{env}")
MyEntity findByFoo(#Param("foo") String foo);
}
According to this blog it is possible to inject a property of spring's principal, which is not very different from what I would like to do.
Any hints on this?
I should really stop asking questions and answer them by myself shortly after ... That is not on purpose.
The mentioned blog has the solution included. Add this:
public class PropertyEvaluationContextExtension extends EvaluationContextExtensionSupport {
private final MyProps p;
public PropertyEvaluationContextExtension(final MyProps p) {
this.p= p;
}
#Override
public String getExtensionId() {
return "foo";
}
#Override
public MyProps getRootObject() {
return this.p;
}
}
#Configuration
public class PropertyConfig {
private final MyProps p;
public PropertyConfig(final MyProps p) {
this.p= p;
}
#Bean
EvaluationContextExtensionSupport propertyExtension() {
return new PropertyEvaluationContextExtension(p);
}
}
Now every property of MyProps is accessible via SpEL.
I can't get Spring Data Rest with class inheritance working.
I'd like to have a single JSON Endpoint which handles all my concrete classes.
Repo:
public interface AbstractFooRepo extends KeyValueRepository<AbstractFoo, String> {}
Abstract class:
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = MyFoo.class, name = "MY_FOO")
})
public abstract class AbstractFoo {
#Id public String id;
public String type;
}
Concrete class:
public class MyFoo extends AbstractFoo { }
Now when calling POST /abstractFoos with {"type":"MY_FOO"}, it tells me: java.lang.IllegalArgumentException: PersistentEntity must not be null!.
This seems to happen, because Spring doesn't know about MyFoo.
Is there some way to tell Spring Data REST about MyFoo without creating a Repository and a REST Endpoint for it?
(I'm using Spring Boot 1.5.1 and Spring Data REST 2.6.0)
EDIT:
Application.java:
#SpringBootApplication
#EnableMapRepositories
public class Application {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
I'm using Spring Boot 1.5.1 and Spring Data Release Ingalls.
KeyValueRepository doesn't work with inheritance. It uses the class name of every saved object to find the corresponding key-value-store. E.g. save(new Foo()) will place the saved object within the Foo collection. And abstractFoosRepo.findAll() will look within the AbstractFoo collection and won't find any Foo object.
Here's the working code using MongoRepository:
Application.java
Default Spring Boot Application Starter.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
AbstractFoo.java
I've tested include = JsonTypeInfo.As.EXISTING_PROPERTY and include = JsonTypeInfo.As.PROPERTY. Both seem to work fine!
It's even possible to register the Jackson SubTypes with a custom JacksonModule.
IMPORTANT: #RestResource(path="abstractFoos") is highly recommended. Else the _links.self links will point to /foos and /bars instead of /abstractFoos.
#JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXISTING_PROPERTY, property = "type")
#JsonSubTypes({
#JsonSubTypes.Type(value = Foo.class, name = "MY_FOO"),
#JsonSubTypes.Type(value = Bar.class, name = "MY_Bar")
})
#Document(collection="foo_collection")
#RestResource(path="abstractFoos")
public abstract class AbstractFoo {
#Id public String id;
public abstract String getType();
}
AbstractFooRepo.java
Nothing special here
public interface AbstractFooRepo extends MongoRepository<AbstractFoo, String> { }
Foo.java & Bar.java
#Persistent
public class Foo extends AbstractFoo {
#Override
public String getType() {
return "MY_FOO";
}
}
#Persistent
public class Bar extends AbstractFoo {
#Override
public String getType() {
return "MY_BAR";
}
}
FooRelProvider.java
Without this part, the output of the objects would be separated in two arrays under _embedded.foos and _embedded.bars.
The supports method ensures that for all classes which extend AbstractFoo, the objects will be placed within _embedded.abstractFoos.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class FooRelProvider extends EvoInflectorRelProvider {
#Override
public String getCollectionResourceRelFor(final Class<?> type) {
return super.getCollectionResourceRelFor(AbstractFoo.class);
}
#Override
public String getItemResourceRelFor(final Class<?> type) {
return super.getItemResourceRelFor(AbstractFoo.class);
}
#Override
public boolean supports(final Class<?> delimiter) {
return AbstractFoo.class.isAssignableFrom(delimiter);
}
}
EDIT
Added #Persistent to Foo.java and Bar.java. (Adding it to AbstractFoo.java doesn't work). Without this annotation I got NullPointerExceptions when trying to use JSR 303 Validation Annotations within inherited classes.
Example code to reproduce the error:
public class A {
#Id public String id;
#Valid public B b;
// #JsonTypeInfo + #JsonSubTypes
public static abstract class B {
#NotNull public String s;
}
// #Persistent <- Needed!
public static class B1 extends B { }
}
Please see the discussion in this resolved jira task for details of what is currently supported in spring-data-rest regarding JsonTypeInfo. And this jira task on what is still missing.
To summarize - only #JsonTypeInfo with include=JsonTypeInfo.As.EXISTING_PROPERTY is working for serialization and deserialization currently.
Also, you need spring-data-rest 2.5.3 (Hopper SR3) or later to get this limited support.
Please see my sample application - https://github.com/mduesterhoeft/spring-data-rest-entity-inheritance/tree/fixed-hopper-sr3-snapshot
With include=JsonTypeInfo.As.EXISTING_PROPERTY the type information is extracted from a regular property. An example helps getting the point of this way of adding type information:
The abstract class:
#Entity #Inheritance(strategy= SINGLE_TABLE)
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME,
include=JsonTypeInfo.As.EXISTING_PROPERTY,
property="type")
#JsonSubTypes({
#Type(name="DECIMAL", value=DecimalValue.class),
#Type(name="STRING", value=StringValue.class)})
public abstract class Value {
#Id #GeneratedValue(strategy = IDENTITY)
#Getter
private Long id;
public abstract String getType();
}
And the subclass:
#Entity #DiscriminatorValue("D")
#Getter #Setter
public class DecimalValue extends Value {
#Column(name = "DECIMAL_VALUE")
private BigDecimal value;
public String getType() {
return "DECIMAL";
}
}
Is it possible to use Spring's #Value annotation to read and write property values of a custom class type?
For example:
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
// is this possible for a custom class like Customer???
// Something behind the scenes that converts Custom object to/from property file's string value via an ObjectFactory or something like that?
#Value("${data.customer:#{null}}")
private Customer customer;
...
}
EDITED SOLUTION
Here is how I did it using Spring 4.x APIs...
Created new PropertyEditorSupport class for Customer class:
public class CustomerPropertiesEditor extends PropertyEditorSupport {
// simple mapping class to convert Customer to String and vice-versa.
private CustomerMap map;
#Override
public String getAsText()
{
Customer customer = (Customer) this.getValue();
return map.transform(customer);
}
#Override
public void setAsText(String text) throws IllegalArgumentException
{
Customer customer = map.transform(text);
super.setValue(customer);
}
}
Then in application's ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
Cheers,
PM
You have to create a class extending PropertyEditorSupport.
public class CustomerEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
Customer c = new Customer();
// Parse text and set customer fields...
setValue(c);
}
}
It's possible but reading Spring documentation. You could see this example:
Example usage
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
See details here
Spring can read properties and load them directly into a class.
Moreover, you can add #ConfigurationProperties(prefix = "data") on top of the class, instead of wiring each nested property one by one, by making the code cleaner.
Given all that, here is the final example with explanations:
// File: CustomerConfig.java
#Configuration
// Set property source file path (optional)
#PropertySource("classpath:/data.properties")
// Put prefix = "data" here so that Spring read properties under "data.*"
#ConfigurationProperties(prefix = "data")
public class CustomerConfig {
// Note: Property name here is the same as in the file (data.customer)
// Spring will automatically read and put "data.customer.*" properties into this object
private Customer customer;
// Other configs can be added here too... without wiring one-by-one
public setCustomer(Customer customer){
this.customer = customer;
}
public getCustomer(){
return this.customer;
}
}
That's it, now you have "data.customer.*" properties, loaded and accessible via CustomerConfig.getCustomer().
To integrate it into your service (based on your example code):
// File: CustomerService.java
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
#Autowired // Inject configs, either with #Autowired or using constructor injection
private CustomerConfig customerConfig;
public void myMethod() {
// Now its available for use
System.out.println(customerConfig.getCustomer().toString());
}
}
This way no "magical hack" is required to read configs into a class.
Take a look at the #ConfigurationProperties documentation/examples, and this post for more useful info.
Note: I'd suggest against using PropertyEditorSupport, since
a) it was built for different purpose, may change in future by breaking the code
b) it requires manual "handling" code inside => possible bugs
Instead, use what was built right for that purpose (Spring already has it), in order to both make the code easier to understand, and to gain possible inner improvements/optimizations which might be done in the future (or present).
Further improvements: Your CustomerService seems to be cluttered with configs (#PropertyService) too. I'd suggest reading those properties via another class too (similarly) then wiring that class here, instead of doing all in the CustomerService.
If you want to use it with lists, there is a workaround using array instead.
Define your property as Customer[] instead of List then:
in ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
customEditors.put(Customer[].class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
In CustomerEditor:
public class CustomerEditor extends PropertyEditorSupport {
public static final String DEFAULT_SEPARATOR = ",";
#Override
public void setAsText(String text) {
String[] array = StringUtils.delimitedListToStringArray(text, this.separator);
if (this.emptyArrayAsNull && array.length == 0) {
super.setValue((Object) null);
} else {
if (this.trimValues) {
array = StringUtils.trimArrayElements(array);
}
// Convert String[] to Customer[]
super.setValue(...);
}
}
}
If you want to use an existing converter/constructor, you can just call it within your expression.
For example:
#Value("#{T(org.test.CutomerMap).transform('${serialized.customer}')}")
private Customer customer;
The Service class and my repository classes in my spring MVC set up are something like this -
public class ObjectServiceImpl implements ObjectService {
#Autowired
Temp1Repo temp1Repo;
#Autowired
Temp2Repo temp2Repo;
...
}
public interface Temp1Repo extends CrudRepository<Temp1, Integer> {
}
public interface Temp2Repo extends CrudRepository<Temp2, Integer> {
}
Now, in my service class, i am getting a object of a type Temp1, I have to call temp1Repo.save(). If I get an object of Temp2, I have to call temp2Repo.save() and so on...
How do i achieve this?
Seems fairly simple to just have an if statement:
if(object instanceof Temp1) {
temp1Repo.save((Temp1) object);
} else if(object instanceof Temp2) {
temp2Repo.save((Temp2) object);
}
Or perhaps you are looking for a more generic way?
I suppose that you want to regroup all repositories in one. Something like
#SuppressWarnings("rawtypes")
public class ObjectServiceImpl {
#Autowired
private CrudRepository[] repositories;
private Map<Class<?>, CrudRepository> repositoryMap = new HashMap<Class<?>, CrudRepository>();
#PostConstruct
public void init() {
for (CrudRepository r : repositories)
repositoryMap.put(getType(r), r);
}
private Class<?> getType(CrudRepository repository) {
Type[] types = repository.getClass().getGenericInterfaces();
for (Type t : types) {
if (t instanceof ParameterizedType)
return (Class<?>) ((ParameterizedType) t).getActualTypeArguments()[0];
}
throw new IllegalStateException("Check repositories...");
}
public void save(Object entity) {
repositoryMap.get(entity.getClass()).save(entity);
}
public <T> T get(Object id, Class<T> clazz) {
return repositoryMap.get(clazz).findOne(id);
}
....
}
Consider to use EntityManager directly, but could be useful anyway...
Following the code you wrote, Spring will rise an exception at startup time if any injection is missing.
What you want to do is a dynamic Module load, depending on a condition you omitted within your question.
You probably have to use XML configuration style and create a by condition spring context and load the correct one to be used.
Cheers
I am currently using DBUnit in conjunction with Spring in order to unit test my application, but have run into an issue where my update logic test always fails because a deadlock occurs on the database and I cannot figure out why this is the case. Please note that I have been able to get around the issue by removing the method annotated by #After, which really isn't needed because I am using the #TransactionConfiguration annotation, but I'm concerned that I'm misunderstanding something regarding how the transaction processing works and thus am hoping someone can indicate why I always get the following exception when running my updateTerritory method.
java.sql.SQLTransactionRollbackException: A lock could not be obtained within the time requested
One thing that may be helpful to point out is that I am able to perform other actions like querying the database and inserting new records without any lock errors. In addition I am using OpenJPA and spring is injecting the PersistenceUnit into my DAO. I'm guessing that mixing up the usage of the PersistenceUnit and the direct use of the datasource within my DBUnit setup code (testSetup and testTeardown) may be part of the issue. I'm currently using Derby as my database.
My Code is provided below:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "/applicationContext.xml")
#TransactionConfiguration(defaultRollback = true)
public class TerritoryZoneManagerTest {
#Autowired
private DataSource unitTestingDataSource;
#Autowired
private ITerritoryZoneDaoManager mgr;
#Before
public void testSetup() throws DatabaseUnitException, SQLException,
FileNotFoundException {
Connection con = DataSourceUtils.getConnection(unitTestingDataSource);
IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
IDataSet dataSet = builder
.build(new FileInputStream(
"./src/com.company.territoryzonelookup/dao/test/TerritoryZoneManagerTest.xml"));
try {
// NOTE: There is no need to use the DatabaseOperation.DELETE
// functionality because spring will automatically remove all
// inserted records after each test case is executed.
DatabaseOperation.REFRESH.execute(dbUnitCon, dataSet);
} finally {
DataSourceUtils.releaseConnection(con, unitTestingDataSource);
}
}
#After
public void testTeardown() throws DatabaseUnitException, SQLException,
FileNotFoundException {
Connection con = DataSourceUtils.getConnection(unitTestingDataSource);
IDatabaseConnection dbUnitCon = new DatabaseConnection(con);
FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
IDataSet dataSet = builder
.build(new FileInputStream(
"./src/com.company.territoryzonelookup/dao/test/TerritoryZoneManagerTest.xml"));
try {
// NOTE: There is no need to use the DatabaseOperation.DELETE
// functionality because spring will automatically remove all
// inserted records after each test case is executed.
DatabaseOperation.DELETE.execute(dbUnitCon, dataSet);
} finally {
DataSourceUtils.releaseConnection(con, unitTestingDataSource);
}
}
#Test
#Transactional
public void updateTerritory() {
TerritoryZone zone = new TerritoryZone();
int id = 1;
zone = mgr.getTerritory(id);
String newCity = "Congerville";
zone.setCity(newCity);
mgr.updateTerritory(zone);
zone = mgr.getTerritory(id);
Assert.assertEquals(newCity, zone.getCity());
}
}
The DAO object is provided below as well in case that is useful.
#Repository
public class TerritoryZoneDaoManager implements ITerritoryZoneDaoManager {
/*
#Autowired
private EntityManagerFactory emf;
*/
/*
* #PersistenceUnit EntityManagerFactory emf;
*
* #PersistenceContext private EntityManager getEntityManager(){ return
* emf.createEntityManager(); }
*/
#PersistenceContext
private EntityManager em;
private EntityManager getEntityManager() {
// return emf.createEntityManager();
return em;
}
/* (non-Javadoc)
* #see com.company.territoryzonelookup.dao.ITerritoryZoneManager#addTerritory(com.company.territoryzonelookup.dao.TerritoryZone)
*/
#Override
public TerritoryZone addTerritory(TerritoryZone territoryZone) {
EntityManager em = getEntityManager();
em.persist(territoryZone);
return territoryZone;
}
/* (non-Javadoc)
* #see com.company.territoryzonelookup.dao.ITerritoryZoneManager#getTerritory(int)
*/
#Override
public TerritoryZone getTerritory(int id) {
TerritoryZone obj = null;
Query query = getEntityManager().createNamedQuery("selectById");
query.setParameter("id", id);
obj = (TerritoryZone) query.getSingleResult();
return obj;
}
/* (non-Javadoc)
* #see com.company.territoryzonelookup.dao.ITerritoryZoneManager#updateTerritory(com.company.territoryzonelookup.dao.TerritoryZone)
*/
#Override
public TerritoryZone updateTerritory(TerritoryZone territoryZone){
getEntityManager().merge(territoryZone);
return territoryZone;
}
/* (non-Javadoc)
* #see com.company.territoryzonelookup.dao.ITerritoryZoneManager#getActiveTerritoriesByStateZipLob(java.lang.String, java.lang.String, java.util.Date, java.lang.String)
*/
#Override
public List<TerritoryZone> getActiveTerritoriesByStateZipLob(String stateCd, String zipCode, Date effectiveDate, String lobCd){
List<TerritoryZone> territoryList;
Query query = getEntityManager().createNamedQuery("selectActiveByZipStateLob");
query.setParameter("zipCode", zipCode);
query.setParameter("state", stateCd);
query.setParameter("lob",lobCd);
query.setParameter("effectiveDate", effectiveDate);
territoryList = (List<TerritoryZone>) query.getResultList();
return territoryList;
}
/* (non-Javadoc)
* #see com.company.territoryzonelookup.dao.ITerritoryZoneManager#deleteAll()
*/
#Override
public void deleteAll(){
Query query = getEntityManager().createNativeQuery("Delete from TerritoryZone");
query.executeUpdate();
}
/***
* the load method will remove all existing records from the database and then will reload it using it the data passed.
* #param terrList
*/
public void load(List<TerritoryZone> terrList){
deleteAll();
for (TerritoryZone terr:terrList){
addTerritory(terr);
}
}
}
Thanks in advance for your assistance.
Jeremy
jwmajors81
i can not know what's wrong with your unit testing code for lacking some details.
i also used spring unit test and dbunit for my himvc framework, a RAD framework based on spring3 and hibernate. here is the code of my super class for unit testingļ¼
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:config/application-test-config.xml"})
#Transactional
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
public class HiMVCTransactionalUnitTest extends AbstractTransactionalJUnit4SpringContextTests{
#Autowired
protected DBUnitHelper dbHelper;
protected void loadFixture(){
try{
String fixtureFile=this.dbHelper.getDataFile();
if(fixtureFile==null){
fixtureFile=this.getDefaultXMLFixtureFile();
this.dbHelper.setDataFile(fixtureFile);
}
if(this.dbHelper.isDataFileExisted()){
if(this.dbHelper.isMSSQL()){
HiMVCInsertIdentityOperation operation=new HiMVCInsertIdentityOperation(DatabaseOperation.CLEAN_INSERT);
operation.setInTransaction(true);
this.dbHelper.executeDBOperation(operation);
}else{
this.dbHelper.executeDBOperation(DatabaseOperation.CLEAN_INSERT);
}
}
}catch(Exception x){
x.printStackTrace();
}
}
...
}
i use the #Transactional annotation in the class declaration, and also specified the transactionManager. i wrote a DBUnitHelper to wrap the dbunit details of data loading.
here is a unit test sample:
public class MyTest extends HiMVCTransactionalUnitTest{
#Before
public void setup(){
super.loadFixture();
}
//other testing methods
}
Hope these codes helpful.