spring + testng + hibernate right approch for session factory - java

I am building a spring 4 + Hibernate5 application. I wonder whether is there any difference in defining the data base connection properties like url ,username etc via DataSource object and via hibernate properties like "hibernate.connection.url", "hibernate.connection.username" etc. Offcourse ultimately the datasource object will be tied to the session factory. Just want to make sure to do the things in right way.
I want to define a separate datesource object via dataSource property, so that I can use the AbstractTransactionalTestNGSpringContextTests for test cases. This classs is always expecting a data source object. I want to use the #Rollback feature and this feature is working with AbstractTransactionalTestNGSpringContextTests. AbstractTestNGSpringContextTests is not supporting the roll back feature but still persisting working perfectly.
Need inputs to implements in the right way.
Adding example code to provide more information.
#ContextConfiguration(locations = { "classpath:spring/fpda_persistence_config.xml" })
#Rollback
#Transactional
public class BankTransactionDAOTest extends AbstractTestNGSpringContextTests {
#Autowired
private BankTransactionDAO bankTransactionDao;
#Test
public void createBankTransactionTest(){
BankTransaction bt = new BankTransaction();
bt.setAuthoritativeTableId(new BigDecimal(1234));
bt.setBankTransactionTypeCode(new Character('C'));
bt.setInstanceId(new BigDecimal(1234));
bt.setRowCreatedEpochTime(new BigDecimal(1234));
bt.setTransactionId(new BigDecimal(1234));
bt.setTransactionKey(new BigDecimal(System.currentTimeMillis()));
bankTransactionDao.createBankTransaction(bt);
}
}
here to make transaction roll back happen sucessfully, I came to know that we should extend AbstractTransactionalTestNGSpringContextTests instead of AbstractTestNGSpringContextTests. Then I should have declared the datasource property instead of defining all properties in hibernate properties.
so overall is it a right approach to declare some properties in data source and some properties in hibernate?. will it make any difference.
Thanks in Advance.

In our project we are using class-level annotation for test classes
#TestPropertySource(locations = "classpath:application-test.properties")

Related

What's the Spring way of accessing properties from an entity?

I'm new to Spring and I'm building an application where some entities (JPA/Hibernate) need access to a property from application.properties. I do have a configuration class in which this is trivial:
#Configuration
public class FactoryBeanAppConfig {
#Value("${aws.accessKeyId}")
private String awsAccessKeyId;
#Value("${aws.secretKey}")
private String awsSecretKey;
}
but since entities do not have and I think they should not have the annotations such as #Configuration or #Component, what's the Spring way for them to access the property?
Now, I know I can create my own class, my own bean, and make it as a simple wrapper around the properties; but is that the Spring way to do it or is there another way?
specify Property file location using #PropertySource
Something like below
#PropertySource("classpath:/application.proerties")
You also need to add below bean in your config
#Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigIn() {
return new PropertySourcesPlaceholderConfigurer();
}
There is no "Spring way", since JPA entities and Spring have nothing to do with each other. Most importantly, JPA entities are not Spring beans, so Spring doesn't know or care about them as they're not managed by Spring.
You can try to hack around, trying in vain to access Spring's configuration from code that should not be trying to access it, or you can accept the truth that your design is broken and you're trying to do something that's not meant to be done.
As was proposed several times, use a service class for this. It's managed by Spring, so it can access the Spring config, and it can handle entities, so there's no crossing boundaries.
First create a public static variable in some bean managed by Spring, then make the following use of the #Value annotation.
public static String variable;
#Value("${variable}")
private void setVariable(String value) {
variable = value;
}
It will be set at runtime on startup, now you can access it from entities and everywhere else because it is just a public static var.
You can use #PropertySource to load the properties file as follows
#Configuration
#PropertySource("classpath:/com/organization/config/application.proerties")
public class FactoryBeanAppConfig {
...
}
Entities should not acces environment properties. If you are using your entity through a service, then the service can access the properties to act on the entity.

UnitTests and Spring - create new beans?

I have an application where I use Spring (annotations, not xml), and I need to load the beans in my unit tests. I have the AppConfig class from my code which I want to use, but with a different datasource (one I define in the test folder). This is because I want to use an in memory DB in my tests, and not the real DB.
Here's how I try to run the AppConfig class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {App.class, AppConfig.class})
public class DAOManagerTest {
//All code goes here
#AutoWired
UserDAO userDAO;
#Test
public void testGet() {
List<User> test = userDAO.selectAll();
for (User u: test) {
u.toString();
}
}
}
This doesn't entirely work, as it fails on creating a bean inside the UserDAO class. I guess I need some tutorial / guide on how to deal with spring in unit tests. Should I define new beans in my test folder, or is it possible to user the spring class from my code? Also, is it possible to define a seperate datasource for the tests?
Yes. For example, if you define some beans in DAOManagerTest, using #Primary if necessary, and add DAOManagerTest.class to #ContextConfiguration.
There are so many other ways of arranging it though, like using profiles or mocks, etc.

JUnit multiple transaction managers for spring tests

I'm using Spring 3.0.5 and Junit 4.8.2
Is it possible to use multiple transaction managers during tests?
Basically I'm try for something like this. I need to add and remove content from two separate databases during the tests.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:/applicationContext-test.xml" })
#TransactionConfiguration(transactionManager = "txMgrA", defaultRollback = true)
#TransactionConfiguration(transactionManager = "txMgrB", defaultRollback = true)
#Transactional
public class SampleTest {
...
}
Looking at Spring 5 TransactionalTestExecutionListener implementation, it looks it only supports one TransactionManager per thread, what seems to be a design flaw of this listener, probably the same as you came across in 2011 :)
However, currently it's possible to workaround this using ChainedTransactionManager. If you have multiple transaction managers, you can define yet another transaction manager in your test context:
#Configuration
class TestTransactionConfig {
#Bean("testTransactionManager")
public PlatformTransactionManager chainedTransactionManager(
#Qualifier("transactionManager1") PlatformTransactionManager transactionManager1,
#Qualifier("transactionManager2") PlatformTransactionManager transactionManager2
) {
return new ChainedTransactionManager(transactionManager1, transactionManager2);
}
}
Now, you can define your base class for tests using this transaction manager:
#RunWith(SpringRunner::class)
#Transactional("testTransactionManager")
class BaseTransactionalTest {
}
For all derived classes all test methods will now be wrapped in both transactions, which will be finally rolled back by TransactionalTestExecutionListener.
Since Java will not allow multiple annotations of the same type per element, you must find another way to configure it. #TransactionConfiguration is interpreted by TransactionalTestExecutionListener, whose getTransactionManager method only returns a single PlatformTransactionManager. It looks at #Transactional but seems to ignore the value qualifier that was added in Seam 3.0.
#Transactional itself only supports a single transaction manager. How is the real application configured? You must be using #Transactional("<qualifier>") (as in the docs), right?
If you just use #Transactional with different tx managers on different methods, then the simplest solution is to just split your test class.
Are you nesting the transactions? That is, you have #Transactional("tm1") on one method, which calls a nested method that has #Transactional("tm2")? Sounds a little unusual. You could try to set up your test in the same way -- have two test #Services, each with the appropriate #Transactional annotations, that are proxied with tx:advice as usual. The outer service sets up the outer txn; the inner service sets up the inner txn and contains the actual test code. You can't use #Rollback, but hey, hacks ain't pretty.
Another option would be to create your own PlatformTransactionManager that delegates to the two other managers (for testing purposes only).
Maybe better would be to just give up and manually manage the two transactions in the test's #Before/#After methods.
Best would be to use JTA global transactions. Hopefully you're not actually nesting separate transactions and this is all moot ;)

Spring start a transaction with object created by new

I have a POJO class with a method annotated with #Transactional
public class Pojo {
#Transactional
public void doInTransaction() {
...
}
}
Spring declarative transaction management is based on AOP but I don't have any experience with that. My question is:
Is it possible that when invoking the (new Pojo).doInTransaction() alone, Spring will start a Transaction.
Spring declarative transaction
management is based on APO but I don't
have any experience with that.
I would recommend to start working with it and you will get the experience of using transaction advices using AOP. A good starting point is here.
Is it possible that when invoking the
(new Pojo).doInTransaction() alone,
Spring will start a Transaction.
No, you can't expect Spring to be aware of a bean that you manually invoked. However, it sounds like that you are wanting to avoid declarative transaction management and do programmatic transaction management. There is a way to do that with Spring using the Transaction Template. Is that what you were looking for?
It is somewhat possible, but in a cumbersome way: You must use the AutowireCapableBeanFactory mechanism.
Here is a transactional class as example
public interface FooBar{
void fooIze(Object foo);
}
public class FooBarImpl implements FooBar{
#Transactional
#Override
public void fooIze(final Object foo){
// do stuff here
}
}
And here is how we can use it:
public class FooService implements ApplicationContextAware{
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(
final ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
public void serviceMethod(){
//declare variable as interface, initialize to implementation
FooBar fooBar = new FooBarImpl();
// try to use it, won't work, as it's not a proxy yet
Object target = new Object[0];
fooBar.fooIze(target); // no transaction
// now let spring create the proxy and re-assign the variable
// to the proxy:
fooBar = // this is no longer an instance of FooBarImpl!!!
(FooBar) applicationContext
.getAutowireCapableBeanFactory()
.applyBeanPostProcessorsAfterInitialization(fooBar,
"someBeanName");
fooBar.fooIze(fooBar); // this time it should work
}
}
This is not a best practice. For one thing, it makes your application highly aware of the Spring Framework and also, it violates the dependency injection principles. So use this only if there is no other way!
Yes, it is possible. Spring does not require the use of dynamic proxies for #Transactional to work. Instead, you can use "true AOP", as provided by AspectJ.
For the details, see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/transaction.html#transaction-declarative-aspectj
The way Spring handle the transaction through Annotation is using AOP as you've said.
The AOP bit is implemented using Dynamic Proxies (see doc)
So in order to do so you'll need to retrieve an instance of your class (Pojo here) through the spring container since to make it work, Spring will return you a Dynamic Proxy over your Pojo that will automatically surround any annotated method with the transaction management code.
If you simply do a
Pojo p = new Pojo();
p.doInTransaction();
Spring doesn't have any role to play here and your method call won't be inside a transaction.
so what you need to do is something like this
ApplicationContext springContext = ...;
Pojo p = (Pojo) springContext.getBean("your.pojo.id");
p.doInTransaction();
Note: this is an example, you should prefer dependency injection instead of retrieving your bean manually from the context
By doing so, and with a properly configured Spring Context, Spring should have lookout your classes to scan for transactional annotation and automatically wrapped your beans into annotation aware dynamic proxies instances. From your point of view that doesn't change anything, you'll still cast your object to your own Classes, but if you try to print out the class name of your spring context Pojo bean, you'll get something as Proxy$... and not your original class name.
Have a look at this link anyway : link text

How can I make Spring testcontext framework use multiple data sources?

I'm trying to integration test my application with Spring TestContext framework. I have done this by extending AbstractTransactionalJUnit4SpringContextTests, as usual. However, my application has three different data sources (with names like xDataSource, yDataSource, zdataSource), så when I try to run the test, the autowiring of data source in AbstractTransactionalJUnit4SpringContextTests won't work, since it looks for a Data Source with autowire-by-type, but finds three, so it does not know which one to choose.
Is there any way to get Spring TestContext Framework to use three data sources? If so; how?
OK, I figured it out. The answer to this question is twofold. Firstly, extending AbstractTransactionalJUnit4SpringContextTests won't work. This is because it needs a single data source for creating the SimpleJdbcTemplate for verifying stuff with simple JDBC queries in the test. Since I don't use this feature in this test, I could replace extends AbstractTransactionalJUnit4SpringContextTests with the collowing configuration:
#ContextConfiguration(locations = "classpath:applicationContext.xml")
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class
})
#Transactional
public class IntegrationTest {
...
}
The combination of these annotations gives the same setup as extending AbstractTransactionalJUnit4SpringContextTests.
The second part was understanding that since I have three data sources, I also need all three so be referenced by the same PlatformTransactionManager. I have distributed transactions. This is impossible with a DataSourceTransactionManager, so I had to use a JtaTransactionManager.
The AbstractTransactionalJUnit4SpringContextTests class is autowired to a single data source only to allow the convenience of providing an injected JdbcTemplate object. You can override the setDataSource(DataSource dataSource) method from AbstractTransactionalJUnit4SpringContextTests in your test subclass and specify the data source to use like this:
#Resource(name = "dataSource")
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
You just have to provide the name of the one data source Spring should use for the jdbcTemplate convenience methods. If extending AbstractTransactionalJUnit4SpringContextTests is more convenient than other methods mentioned above, then you can force it to work by just choosing one of your data sources.
I found these details in Spring Jira ticket #SPR-4634.
You can define one of the data-sources as primary="true" in your xml, and it will be chosen.
If you need all threem then you cannot rely on autowiring - use ReflectionTestUtils to set it manually in your tests.

Categories