How to register a servlet in Ktor? - servlets

I'm looking for a way to register a javax.servlet.http.HttpServlet in ktor, but can't find any.
Do I need to install a feature? Register it in Routing? Can I enable scanning of #WebServlet annotations?
Example servlet:
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
#WebServlet("/foo")
public class MyServlet extends HttpServlet {
#Override
protected void doGet(final HttpServletRequest req, final HttpServletResponse resp) {
// ...
}
}

What you want is currently not supported by design. See my Feature Request and corresponding PR to add support for it.

Related

Spring MockMvc doesn't contain cookies

I have a controller protected with HTTP Basic authentication.
I setup the app to use session cookies and it works.
However when I test the controller using MockMvc, a successful authentication does not give me any cookie.
Web configuration:
package world.pyb.spring.cookiesdemo;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("argentina").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
//#formatter:off
http.httpBasic()
.and().authorizeRequests().antMatchers(HttpMethod.GET, "/hello").authenticated()
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.ALWAYS);
//#formatter:on
}
}
Simple controller:
package world.pyb.spring.cookiesdemo;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class HelloController {
#RequestMapping("/hello")
public String index() {
return "Greetings from Spring Boot!";
}
}
Simple controller test that doesn't give me the session cookie:
package world.pyb.spring.cookiesdemo;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class HelloControllerTest {
#Autowired
private MockMvc mvc;
#Test
public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/hello")
.with(SecurityMockMvcRequestPostProcessors.httpBasic("admin", "argentina"))
)
// prints "Cookies = []"
.andDo(MockMvcResultHandlers.print())
.andExpect(cookie().exists("JSESSIONID"))
.andExpect(status().is2xxSuccessful())
.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
}
}
Related questions:
Why does Spring MockMvc result not contain a cookie?
Unit Testing /login in Spring MVC using MockMvc
Spring MVC testing (security Integration test), JSESSIONID is not present
Some answers suggest not to use MockMvc but I'd like to keep using it if possible.
As shown in the question's code, MockMvcResultMatcher includes support for cookies.
This will work fine, as long as the controller under test itself delivers the cookie. The problem here is that the cookie is delivered by Spring Security, which is a wrapper around your controller. MockMvc is testing your controller directly, and not testing your controller running in its real HTTP server, as would be required to test the security-layer cookies.
That's why TestRestTemplate, which invokes your controller in its full server context, delivers a more thorough test environment.
Notice however that as of Spring 5, the newer approach to running-server API testing is based on WebTestClient.

Spring 4 mvc I always get Request method 'POST' not supported

My issue is that I get always Request method 'POST' not supported !
I'm trying to test my rest web webservice. Here is the WS :
#RequestMapping(value = "/addGouvernorate", method = RequestMethod.POST, produces = { "application/json" })
public ResponseEntity<Gouvernorate> addGouvernorateee(#RequestBody Gouvernorate gouvernorate) throws IOException {
gouvernorateService.addGouvernorat(gouvernorate);
return new ResponseEntity<Gouvernorate>(gouvernorate, HttpStatus.OK);
}
i'm trying to call it with jsoup as follows :
package test.sofiane.rqs;
import java.io.IOException;
import org.jsoup.Connection.Method;
import org.jsoup.Connection.Response;
import org.jsoup.Jsoup;
import org.springframework.security.crypto.codec.Base64;
public class Test {
public static void main(String[] args) throws IOException {
String base64login = new String(Base64.encode("sof:1".getBytes()));
Response docs = Jsoup.connect("http://localhost:8080/site/data/addGouvernorate")
.data("name", "name")
.data("delegation", "delegation")
.data("district", "district")
.data("postalCode", "postalCode")
.method(Method.POST)
.execute();
}
}
I get the exception :
Exception in thread "main" org.jsoup.HttpStatusException: HTTP error fetching URL. Status=405, URL=http://localhost:8080/mintad/data/addGouvernorate
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:459)
at org.jsoup.helper.HttpConnection$Response.execute(HttpConnection.java:434)
at org.jsoup.helper.HttpConnection.execute(HttpConnection.java:181)
at test.sofiane.rqs.Test.main(Test.java:21)
And with Postman application I get
Etat HTTP 405 - Request method 'POST' not supported
I'm using spring security also.
as follow
package com.site.spring.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
/**
* #author Sofiane
*/
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests()
.antMatchers("/", "/home").permitAll()
//.antMatchers("/admin/**").denyAll()//.access("hasRole('ADMIN')")
.and().formLogin().loginPage("/login")
.defaultSuccessUrl("/welcome").usernameParameter("username").passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/404");
// #formatter:off
}
}
A guess : it can be the csrftoken which I have to send since I'm behind spring security but how to generate it ?
Please help because it's driving me insane guys

Using HttpServlet request and response objects with Spring MVC 3

I have seen everywhere in the Spring MVC examples on net that we can use HttpServlet request & response objects in the method parameter in the controller. But when I am using it. Given in the below code.
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
#Controller
public class StudentController {
public void testSyntax(HttpServletRequest request, HttpServletResponse response)
{
System.out.println("Inside testSyntax");
}
}
The compiler is throwing an error. HttpServletRequest request cannot be resolved to a type.
I am using Spring MVC 3.0. Can anyone tell me the reason for it.
You are missing a couple of import statements.
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
Where you get these classes from typically is different per application container you use. My favorite example is Tomcat:
<tomcat_base_dir>/lib/servlet-api.jar

simple Servlet CDI generating NullPointerException

I am working on sample application called bookstore where I have used Dependency Injection. Very simple application. I am using JavaEE 6, GlassFish 3.1.2, Static data in a class (no db), Eclipse Juno.
I can provide more info if needed.
Error I get:
WARNING: StandardWrapperValve[com.bookstore.web.BookListServlet]: PWC1406: Servlet.service() for servlet com.bookstore.web.BookListServlet threw exception
java.lang.NullPointerException
at com.bookstore.web.BookListServlet.doGet(BookListServlet.java:29)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
This I know is Dependency is not injected. Class instance is not created to use it. If I remove #Inject and created an instance of a class than the page is loading fine.
Servlet code generating error: See bold comments
package com.bookstore.web;
import java.io.IOException;
import javax.inject.Inject;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.bookstore.BookRepositoryImp;
#WebServlet("/book/")
public class BookListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
#Inject
private BookRepositoryImp bookRepo;
public BookListServlet() {
super();
}
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException,
IOException {
**//bookRepo = new BookRepositoryImp(); If uncommect this code and remove #Inject than page working fine**
req.setAttribute("books", bookRepo.listBooks());
String path = "/WEB-INF/pages/book-list.jsp";
getServletContext().getRequestDispatcher(path).forward(req, res);
}
protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException,
IOException {
}
}
Project structure:
Have you tried moving your beans.xml file into the WEB-INF folder where your web.xml lives, maybe for some reason your beans.xml file is not copied properly to the resulting war file.

ServletContainerInitializer vs ServletContextListener

I'm trying to register a servlet using servletContainerInitializer but it doesn't seem to work, Maybe it's my code (kindly review it), but I came to wonder about the difference between ServletContainerInitializer and ServletContextListener, because the follwing code runs fine when used as ServletContextListener instead.
From servlet 3.0 specification:
4.4
Configuration methods (adding servlets dynamically):
... or from the onStartup method of a ServletContainerInitializer implementation ...
The ServletContainerInitializer:
package com.marmoush.javaexamples.nullhaus.servlet;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class MyInit implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
System.out.println("hello");
ServletRegistration reg = ctx.addServlet("q31","com.marmoush.javaexamples.nullhaus.servlet.Q31");
reg.addMapping("/q31/*");
}
}
The servlet which I'm trying to auto-register:
package com.marmoush.javaexamples.nullhaus.servlet;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Q31 extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("hello world");
}
}
Original code from nullhaus java examples website "only class name edited" also didn't work!
package com.marmoush.javaexamples.nullhaus.servlet;
import java.util.Set;
import javax.servlet.Servlet;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
public class MyInit implements ServletContainerInitializer {
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
try {
Class klass = Class.forName("com.marmoush.javaexamples.nullhaus.servlet.Q31");
Class<Q31> clazz = (Class<Q31>) klass;
Servlet s = ctx.createServlet(clazz);
ServletRegistration.Dynamic d = ctx.addServlet("q31", s);
d.addMapping("/baz/*");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
The ServletContainerInitializer implementation is intented to be bundled in a JAR file which is in turn been dropped in /WEB-INF/lib of the webapp. The JAR file itself should have a /META-INF/services/javax.servlet.ServletContainerInitializer file containing the FQN of the ServletContainerInitializer implementation in the JAR. Please note that this file should thus not be placed in the webapp itself!
This allows webapp module developers to let their JAR file hook on webapp's startup and shutdown cycle. It's true that they could also have used a ServletContextListener with #WebListener for this, but this won't work if the webapp's own web.xml file has a metadata-complete="true" attribute set in <web-app> which means that the webapp shouldn't scan JARs for annotations (which saves startup time).
That the ServletContainerInitializer doesn't work in your particular case can only mean that you're actually not developing a module JAR file, but just a part integral to your own web application. In that case, the ServletContainerInitializer is useless for you and you should be using ServletContextListener instead.
#WebListener
public class Config implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent event) {
// Do stuff during server startup.
}
#Override
public void contextDestroyed(ServletContextEvent event) {
// Do stuff during server shutdown.
}
}
See also:
Map servlet programmatically instead of using web.xml or annotations
Splitting up shared code and web.xml from WAR project to common JAR project
Using special auto start servlet to initialize on startup and share application data
what is the equivalence of contextDestroyed() in ServletContainerInitializer?
Check if you have configured the ServletContainerInitializer propertly. The ServletContainerInitializer class name should be configured inside a file:
META-INF/services/javax.servlet.ServletContainerInitializer
The file should contain just the class name. For Ex in your case it should look like:
com.marmoush.javaexamples.nullhaus.servlet.MyInit
The file (META-INF/services/javax.servlet.ServletContainerInitializer) can be bundled in a library JAR in WEB-INF/lib.
Here is any example which explains.

Resources