Can't get Spring Retry to work - java

I've been attempting to make my Spring application use Spring Retry for the past few days with no luck so far. I have an XML based config so I've tried adding
<context:annotation-config/>
<aop:aspectj-autoproxy />
<bean class="org.springframework.retry.annotation.RetryConfiguration" />
along with adding the needed dependencies and setting the function I'm using #Retryable, this didn't work.
I've also added a component-scan in my XML for a newly created config file, to which I've added #Configuration and #EnableRetry. I've tried this both with an empty config file and one with a ReturnPolicy set up in it, tried both of these setups with and without Aspects instead of using #Retryable. Neither options worked.
I'm running out of sources and ideas to explore, any help would be greatly appreciated.
Thanks!

I hope you are setting and calling it correctly. The #Retryable annotation on the method to be discovered needs to be called correctly from an initialised spring context. Are you doing that( method invoked from a bean from the spring context) or called by other means - outside context?
Alternatively JUnit is best friend - try SpringJunit4ClassRunner
You should restructure your test class at least to something like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes=MyConfig.class)
public class MyServiceTest {
#Configuration
#EnableRetry
#Import(myService.class)
public static class MyConfig {}
Couple of reference pages are here

Related

Spring #Value always returns a null value

I'm facing an issue with a dev I have to do with Spring (not spring boot).
In a class, I have to retrieve the value of a property defined on a properties files (application.properties).
So, I use the #Value annotation (normally it's easy to use), but it doesn't work in my case.
In my class, I have this code :
#Value("${value:'DefaultValue'}")
private String myValue;
with the import : import org.springframework.beans.factory.annotation.Value;
My property file contains : value=a value
But, when I want to test my application, I always receive a null value (also with the use of the default value).
I try to add deafferents annotations in my class like
#Component
...
Do you have any suggestion? I'm pretty sure I miss a config somewhere, but I don't know what.
Thanks in advance
Tigrou
Every class where you use #Value annotation MUST be a spring-managed bean. You can achieve this by adding #Component annotation but make sure that you have configured component scan #ComponentScan(basePackages = "your.package") in your java configuration, so spring knows where to search for components.
Finally, with the help of everybody here (special thanks to #M. Deinum I fixed my issue.
So, first thing done, replace the Junit dependeny (use) by a Spring test dependency.
secondly, I've updated my test to be executed with Spring with those lines :
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {AppConfig.class})
This was enough to retrieve the default value of the #Value field.
To retrieve the value I had to add
#PropertySource("classpath:application.properties")
in my AppConfig class

How to use Spring #Component annotation with AspectJ compiler

I excluded part of my project for easier reproduce problem: GitHub repo.
When I compile it by Javac everything works as expected. I see logging in console when I open URLs /user/ and /user/2/:
Access: execution(List ru.krivochenko.demo.user.UserController.getAll())
Access: execution(User ru.krivochenko.demo.user.UserController.getOne(Integer))
But I wanna use AspectJ compiler. When I switch to it, error occurs:
java.lang.NoSuchMethodError: ru.krivochenko.demo.logging.LoggingAspect: method <init>()V not found
As I understood it happens because there is not no-args constructor in LoggingAspect. If I add it, I get another error, because logger is not injected:
java.lang.NullPointerException: null
at ru.krivochenko.demo.logging.LoggingAspect.beforeGettingUsers(LoggingAspect.java:28) ~[classes/:na]
So, how we can see, AspectJ ignores Autowired constructor with args.
In branch via-setter of my repo I implemented another solution. I removed #Component annotation of LoggingAspect and replaced constructor injection to setter injection. In DemoApplication.java I added #Bean configuration of LoggingAspect. It works fine, but in some situations it requires getting dependencies from application context. What is the best practice to resolve it?
Thanks for help.
Spring Aspects and compile time weaving don't automatically integrate. This is primary because aspectj and spring are fairly separate and I suspect Spring's recommended approach is not to use compile time weaving.
So thus by default Aspects are not spring magic and we need to add a little bit of plumbing to ensure they are.
In this regard, it is important to note that Aspects are not spring managed (they are managed by aspectj so we need to add something to ensure they are).
Thus the reason why you need a parameterless constructor on your aspect (so must use field injection).
Traditionally I have had to add the following piece of xml to my xml config files:
<bean id="securityAspect" class="com.<skip>.security.AuthorizationAspect"
factory-method="aspectOf" autowire="byType" />
So this works because the AspectJ compiler adds the static method aspectOf to the aspects and this method is available for acquiring the instance of the Aspect that aspectj creates (and uses).
This method is obviously not available in the source so we can't just add to our application class (DemoApplication):
#Bean
public LoggingAspect loggingAspect() {
return LoggingAspect.aspectOf();
}
Then what to do? My next option was to write some reflective code to call this method then having looked at this very helpful example that demonstrates exactly what you need - The Aspects class from AspectJ has a utilty method that does this work for us, so adding the following to our DemoApplication we have success:
#Bean
public LoggingAspect loggingAspect() {
return Aspects.aspectOf(LoggingAspect.class);
}
Btw, remove the #Component from the LoggingAspect as that will mean both Aspectj and Spring create an instance of the class...
Btw, I'd also suggest you add the following to your test class to demonstrate the problem in a test:
#Autowired
private UserController controller;
#Test
public void contextLoads() {
controller.getAll();
controller.getOne(1);
}
Btw, other suggestions to address this problem used #Configurable. I suspect this might work but you'll need to make sure you include the spring aspects java in your aspectj compile time config and I suspect it may still not work as I'm not sure the Spring context will be ready in time. i.e. if the Aspect is created before the spring context then #Configurable won't work as the beans to be injected will not yet be created.
Your approach to configure the aspect via setter injection looks valid to me. For more information about how to use AspectJ in combination with Spring check out the corresponding chapter in the Spring manual, specifically the description about how to configure AspectJ aspects by Spring IoC. It is mostly explained in the context of LTW, but it should work pretty much the same for CTW.

How to tell spring to only load the needed beans for the JUnit test?

A simple question that might have an advanced answer.
The Question:
My question is, is there a way to instantiate only the classes, in your application context, needed for that specific JUnit test ?
The Reason:
My application context is getting quite big. I also do a lot of integration tests so you I guess you would understand when I say that every time I run a test all the classes in my application context get instantiated and this takes time.
The Example:
Say class Foo inject only bar
public class Foo {
#Inject
Bar bar;
#Test
public void testrunSomeMethod() throws RegisterFault {
bar.runSomeMethod();
}
but the application context has beans foobar and bar. I know this is not a vaild application context but rest assure all my code works.
<beans>
<bean id="foobar" class="some.package.FooBar"/>
<bean id="bar" class="some.package.Bar"/>
<beans>
So how do I tell spring to only instantiate Bar and ignore FooBar for the test class foo.
Thank you.
Consider adding default-lazy-init="true" to your spring context xml beans tag (or add lazy-init="true" to those specific beans that take a long time starting up).
This will ensure that only those beans are created that called with applicationContext.getBean(class-or-bean-name) or injected via #Autowired / #Inject into your tests. (Some other types of beans like #Scheduled beans will be created nevertheless but you need to check if that's a problem or not)
(if you use spring Java configuration, add #Lazy to the config files)
Caveat - If there is a bean that is not initialized explicitly with applicationContext.getBean() or injected as a dependency used by the bean obtained by using applicationContext.getBean(), then that bean will NO LONGER be constructed or initialized. Depending upon your application, that can cause things to fail OR not. Maybe you can selectively mark those beans as lazy-init="false"
Yes, we can do that, using context per test case. Prepare a test context xml file with the beans required for your test case.
If you use maven, place the test-context.xml under src/test/resources folder.
Annotate your required test class with the following annotation
#ContextConfiguration(locations = "classpath:test-application-context.xml")
This helps in loading only specific beans for the test case.
If you have two kinds of test cases, then
#Runwith(SpringJUnit4Runner.class)
#ContextConfiguration(locations = "classpath:test-context-case1.xml")
public class TestClassCase1 {}
#Runwith(SpringJUnit4Runner.class)
#ContextConfiguration(locations = "classpath:test-context-case2.xml")
public class TestClassCase2 {}
It's not direct answer, so I'd would not mark as solution. But hope it's helpful.
Generally I see three options.
As VinayVeluri answered nicely. Create separate contexts and launch them in every tests separately.
Create context one time per all tests. Just like here: Reuse spring application context across junit test classes It's a big optimization for testing all tests at once.
Mix those two first points. Create one smaller context only for testing purpose. Mock that, what's never is tested but can throw NPE etc. Like here: Injecting Mockito mocks into a Spring bean to boost up context build. And re-use it like in point 2. One time build for all tests. Personally I'd go with that one.
This one waiting for answer about some kind of smart test runner, which creates minimum needed context per test.

intellij incorrectly saying no beans of type found for autowired repository

I have created a simple unit test but IntelliJ is incorrectly highlighting it red. marking it as an error
No beans?
As you can see below it passes the test? So it must be Autowired?
I had this same issue when creating a Spring Boot application using their #SpringBootApplication annotation. This annotation represents #Configuration, #EnableAutoConfiguration and #ComponentScan according to the spring reference.
As expected, the new annotation worked properly and my application ran smoothly but, Intellij kept complaining about unfulfilled #Autowire dependencies. As soon as I changed back to using #Configuration, #EnableAutoConfiguration and #ComponentScan separately, the errors ceased. It seems Intellij 14.0.3 (and most likely, earlier versions too) is not yet configured to recognise the #SpringBootApplication annotation.
For now, if the errors disturb you that much, then revert back to those three separate annotations. Otherwise, ignore Intellij...your dependency resolution is correctly configured, since your test passes.
Always remember...
Man is always greater than machine.
Add Spring annotation #Repository over the repository class.
I know it should work without this annotation. But if you add this, IntelliJ will not show error.
#Repository
public interface YourRepository ...
...
If you use Spring Data with extending Repository class it will be conflict packages. Then you must indicate packages directly.
import org.springframework.data.repository.Repository;
...
#org.springframework.stereotype.Repository
public interface YourRepository extends Repository<YourClass, Long> {
...
}
And next you can autowired your repository without errors.
#Autowired
YourRepository yourRepository;
It probably is not a good solution (I guess you are trying to register repository twice). But work for me and don't show errors.
Maybe in the new version of IntelliJ can be fixed: https://youtrack.jetbrains.com/issue/IDEA-137023
My version of IntelliJ IDEA Ultimate (2016.3.4 Build 163) seems to support this. The trick is that you need to have enabled the Spring Data plugin.
Sometimes you are required to indicate where #ComponentScan should scan for components. You can do so by passing the packages as parameter of this annotation, e.g:
#ComponentScan(basePackages={"path.to.my.components","path.to.my.othercomponents"})
However, as already mentioned, #SpringBootApplication annotation replaces #ComponentScan, hence in such cases you must do the same:
#SpringBootApplication(scanBasePackages={"path.to.my.components","path.to.my.othercomponents"})
At least in my case, Intellij stopped complaining.
I always solve this problem doing de following..
Settings>Inspections>Spring Core>Code than you shift from error to warning the severity option
I am using spring-boot 2.0, and intellij 2018.1.1 ultimate edition and I faced the same issue.
I solved by placing #EnableAutoConfiguration in the main application class
#SpringBootApplication
#EnableAutoConfiguration
class App{
/**/
}
Check if you missed #Service annotation in your service class, that was the case for me.
Configure application context and all will be ok.
Have you checked that you have used #Service annotation on top of your service implementation?
It worked for me.
import org.springframework.stereotype.Service;
#Service
public class UserServiceImpl implements UserServices {}
Putting #Component or #configuration in your bean config file seems to work, ie something like:
#Configuration
public class MyApplicationContext {
#Bean
public DirectoryScanner scanner() {
return new WatchServiceDirectoryScanner("/tmp/myDir");
}
}
#Component
public class MyApplicationContext {
#Bean
public DirectoryScanner scanner() {
return new WatchServiceDirectoryScanner("/tmp/myDir");
}
}
Use #EnableAutoConfiguration annotation with #Component at class level. It will resolve this problem.
For example:
#Component
#EnableAutoConfiguration
public class ItemDataInitializer {
#Autowired
private ItemReactiveRepository itemReactiveRepository;
#Autowired
private MongoOperations mongoOperations;
}
simple you have to do 2 steps
add hibernate-core dependency
change #Autowired to #Resource.
==>> change #Autowired to #Resource
If you don't want to make any change to you code just to make your IDE happy. I have solved it by adding all components to the Spring facet.
Create a group with name "Service, Processors and Routers" or any name you like;
Remove and recreate "Spring Application Context" use the group you created previously as a parent.
As long as your tests are passing you are good, hit alt + enter by taking the cursor over the error and inside the submenu of the first item you will find Disable Inspection select that
For me the solution was to place #EnableAutoConfiguration in the Application class under the #SpringBootApplication its going to underline it because its redundant. Delete it and voila all you warnings regarding missing beans are vanished! Silly Spring...
And one last piece of important information - add the ComponentScan so that the app knows about the things it needs to wire. This is not relevant in the case of this question. However if no #autowiring is being performed at all then this is likely your solution.
#Configuration
#ComponentScan(basePackages = {
"some_package",
})
public class someService {
I am using this annotation to hide this error when it appears in IntelliJ v.14:
#SuppressWarnings("SpringJavaAutowiringInspection")
I had similar issue in Spring Boot application. The application utilizes Feign (HTTP client synthetizing requests from annotated interfaces). Having interface SomeClient annotated with #FeignClient, Feign generates runtime proxy class implementing this interface. When some Spring component tries to autowire bean of type SomeClient, Idea complains no bean of type SomeClient found since no real class actually exists in project and Idea is not taught to understand #FeignClient annotation in any way.
Solution: annotate interface SomeClient with #Component. (In our case, we don't use #FeignClient annotation on SomeClient directly, we rather use metaannotation #OurProjectFeignClient which is annotated #FeignClient and adding #Component annotation to it works as well.)
in my Case, the Directory I was trying to #Autowired was not at the same level,
after setting it up at the same structure level, the error disappeared
hope it can helps some one!
As most synchronisation errors between IntelliJ (IDE) and development environments.
Specially if you have automated tests or build that pass green all the way through.
Invalidate Cache and Restart solved my problem.
What you need to do is add
#ComponentScan("package/include/your/annotation/component") in AppConfiguration.java.
Since I think your AppConfiguraion.java's package is deeper than your annotation component (#Service, #Component...)'s package,
such as "package/include/your/annotation/component/deeper/config".
I had a similar problem in my application.
When I added annotations incorrect highliting dissapeared.
#ContextConfiguration(classes = {...})
IntelliJ IDEA Ultimate
Add your main class to IntelliJ Spring Application Context, for example Application.java
File -> Project Structure..
left side:
Project Setting -> Modules
right side: find in your package structure
Spring and add + Application.java
just add below two annotations to your POJO.
#ComponentScan
#Configuration
public class YourClass {
//TODO
}
#Autowired(required = false)
will shut intellij up
My solution to this issue in my spring boot application was to open the spring application context and adding the class for the missing autowired bean manually!
(access via Project Structure menu or spring tool window... edit "Spring Application Context")
So instead of SpringApplicationContext just containing my ExampleApplication spring configuration it also contains the missing Bean:
SpringApplicationContext:
ExampleApplication.java
MissingBeanClass.java
et voilĂ : The error message disappeared!
This seems to still be a bug in the latest IntelliJ and has to do with a possible caching issue?
If you add the #Repository annotation as mk321 mentioned above, save, then remove the annotation and save again, this fixes the problem.
Sometimes - in my case that is - the reason is a wrong import. I accidentally imported
import org.jvnet.hk2.annotations.Service
instead of
import org.springframework.stereotype.Service
by blindly accepting the first choice in Idea's suggested imports. Took me a few minutes the first time it happend :-)
All you need to do to make this work is the following code:
#ComponentScan
public class PriceWatchTest{
#Autowired
private PriceWatchJpaRepository priceWatchJpaRepository;
...
...
}
I just had to use #EnableAutoConfiguration to address it, however this error had no functional impact.

Why is Spring not wiring my #Autowired members in a dependent jar?

I'm building a Google App Engine app using Spring 3.1 and am having a problem getting members in one of my jars wired.
I have three projects:
server
server.model
server.persistence
I have an ant build script so that when my workspace builds, it creates jars for server.model and server.persistence, and puts them in the correct lib directory for the server project.
In server, I can autowire things from both server.model and server.persistence, but in server.model my server.persistence beans aren't getting wired even though they're the exact same as in server.
snippet from my servlet application config:
<context:component-scan base-package="com.impersonal.server"/>
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
<bean autowire="byType" id="userList" class="com.impersonal.server.model.UserList"/>
I have the following code in both the server project and the server.model project, and only the server one gets fulfilled. Here's the one failing:
package com.impersonal.server.model;
import java.util.ArrayList;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import com.impersonal.server.persistance.AppEngineDataStore;
import com.impersonal.server.persistance.IDataStore;
public class UserList extends ArrayList<User>
{
private UserList(){}
//this is always null, but the same line in a class in the other project works
private #Autowired AppEngineDataStore _dataStore;
public UserList(UUID userId, String tempId)
{
String poo = "poo";
poo.concat("foo ");
int i = 3;
}
}
Edit:
Just did a test in the server.model project trying to #Autowired something that I don't have defined as a bean in my application config, and didn't get any errors. I should have got a 'no such bean found' error like I do if I do the same thing for the server project.
Any ideas why?
I was instantiating my objects incorrectly. For framework objects and such like MVC controllers, you don't need to do anything to get your #Autowired members wired.
For objects I was creating on the fly, I wasn't going through the IOC container, that's why their dependencies weren't being fulfilled.
<context:component-scan/> tag searches for annotated classes.
If you are going to autowire class using #Autowire annotation, Autowiring class should be annotated with one of stereotype annotation (#Component,#Controller,#Service,#Repository). Spring resolves first annotation configuration and then xml configuration. This is written in spring doc as
Annotation injection is performed before XML injection, thus the latter configuration will override the former for properties wired through both approaches.
Check proof on spring doc.
So what you need to do is add annotations for classes from server project as well as server.model. Same in case of your third project server.persistence. Add annotations according to layers or functionality.
Try:
#Autowired(required = true)
private AppEngineDataStore _dataStore;
Instead of:
private #Autowired AppEngineDataStore _dataStore;
EDIT 1:
While using the autowire above, in your spring xml, try:
<bean id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" scope="prototype"></bean>
Instead of:
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore"/>
autowire in xml means slightly different thing. Instead of defining your bean in xml, you can annotate it as #Service, it will be discovered by the component-scan and the #Autowired will work.
In your xml configuration, use autowire-candidate property
<bean autowire="byType" id="appEngineDataStore" class="com.impersonal.server.persistance.AppEngineDataStore" autowire-candidate="true" />

Categories