spring and #transactional, is this normal? - java

i wrote this simple example:
//file TestController.java
public interface TestController {
public List<Test> findAll();
}
//file TestControllerImp.java
#Controller
public class TestControllerImp implements TestController{
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory=sessionFactory;
}
public List<Test> findAll() {
return sessionFactory.getCurrentSession().createQuery("from Test").list();
}
}
//file TestService.java
#Service
public class TestService {
#Autowired
private TestController controller;
public boolean flag=true;
public void setController(TestController controller){
this.controller=controller;
}
#Transactional
public List<Test> useController(){
flag=false;
return controller.findAll();
}
}
And this is my try:
TestService s1=context.getBean(TestService.class);
TestService s2=context.getBean(TestService.class);
List<Test> list=s1.useController();
System.out.println(s1.flag+" "+s2.flag);
Now the strange behaviour (im very new with spring):
If i declare #Transactional the method "useController()", the output is: true true
If i move #Transactional from TestService to TestControllerImp, and i declare "findAll()" with #Transactional, the output is: false false.
Why i have this behaviour? I know by default #Autowired classes are singletone, but why in the first case the flag still remains true?
Thanks all.

The #Transactional mechanism works on JDK proxies per default and those work on interfaces only.
So if you let TestService be an interface and TestServiceImpl be its implementation, then the above code should work.
e.g. change the class declaration to this:
#Service
public class TestServiceImpl implements TestService {
but the test code must reference the interface, not the class:
// this code remains unchanged
TestService s1=context.getBean(TestService.class);
TestService s2=context.getBean(TestService.class);
Reference:
<tx:advice/> settings (Spring Reference)
Using #Transactional (Spring Reference)
TransactionProxyFactorybean (javadoc)

Related

Field ClientService required a bean that could not be found in Spring

This is my ClientService class :
public interface ClientService{
public void saveClient(Client client);
}
This is the implementation :
#Service("clientService")
public class ClientServiceImpl{
#Autowired
private ClientRepository clientRepository;
public void saveClient(Client client) {
clientRepository.save(survey);
}}
This is my repository:
#Repository("clientRepository")
public interface ClientRepository extends JpaRepository<Client, Long> { }
And in my controller I have :
#Controller
public class LoginController {
#Autowired
private ClientService clientService;
which I then try to access
clientService.save in the function.
What annotation could I possibly be missing or what am I doing wrong ?
Cuz I've done this the same way before and it has worked for other services.
Thank you
Fixed it!
I had forgotten implements ClientService in the ClientServiceImplementation class!

How to enable #ConditionalOnProperty in spring-boot on runtime changeable property

I have two class which depends on config variable:
#Component
#ConditionalOnProperty("config.db")
public class DatabaseTokenStore implements TokenStore {
}
#Component
#ConditionalOnMissingBean(DatabaseTokenStore.class)
public class SimpleTokenStore implements TokenStore {
}
so when db is true then DatabaseTokenStore class is autowired when false then SimpleTokenStore is autowired. Problem is that I can change this property in runtime with CRaSH. Then this mechanic will not work. Is there some way how to change implement of interface in runtime ?
Initialize both TokenStores on startup. And create a resolver to inject into classes where you need to work with them. Like so:
#Component
public class HelloStoreResolver {
#Autowired
private HelloStore oneHelloStore;
#Autowired
private HelloStore twoHelloStore;
public HelloStore get() {
if (condition) {
return oneHelloStore;
} else {
return twoHelloStore;
}
}
}
#Component
public class HelloController {
#Autowired
private HelloStoreResolver helloResolver;
//annotations omitted
public String sayHello() {
return helloResolver.get().hello();
}
}

Spring autowiring issue in spring batch

I seem to be having an issue with the way I have implemented autowiring in my Spring Batch application.For example if I use:
public class A{
#Autowired
BeanList beanList;
}
this works fine for Class A.In the sense that,beanList returns the values that it should.But if from a method from class A I am calling a method from a different class and then have the same
#Autowired
BeanList beanList
,beanList return a null.But autowiring seems to work fine across steps.I have
I'm not sure if I understood your question correctly. I assume, you have something like this:
public class A{
B aB;
#Autowired
BeanList beanList;
public void callToB() { aB.aMethod(); }
}
public class B {
#Autowired
BeanList beanList;
public void aMethod() {Assert.notNull(beanList);}
}
If this is correct, then the problem is likely that you didn't instantiate class B as a "spring bean".
The most simply way to do this would be to mark class B with #Component and to autowire it into class A.
public class A {
#Autowired
B aB;
or to instantiate it with an #Bean directly in class A
#Component
public class A {
#Autowired
BeanList beanList;
#Bean
B myBean() {return new B();}
public void callToB() { myBean().aMethod(); }
Does this describe and solve your problem?

How to extend #Service?

Here is a sample class below:
#Service("testService")
public class TestService {
public String something() {
return "abc";
}
}
I want to extend the class and let the container know that it needs to pick up my extended class from now.
#Service("extendedTestService")
public class ExtendedTestServiceMock extends TestService {
#Override
public String something() {
return "xyz";
}
}
Test class:
public class TestClass extends SpringTest {
#Autowired
#Qualifier("extendedTestService")
private ExtendedTestService testService;
public void testMethod() {
......
}
}
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [TestService] is defined: expected single matching bean but found 2: ExtendedTestServiceMock,testService
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:865) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:770) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:489) ~[spring-beans-3.2.8.RELEASE.jar:3.2.8.RELEASE]
... 91 common frames omitted
How to resolve it?
Try using interfaces.
public interface TestService {
String something();
}
Implementations:
#Service
#Qualifier("testService")
public class TestServiceImpl implements TestService { ... }
#Service
#Qualifier("testServiceMock")
public class TestServiceMockImpl implements TestService { ... }
And the test class:
public class TestClass extends SpringTest {
#Autowired
#Qualifier("extendedTestService")
private TestService testService;
...
}
One solution that would work in your case is the #Primary annotation.
Your TestServiceMockImpl would look like:
#Service("extendedTestService ")
#Primary
public class ExtendedTestServiceMock extends TestService {
#override
public String something() {
return "xyz";
}
}
Check out this for more details on #Primary
I however suggest that you don't follow the above solution (since this will get out of hand very quick if you start using #Primary everywhere), that you instead take a look at Spring Profiles
There are a lot of way you could create your Spring configuration using profiles, but regardless of how you end up configuring the beans, the end result would be a more clean design.
If you have an identifier to help you decide which service to initialize, then you can use ConditionlOnProperty annotation
Ex:
#Service
#ConditionlOnProperty(value = "test.service.extension.enabled")
public class TestService {
}
#Service
#ConditionlOnProperty(value = "test.service.extension.enabled", havingValue = "false")
public class ExtendedTestServiceMock extends TestService {
}
If you want to use the extended test service, you can set the property test.service.extension.enabled=true in your application.properties
It depends on your definition order if your service define on the xml file.
Otherwise, you could use a BeanFactoryPostProcessor to do this, which is only registered in the test scenarios that you want this mocked.
public class SystemTestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory factory) throws BeansException {
// put your custom code in here
}
}
Or you can use #DependsOn to make sure the parent bean should be deploy firstly then your extend bean
#Service("testService")
#DependsOn("testService")
public class ExtendedTestService extends TestService {
}
Hope this helps.

How to inject mock into #Service that has #Transactional

I have any issue in my unit test where I have something along the lines of this. The mock injection get overridden on the someService if the blargh function is annotated with Transactional. If I remove the Transactional the mock stays there. From watching the code it appears that Spring lazily loads the services when a function in the service is annotated with transactinal, but eagerly loads the services when it isn't. This overrides the mock I injected.
Is there a better way to do this?
#Component
public class SomeTests
{
#Autowired
private SomeService someService;
#Test
#Transactional
public void test(){
FooBar fooBarMock = mock(FooBar.class);
ReflectionTestUtils.setField(someService, "fooBar", fooBarMock);
}
}
#Service
public class someService
{
#Autowired FooBar foobar;
#Transactional // <-- this causes the mocked item to be overridden
public void blargh()
{
fooBar.doStuff();
}
}
Probably you could try to implement your test in the following way:
#Component
#RunWith(MockitoJUnitRunner.class)
public class SomeTests
{
#Mock private FooBar foobar;
#InjectMocks private final SomeService someService = new SomeService();
#Test
#Transactional
public void test(){
when(fooBar.doStuff()).then....;
someService.blargh() .....
}
}
I could not try it right now as don't have your config and related code. But this is one of the common way to test the service logic.
Use the Spring #Profile functionality - beans can be associated to a certain group, and the group can be activated or deactivated via annotations.
Check this blog post and the documentation for more detailed instructions, this is an example of how to define production services and two groups of mock services:
#Configuration
#Profile("production")
public static class ProductionConfig {
#Bean
public InvoiceService realInvoiceService() {
...
}
...
}
#Configuration
#Profile("testServices")
public static class TestConfiguration {
#Bean
public InvoiceService mockedInvoiceService() {
...
}
...
}
#Configuration
#Profile("otherTestServices")
public static class OtherTestConfiguration {
#Bean
public InvoiceService otherMockedInvoiceService() {
...
}
...
}
And this is how to use them in the tests:
#ActiveProfiles("testServices")
public class MyTest extends SpringContextTestCase {
#Autowired
private MyService mockedService;
// ...
}
#ActiveProfiles("otherTestServices")
public class MyOtherTest extends SpringContextTestCase {
#Autowired
private MyService myOtherMockedService;
// ...
}
I have the exact same problem and I solve it by using Mockito.any() for the arguments
eg:
when(transactionalService.validateProduct(id)).thenReturn("")
=> when(transactionalService.validateProduct(Mockito.any())).thenReturn("")

Categories

Resources