Avoid proliferation of #MockBeans in Spring Boot #WebMvcTest test - spring-mvc

I have a simple controller e.g.
#Controller
public class FooController
{
#Autowired
private BarService barService;
#RequestMapping(value = "/foo", method = RequestMethod.GET)
public String displayFoo()
{
return "foo";
}
}
When I want to do a #WebMvcTest, I have to create a great number of #MockBeans to prevent a NoSuchBeanDefinitionException.
#RunWith(SpringRunner.class)
#WebMvcTest
#Import(WebSecurityConfig.class)
public class FooControllerTest
{
#MockBean ...
#MockBean ...
#MockBean ...
...
...
}
Does this mean that BarService is somehow creating a chain of dependencies? (it has some dependencies but some #MockBeans appear completely unrelated).
The problem is, is that each #WebMvcTest I add for different controllers also requires the same #MockBeans.
Should I be using an annotation like #TestConfiguration to specify all the #MockBeans for the DRY principal?

I looked at this again, and found you can pass the controller name to #WebMvcTest e.g. #WebMvcTest(FooController.class).
Specifies the controllers to test. May be left blank if all {#code
#Controller} beans should be added to the application context.

As Hal8k said, if you don't specify a controller like #WebMvcTest(YourController.class), it will try to load all #Controller components. And #Import(WebSecurityConfig.class) also try to inject components in WebSecurityConfig.class.
Refer : https://spring.io/blog/2016/08/30/custom-test-slice-with-spring-boot-1-4

This could happen when the bean scanning configuration is faulty or excessive.
In my case, I was still getting the error despite having specified the controller to test in #WebMvcTest(FooController.class).
I eventually realised it was due to the #ComponentScan of my application being needlessly cluttered up. My Application.java was something like this:
#SpringBootApplication
#ComponentScan({"fr.nevechris.projectname","fr.nevechris.projectname.otherpackage"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
I removed the #ComponentScan entirely and the issue was solved.
If your #ComponentScan is good or not specified, try searching for other places in your project where configuration is done (eg #Configuration tag).

Related

Please help to explain a strange combination of Lombok's #AllArgsConstructor and spring's #RestController

I'm working on a spring project from our customer.
Below is the code for controller
#Log4j2
#RestController
#AllArgsConstructor
#RequestMapping(path = "/api/theapi")
#Api(value = "Description for the API")
public class TheAPIController {
private final ModelMapper modelMapper;
private final ObjectMapper objectMapper;
private final TheDemoService demoService;
...other code for controller
}
Below is the code for Service:
#Service
public class TheDemoService{ ... }
I was so surprise about 2 things:
Question 1: Why we need to use #AllArgsConstructor from project Lombok?
As per my understanding, Spring provide #RestController that Spring runtime container will initialize an Instance for our Controller. So that, having a constructor for our Controller seems like an invalid approach for using Spring Inversion of Control, is this correct?
Question 2. Because of using #AllArgsConstructor, somehow, the instance for demoService is to be injected
But again, I surprise because the code of Controller does not have #Autowired in combine with demoService.
In the actual code, there is no #Autowired for "private final TheDemoService demoService".
Hence, I could think of a possibility there, is that because of Lombok's #AllArgsConstructor would inject an instance of our TheDemoService via a constructor of
TheAPIController, I could not reason anything about this logic.
It's Invalid approach, no need for defining constructor for RestController
It's implicitly auto wiring the service
if a class, which is configured as a Spring bean, has only one constructor, the Autowired annotation can be omitted and Spring will use that constructor and inject all necessary dependencies.
To sum up #AllArgsConstructor can/should be removed

Integrate vertex with existing spring web application

I have an existing Spring based web application. I want to integrate vertx within the application.
Is there a way to do so?
Yes, have a look at the Vert.x with Spring section in the examples repository on GitHub.
In spring boot it is fairly simple
#SpringBootApplication
#ComponentScan(basePackages = { "com.mypackage", "com.myotherpackage" })
public class MyApplication {
#Autowired
private MainVerticle mainVertical;
public static void main(String[] args) throws Exception {
new SpringApplication(MyApplication.class).run(args);
}
#PostConstruct
public void deployServerVerticle() {
Vertx.vertx().deployVerticle(mainVertical);
}
}
The #PostConstuct allows you to deploy all the verticals you want (all the properties are set at this point).
And it goes without saying that the MainVerticle should be marked with the #Component annotation.

Using a custom interceptor in spring-boot, the #Value default is taking precedence over my configured value

I am in the trenches of writing my first spring-boot app, so I believe I have a configuration issue somewhere that is causing my error.
I have a class, "MyInterceptor", and it is annotated with "#Component" and extending HandlerInterceptorAdapter.
#Component
public class MyInterceptor extends HandlerInterceptorAdapter { ... }
And I have a configuration class "WebConfiguration" that is annotated with "#Configuration" (and is NOT annotated with "#EnableWebMvc").
I declare/inject my interceptor class in WebConfiguration like so:
#Resource
private MyInterceptor myInterceptor;
and then specify this class as an interceptor like so:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(myInterceptor);
}
In MyInterceptor, I have a property declared for which I want to inject a value. I have it declared, with a default, like so:
#Value("${my.interceptor.property:default_value}")
private String myInterceptorProperty;
When I have the "default_value" declared in the #Value annotation as I do above, then that value is always used. The value declared in my application-dev.yml file is ignored.
When I remove the default value, then the value in my application-dev.yml is used.
It is my suspicion that the default value from the #Value annotation is being loaded AFTER the configured value and overriding it for some reason. But I can't figure out why or how to stop it.
Other services in my app that are using #Value annotations, but that are NOT declared/injected in my WebConfiguration, are not exhibiting the same behavior.
I tried adding my interceptor like this instead:
#Bean
public MyInterceptor getMyInterceptor() {
return new MyInterceptor();
}
and then changed this:
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getMyInterceptor());
}
But when I did this, then the configuration values in the application-dev.yml were never picked up regardless of whether or not I had a default value declared.
I do understand why the #Resource annotated injection is making my configured properties available, and why the direct constructor call in the Config class is not. But is using the #Resource annotation the wrong way to do it? Why isn't my default being overridden?
How should I be injecting configuration values into my interceptors and other classes that are similarly declared in my Config class?

404 fail while trying to run spring boot app from start.spring.io

When I'm starting my mini project in spring boot (which mostly I generated from start.spring.io) from command line by command mvn spring-boot:run and walk to the http://localhost:8080/test/{michal} I see the 404 fail.
Beside that I can't create return statement in controller class using Response.create -> it shows:
The method create(String) is undefined for the type Response
I think this is the main problem why my app doesn't want to run properly.
This is my controller class
#RestController
public class TestController {
#Autowired
private TestService testService;
#RequestMapping(value = "/test/{name}", method = RequestMethod.GET)
public Response<String> /*#ResponseBody String*/ getWelcomeText(#PathVariable("name") String name) {
return Response.create(testService.loadWelcomeText(name));
}
}
This is my service class
#Service
public class TestService {
public String loadWelcomeText(String name) {
return "Hello " + name;
}
}
I have #ComponentScan annotation
It's like this: I have #ComponentScan annotation
How it looks in my project
Update
Looking at package layout you need to add #ComponentScan("com.bielawski.michal") annotation on your main class to tell spring-boot where to locate controller and service (or move main class to com.bielawski.michal package).
I think the problem is your use of Response instead of ResponseEntity. Not sure where you got documentation that said to use Response but the official documentation describes it here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-httpentity
Constructors for using ReponseEntity are: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html

Java Object with static variable instance inside Stateless Bean

Is it ok to have an object inside of EAR like the Calculator class to be used as a utility for other stateless classes?
Is it a bad design? If so what appropriate approach should be applied?
#Stateless
class A{
public void sumForA(){
System.out.println("SUM IS : "+ (Calculator.getInstance().add(4+6)));
}
}
#Stateless
class B{
public void sumForB(){
System.out.println("SUM IS : "+(Calculator.getInstance().add(1+2)));
}
}
public class Calculator{
static{
INSTANCE=new Calculator();
}
private static INSTANCE;
public Calculator getInstance(){
return INSTANCE;
}
public int add(int x,int y){
return x+y;
}
}
First, there is no such name "static variable instance", there is instance variables and static variables, you can find an example here: Java Static vs Instance.
Second, regarding your Calculator class, you need to mark the getInstance() method as static beacause you are calling it directly. And, you seem trying to use the singleton pattern, I suggest you take a look at this SO question: What is an efficient way to implement a singleton pattern in Java?
Third, in your example there is no static variable in the statless bean, and to make it simple: you are only invoking a method in the Class Calculator which has static members. So why not?! you are using your utility class inside your method, it doesn't matter if it's a stateless bean or any kind of beans (EJB session beans, CDI / JSF beans, Spring Components ... ).

Resources