Integrate vertex with existing spring web application - spring-mvc

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.

Related

Avoid proliferation of #MockBeans in Spring Boot #WebMvcTest test

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).

Mockito failure: Actually, there were zero interactions with this mock

I'm trying to test a spring rest controller class using JUnit, Mockito, Spring test and Spring Security test. The following is my rest controller class for which i'm performing the test;
#RestController
public class EmployeeRestController {
#Autowired
private EmployeeService employeeService;
#PreAuthorize("hasAnyRole('ROLE_EMPSUPEADM')")
#RequestMapping(value = "/fetch-timezones", method = RequestMethod.GET)
public ResponseEntity<List<ResponseModel>> fetchTimeZones() {
List<ResponseModel> timezones = employeeService.fetchTimeZones();
return new ResponseEntity<>(timezones, HttpStatus.OK);
}
}
The following is my test class;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {SpringConfiguration.class})
#WebAppConfiguration
public class EmployeeRestControllerUnitTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private EmployeeService employeeService;
#InjectMocks
private EmployeeRestController employeeRestController;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
}
#Test
#WithMockUser(roles = {"EMPSUPEADM"})
public void testFetchTimezones() {
try {
mockMvc.perform(get("/fetch-timezones"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", hasSize(4)));
verify(emploeeService, times(1)).fetchTimeZones();
verifyNoMoreInteractions(employeeService);
} catch (Exception e) {
e.printStackTrace();
}
}
}
I made the above test class by refering many tutorials. The problem is i'm not able to understand everything clearly. so, i'm having the following doubts.
I'm creating a mock of EmployeeService and injecting it into EmployeeRestController using #InjectMocks, then why i'm getting the following failure;
Wanted but not invoked:
careGroupService.fetchTimeZones();
-> at com.example.api.test
.restcontroller.EmployeeRestControllerUnitTest
.testFetchTimezones(EmployeeRestControllerUnitTest.java:73)
Actually, there were zero interactions with this mock.
How does MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); works exactly.
I know that MockMvcBuilders.standaloneSetup(employeeRestController) is for testing individual controller classes and spring configuration will not be available for this method. How can we provide spring configuraton for this method, is it possible.
Finally, how does this piece of code: Mockito.reset(employeeService); works.
1) you do verify for
verify(emploeeService, times(1)).fetchTimeZones();
but you didn't setup mock behaviour for it (before you call mockMvc.perform(get("/fetch-timezones"))).
List<ResponseModel> timezones = new ArrayList<>();
when(emploeeService.fetchTimeZones()).thenReturn(timezones );
2) create MockMvc from context. mockmvc emulates web container, use mock for all where is possible but supports http call and gave the possibility to call controller.
It stands up the Dispatcher Servlet and all required MVC components,
allowing us to test an endpoint in a proper web environment, but
without the overhead of running a server.
3) when you use:
#MockBean private EmployeeService employeeService;
you override real service. remove it from test class real service will be used in testing. Instead of use #Mock use #MockBean. #MockBean it's override by container, with #Mock you need to inject this into controller by reflection
or without spring boot with reflection:
#Before
public void init() {
MockitoAnnotations.initMocks(this);
Mockito.reset(employeeService);
mockMvc = MockMvcBuilders
.webAppContextSetup(webApplicationContext)
.build();
EmployeeRestController employeeRestController=
webAppContext.getBean(EmployeeRestController.class);
ReflectionTestUtils.setField(employeeRestController,
"employeeService",
employeeService);
}
4) Mockito.reset(employeeService);- you reset all behaviors that you setupped before. Mock contains information from when(), verify() and controls it , call reset - it's clean all information.

Spring custom login page only showing in IDE

I am developing a REST-API with Spring Boot. Now I want to act as a OAuth2 provider as well and therefore I want to add support for the "client_credentials" grant type.
In order to do that I have to allow users to login and authorize the client. Spring provides an ugly default login form for doing that so now I want to show my own custom login form instead.
The problem is I can't get it to work outside my IDE.
My configuration looks as follows:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().requireCsrfProtectionMatcher(new AntPathRequestMatcher("**/login")).and().authorizeRequests().antMatchers("/hellopage").hasAuthority(Role.USER.value())
.and().formLogin().defaultSuccessUrl("/hellopage").loginPage("/login").and().logout().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/*.css");
web.ignoring().antMatchers("/*.js");
}
}
#Configuration
protected class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(final ResourceHandlerRegistry registry) {
registry.addResourceHandler("/*.js/**").addResourceLocations("/ui/static/");
registry.addResourceHandler("/*.css/**").addResourceLocations("/ui/static/");
}
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("login");
registry.addViewController("/login").setViewName("login");
registry.addViewController("/testpage").setViewName("testpage");
registry.addViewController("/hellopage").setViewName("hellopage");
}
#Bean
public InternalResourceViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/ui/jsp/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
And my folder structure looks like this:
When I run my application inside Eclipse and visit http://localhost:8080/login everything works fine and my custom login form is shown. When I package my application with maven and execute the generated .war file, visiting http://localhost:8080/login shows the ugly default login form which leads me to believe that spring is unable to find the resources for my custom form.
When I try to access any other .jsp like testpage.jsp, I get the following error (this also works fine when the app is run from my IDE):
I am deploying my application using a docker container that runs the .war file using java -jar myserver.war, so this has to work for me.
How can I make sure Spring can find my provided resources when executing the .war file?
By default Maven expects a the jsp's in /WEB-INF/* location.
You can keep the jsp's in src/main/webapp/WEB-INF/jsp. Also you can update the InternalViewResolver prefix as well accordingly.
For detailed explanation you can refer https://stackoverflow.com/a/19786283/3981536

Spring boot No WebApplicationContext found

I have a simple spring boot app and I'm trying to get it up and running. The config consists of an app context ( applicationContext.xml) XML with a bunch of beans in it. I have a Spring application class:
#SpringBootApplication
#Configuration
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
private static final Logger logger = Logger.getLogger(WebCheckApplication.class);
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(WebCheckApplication.class, args);
if (logger.isDebugEnabled()) {
logger.debug("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
logger.debug(beanName);
}
}
}
}
And I have a #WebListener class that grabs a few beans from the WebContext from within the ServletContext:
#WebListener
public class SystemPropertiesContextInitializer extends SysPropsAlertsFetcher implements ServletContextListener {
private static final Logger logger = Logger.getLogger(SystemPropertiesContextInitializer.class);
#Override
public void contextDestroyed(ServletContextEvent sce) {
//remove the SystemProperties and alert types map object from context
sce.getServletContext().removeAttribute(BaseAuthenticatedController.SYSPROPS_KEY);
sce.getServletContext().removeAttribute(BaseAuthenticatedController.ALERT_TYPES_MAP_KEY);
}
#Override
public void contextInitialized(ServletContextEvent sce) {
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
AlertsDataAccess = (AlertDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("AlertsDataAccess");
fetchObjects(sce.getServletContext());
}
}
When I attempt to start the app, I get the following error:
SEVERE: Exception sending context initialized event to listener instance of class web.SystemPropertiesContextInitializer
java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:83)
at .web.SystemPropertiesContextInitializer.contextInitialized(SystemPropertiesContextInitializer.java:31)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4994)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5492)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
and it occurs at this line:
SysPropsDataAccess = (SystemPropertiesDataAccess) WebApplicationContextUtils.getRequiredWebApplicationContext(sce.getServletContext()).getBean("SystemPropertiesDataAccess");
It looks like Spring isn't creating a WebApplicationContext.
Greater than or equal 1.3.0.RC1 use #ServletComponentScan
#ServletComponentScan // <-- This scans for EJB #WebFilter, #WebListener and #WebServlet
#SpringBootApplication
#ImportResource("classpath:applicationContext.xml")
public class WebCheckApplication {
Less than or equal 1.2.x use #Component to scan for listener
#Component // <-- This allows the component to be found by #ComponentScan inside of #SpringBootApplication
#WebListener
public class MojoSystemPropertiesContextInitializer extends MojoSysPropsAlertsFetcher implements ServletContextListener {
War Deploy extend SpringBootServletInitializer
public class WebCheckApplication extends SpringBootServletInitializer {
In 1.3.0.RC1 #ServletComponentScan was added so simply annotating your main application config should allow these to be picked up. Otherwise adding #Component to your ServletContextListener should work
This link is a discussion on how they currently handle #WebFilter how they decided to handle #WebFilter and they also discuss SpringBootServletInitializer and how this would pick process each item twice if both were to be used. Also links to the commits that implement the new feature.
https://github.com/spring-projects/spring-boot/issues/2290
If you intend to deploy your application as a war file you may also have your main configuration extend SpringBootServletInitializer
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html
All that was needed was to make the Application class extend SpringBootServletInitializer

How to run specific SpringBoot CommandLineRunner runner in my app?

I'm following the Spring Boot CommandLineRunner : filter option argument for creating CommandLineRunner for my SpringBoot application. What I dont understand is how can I run this specific command in ma app? In this specific example there is a FileProcessingCommandLine class with 'run' method implemented. Now how can I run this from command prompt?
a think that cannot be run manually. Spring framework is responsible for running this method!.
You should mark your class with Spring’s #Component annotation so that will automatically picked up by #SpringBootApplication.
If your class implements Spring Boot’s CommandLineRunner it will run after all the beans are created and registered.
#Component
public class FirstCommandLineRunner implements CommandLineRunner {
#Override
public void run(String... strings) throws Exception {
System.out.println("hello world");
}
}

Resources