spring requestmapping testing code doesn't works - java

i am studying spring 5 and i can not use #RequestMapping annotation and don't know why
#RequestMapping includes #Component annotation so I just thought I can use that
initRequest includes URL parameter by string
i just expected initRequest(/hello) parameter binds URL
here is my code
public class SimpleControllerTest extends AbstractDispatcherServletTest {
#Test
public void helloSimpleController() throws ServletException, IOException {
setClasses(HelloController.class);
initRequest("/hello").addParameter("name", "spring");
runService();
assertModel("message", "Hello spring");
assertViewName("/WEB-INF/view/hello.jsp");
}
#Test(expected=Exception.class)
public void noParameterHelloSimpleController() throws ServletException, IOException {
setClasses(HelloController.class);
initRequest("/hello");
runService();
}
#Component("/hello")
//#RequestMapping("/hello")
static class HelloController extends SimpleController {
public HelloController() {
this.setRequiredParams(new String[] {"name"});
this.setViewName("/WEB-INF/view/hello.jsp");
}
public void control(Map<String, String> params, Map<String, Object> model) throws Exception {
model.put("message", "Hello " + params.get("name"));
}
}
static abstract class SimpleController implements Controller {
private String[] requiredParams;
private String viewName;
public void setRequiredParams(String[] requiredParams) {
this.requiredParams = requiredParams;
}
public void setViewName(String viewName) {
this.viewName = viewName;
}
final public ModelAndView handleRequest(HttpServletRequest req,
HttpServletResponse res) throws Exception {
...
}
public abstract void control(Map<String, String> params, Map<String, Object> model) throws Exception;
}
}

You need to work on your Spring basics. Your understanding of which annotations do what is incorrect and incomplete. The following links provide good knowledge on these. Go through these, revise your code, and you will solve this problem without needing help.
Spring Framework Annotations
Spring Annotations - JournalDev

Related

How to code Spring Cloud Function in Azure with multiple endpoints?

I am trying to create 2 Azure Functions with Spring Cloud but I can't make it work.
#Configuration
public class FirstFunction extends AzureSpringBootRequestHandler<Optional<Void>, String>
{
#FunctionName("firstFunction")
public void run(
#HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context)
{
handleRequest(Optional.empty(), context);
}
#Bean
#Lazy
Function<Optional<Void>, String> firstFunction()
{
return context ->
{
// do firstFunction stuff;
};
}
}
#Configuration
public class SecondFunction extends AzureSpringBootRequestHandler<Optional<Void>, String>
{
#FunctionName("secondFunction")
public void run(
#HttpTrigger(name = "req", methods = {HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context)
{
handleRequest(Optional.empty(), context);
}
#Bean
#Lazy
Function<Optional<Void>, String> secondFunction()
{
return context ->
{
// do secondFunction stuff;
};
}
}
#SpringBootApplication
public class Application
{
public static void main(final String[] args)
{
SpringApplication.run(Application.class, args);
}
}
Using the above code with the dependency on spring-cloud-function-dependencies 2.0.1.RELEASE, it always hits the firstFunction Bean when calling both the firstFunction and secondFunction endpoints.
After doing some googling, I found this SO answer that suggests to move to 2.1.
However when I tried changing to 2.1.1.RELEASE, I am getting an exception where it is failing to find a main class:
System.Private.CoreLib: Exception while executing function: Functions.extractContent. System.Private.CoreLib: Result: Failure
Exception: IllegalArgumentException: Failed to locate main class
Stack: java.lang.IllegalStateException: Failed to discover main class. An attempt was made to discover main class as 'MAIN_CLASS' environment variable, system property as well as entry
in META-INF/MANIFEST.MF (in that order).
Need some help on what I am doing wrong.
I tested at my side, and everything was OK.
You may get my demo at: https://github.com/AI-EVO/azuresptingfunction.git . The project is based on the official demo: https://github.com/Azure-Samples/hello-spring-function-azure
My changes:
HelloFunction.java
#SpringBootApplication
public class HelloFunction {
public static void main(String[] args) throws Exception {
SpringApplication.run(HelloFunction.class, args);
}
#Bean("hello")
public Function<User, Greeting> hello() {
return user -> new Greeting("Hello! Welcome, " + user.getName());
}
#Bean("hi")
public Function<User, Greeting> hi() {
return user -> new Greeting("Hi! Welcome, " + user.getName());
}
}
Modify HelloHandler.java
public class HelloHandler extends AzureSpringBootRequestHandler<User, Greeting> {
#FunctionName("hello")
public Greeting execute(
#HttpTrigger(name = "request", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request,
ExecutionContext context) {
context.getLogger().info("Greeting user name: " + request.getBody().get().getName());
return handleRequest(request.getBody().get(), context);
}
}
Add HiHandler.java
public class HiHandler extends AzureSpringBootRequestHandler<User, Greeting> {
#FunctionName("hi")
public Greeting execute(#HttpTrigger(name = "request", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<User>> request,
ExecutionContext context) {
context.getLogger().info("Greeting user name: " + request.getBody().get().getName());
return handleRequest(request.getBody().get(), context);
}
}
Run functions:
mvn azure-functions:run
Test with postman
From function hello:
From function hi:

Spring Boot OncePerRequestFilter shouldNotFilter Junit

I am trying to add junit test case for my Spring Boot OncePerRequestFilter shouldNotFilter method logic. The logic works fine with real-time REST calls but junit case is failing. Any idea?.
Here is test code.
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SpringFilterTest {
#Test
public void getHealthTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/health")).andExpect(status().isOk());
}
#Test
public void getPersonTest() throws Exception {
standaloneSetup(new PersonController()).addFilter(new SkipFilter()).build().perform(get("/person")).andExpect(status().isAccepted());
}
private class SkipFilter extends OncePerRequestFilter {
private Set<String> skipUrls = new HashSet<>(Arrays.asList("/health"));
private AntPathMatcher pathMatcher = new AntPathMatcher();
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(request, response);
response.setStatus(HttpStatus.ACCEPTED.value());
}
#Override
protected boolean shouldNotFilter(HttpServletRequest request) {
return skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
}
}
#RestController
#RequestMapping(value = "/")
private static class PersonController {
#GetMapping("person")
public void getPerson() {
}
#GetMapping("health")
public void getHealth() {
}
}
}
I am expecting both of junit #Test cases to be successful but health one is always failing(its using Filter).
Incase, if you want to replicate below is complete repo code.
https://github.com/imran9m/spring-filter-test
Below Expression evaluates to false with request.getServletPath() when /health
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getServletPath()));
Change to request.getRequestURI() to get the uri and below condition matches the path
skipUrls.stream().anyMatch(p -> pathMatcher.match(p, request.getRequestURI()));

Escape quotes in java spring request body

I have a Java Spring controller.
I want to escape all quotes in my request (sanitize it for using it in SQL queries for example).
Is there a way to do that with Spring ?
Example :
#RequestMapping(method = RequestMethod.POST)
public List<String[]> myEndpoint(#RequestBody Map<String, String> params, #AuthenticationPrincipal Account connectedUser) throws Exception{
return myService.runQuery(params, connectedUser);
}
If you want to validate all your request parameters in controllers, you can use custom validators. For Complete info, check Complete Example
Brief Overview:
Validator Implementation
#Component
public class YourValidator implements Validator {
#Override
public boolean supports(Class<?> clazz) {
return clazz.isAssignableFrom(YourPojoType.class);
}
#Override
public void validate(Object target, Errors errors) {
if (target instanceof YourPojoType) {
YourPojoType req = (YourPojoType) target;
Map<String, String> params = req.getParams();
//Do your validations.
//if any validation failed,
errors.rejectValue("yourFieldName", "YourCustomErrorCode", "YourCustomErrorMessage");
}
}
}
Controller
#RestController
public class YourController{
#Autowired
private YourValidator validator;
#RequestMapping(method = RequestMethod.POST)
public List<String[]> myEndpoint(#Valid YourPojoType req, BindingResult result, #AuthenticationPrincipal Account connectedUser) throws Exception{
if (result.hasErrors()) {
//throw exception
}
return myService.runQuery(params, connectedUser);
}
#InitBinder
private void initBinder(WebDataBinder binder) {
binder.setValidator(validator);
}
}

How to see REST Request/Respons in Spring

Background
Let's say we have a #RestController with the following method (Spring Boot 1.3.5.RELEASE):
#RequestMapping(value = "/helloworld", method = RequestMethod.POST)
public Map<String, String> helloWorld(#RequestBody Map<String, String> m) {
m.put("Hello", "2");
m.put("World", "1");
return m;
}
And a #Test using TestRestTemplate:
RestTemplate restTemplate = new TestRestTemplate();
#Test
public void testHelloWorld() {
Map<String, String> request = new HashMap<>();
request.put("Hello", "1");
request.put("World", "2");
Map<String, String> respons = this.restTemplate.postForObject("/helloworld", request, Map.class);
}
Question
How can one print/log the actual request/respons being sent/received?
I.e how to print/log the serialized versions of the request/respons?
This is availible on the level of request filters:
public class YourCustomFilter implements Filter {
#Override
public void destroy() {
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// your code here
}
#Override
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// your code here
}
}
But, the question is: Would you really like to do this and because of what? Remember, that this is really error prone.
You can use aspect to log request and response
example snippet of request:
#Aspect
#Component
public class InputLoggerAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(InputLoggerAspect.class);
#Autowired
private ObjectMapper objectMapper;
#Before(value = "valueToPointCut")
public void before(JoinPoint pointcut) throws Exception {
Object[] args = pointcut.getArgs();
for (Object object : args) {
LOGGER.info("{}:{}", object.getClass(), objectMapper.writeValueAsString(object));
}
}
}

Spring Boot JPA - paging and sorting

I am trying to implement pagination to my Spring Data JPA repository in Spring Boot but I am stuck with the following exception when running uni tests:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.domain.Pageable]: Specified class is an interface
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
...
Could someone point out to me what am I missing here? This is my repository:
#Repository
public interface VenueRepository extends PagingAndSortingRepository<Venue, Long> {
public Page<Venue> findAll(Pageable pageable);
}
and controller:
#RestController
#RequestMapping("/venues")
public class VenueController {
#Autowired
private VenueRepository venueRepo;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Page<Venue>> getVenues(Pageable pageable) {
return new ResponseEntity<>(venueRepo.findAll(pageable), HttpStatus.OK);
}
}
and finally my test:
#Test
public void responseOkVenuesTest() throws Exception {
mvc.perform(get("/venues").accept(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk());
}
I spent couple of hours trying to make this work and am running out of ideas. Thank you for any tips!
Change your method getVenues in the way that you can pass the parameters to instantiate a PageRequest instead of passing Pageable :
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<List<Venue>> getVenues(int from,int to) {
return new ResponseEntity<>(
venueRepo.findAll((new PageRequest(from, to)), HttpStatus.OK).getContent();
}
In addition to #SEY_91's answer you might also like to use the following solution inspired with How to remove redundant Spring MVC method by providing POST-only #Valid? and used in my Spring Boot-driven application for long time.
In short, here is an annotation to annotate controller method parameters:
#Target(PARAMETER)
#Retention(RUNTIME)
public #interface PlainModelAttribute {
}
Now, just a method processor that would scan for parameters annotated with #PlainModelAttribute:
public final class PlainModelAttributeMethodProcessor
extends ModelAttributeMethodProcessor {
private final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index;
private PlainModelAttributeMethodProcessor(final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index) {
super(true);
this.index = index;
}
public static HandlerMethodArgumentResolver plainModelAttributeMethodProcessor(final Map<TypeToken<?>, Converter<? super NativeWebRequest, ?>> index) {
return new PlainModelAttributeMethodProcessor(index);
}
#Override
public boolean supportsParameter(final MethodParameter parameter) {
return parameter.hasParameterAnnotation(PlainModelAttribute.class) || super.supportsParameter(parameter);
}
#Override
protected Object createAttribute(final String attributeName, final MethodParameter parameter, final WebDataBinderFactory binderFactory,
final NativeWebRequest request) {
final TypeToken<?> typeToken = TypeToken.of(parameter.getGenericParameterType());
final Converter<? super NativeWebRequest, ?> converter = index.get(typeToken);
if ( converter == null ) {
throw new IllegalArgumentException("Cannot find a converter for " + typeToken.getType());
}
return converter.convert(request);
}
#Override
protected void bindRequestParameters(final WebDataBinder binder, final NativeWebRequest request) {
final HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
if ( !isSafe(resolve(servletRequest.getMethod())) ) {
((ServletRequestDataBinder) binder).bind(servletRequest);
}
}
private static HttpMethod resolve(final String name) {
return HttpMethod.valueOf(name.toUpperCase());
}
private static boolean isSafe(final HttpMethod method)
throws UnsupportedOperationException {
switch ( method ) {
case GET:
case HEAD:
case OPTIONS:
return true;
case POST:
case PUT:
case PATCH:
case DELETE:
return false;
case TRACE:
throw new UnsupportedOperationException();
default:
throw new AssertionError(method);
}
}
}
I don't really remember, but a resolve() method equivalent should be present in Spring Framework somewhere. Note that I use Google Guava TypeToken in order to let the processor be compatible with generic types (since I use models like IQuery<Foo> and IQuery<Bar> in controllers). Now just register the processor:
#Configuration
#EnableWebMvc
public class MvcConfiguration
extends WebMvcConfigurerAdapter {
#Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(createModelAttributeMethodProcessor());
}
private static HandlerMethodArgumentResolver createModelAttributeMethodProcessor() {
return plainModelAttributeMethodProcessor(ImmutableMap.of(pageableTypeToken, MvcConfiguration::toPageable));
}
private static final TypeToken<Pageable> pageableTypeToken = new TypeToken<Pageable>() {
};
private static Pageable toPageable(final WebRequest request) {
return new PageRequest(
ofNullable(request.getParameter("page")).map(Integer::parseInt).orElse(0),
ofNullable(request.getParameter("size")).map(Integer::parseInt).orElse(1)
);
}
}
Here is a web request to a Pageable DTO conversion, and the converter must be registered as an argument resolver. So now it's ready to use:
#RestController
#RequestMapping("/")
public class Controller {
#RequestMapping(method = GET)
public String get(#PlainModelAttribute final Pageable pageable) {
return toStringHelper(pageable)
.add("offset", pageable.getOffset())
.add("pageNumber", pageable.getPageNumber())
.add("pageSize", pageable.getPageSize())
.add("sort", pageable.getSort())
.toString();
}
}
A few examples:
/ ⇒ PageRequest{offset=0, pageNumber=0, pageSize=1, sort=null}
/?page=43 ⇒ PageRequest{offset=43, pageNumber=43, pageSize=1, sort=null}
/?size=32 ⇒ PageRequest{offset=0, pageNumber=0, pageSize=32, sort=null}
/?page=22&size=32 ⇒ PageRequest{offset=704, pageNumber=22, pageSize=32, sort=null}

Categories