Not able to resolve PUT and POST issue with spring boot - rest

I am building an application with spring boot with REST my GET method is working but POST and PUT method is not working giving exception :
2015-05-28 16:30:09.498 DEBUG 22670 --- [qtp536775614-18] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /api/v1/user
2015-05-28 16:30:09.500 DEBUG 22670 --- [qtp536775614-18] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PUT' not supported
2015-05-28 16:30:09.500 DEBUG 22670 --- [qtp536775614-18] .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PUT' not supported
2015-05-28 16:30:09.500 DEBUG 22670 --- [qtp536775614-18] .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'PUT' not supported
2015-05-28 16:30:09.501 WARN 22670 --- [qtp536775614-18] o.s.web.servlet.PageNotFound : Request method 'PUT' not supported
2015-05-28 16:30:09.501 DEBUG 22670 --- [qtp536775614-18] o.s.web.servlet.DispatcherServlet : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2015-05-28 16:30:09.502 DEBUG 22670 --- [qtp536775614-18] o.s.web.servlet.DispatcherServlet : Successfully completed request
I searched a lot for this issue but not found satisfactorily solution.
My controller code is :
package com.samepinch.controllers;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.samepinch.services.UserService;
import com.samepinch.utills.response.ResponseHandler;
#RestController
#RequestMapping("/api/v1")
public class UserController {
public static Logger log = LoggerFactory.getLogger(UserController.class);
#Autowired
UserService userService;
/**
* to pass user info to service
*/
/*#RequestMapping(value = "/signup",method = RequestMethod.POST)
public Map<String, Object> saveUser(#RequestBody User user) {
successfully", HttpStatus.ACCEPTED, false, null);
}*/
/**
* to delete user by id
*/
#RequestMapping(value = "/user", method = RequestMethod.DELETE)
public void deleteUser(#PathVariable("id") String id) {
userService.deleteUser(id);
}
/**
* to update user by id
*/
#RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser() {
System.out.println("in update method");
// userService.updateUser(user);
return "success";
}
#RequestMapping(value = "/user" , method = RequestMethod.GET)
public Map<String,Object> getUsers(){
log.info("getting user");
return ResponseHandler.generateResponse("", HttpStatus.ACCEPTED, false, null);
}
} userService.saveUser(user);
return ResponseHandler.generateResponse("User registerted successfully", HttpStatus.ACCEPTED, false, null);
}*/
/**
* to delete user by id
*/
#RequestMapping(value = "/user", method = RequestMethod.DELETE)
public void deleteUser(#PathVariable("id") String id) {
userService.deleteUser(id);
}
/**
* to update user by id
*/
#RequestMapping(value = "/user", method = RequestMethod.PUT)
public String updateUser() {
System.out.println("in update method");
// userService.updateUser(user);
return "success";
}
#RequestMapping(value = "/user" , method = RequestMethod.GET)
public Map<String,Object> getUsers(){
log.info("getting user");
return ResponseHandler.generateResponse("", HttpStatus.ACCEPTED, false, null);
}
}

Related

Spring Boot Controller Test with Mock Service doesn't use the mock service

I have a simple RestController with a Service and want to test just the controller by providing a mock implementation for the Service.
However, I'm getting an empty response in resultActions = mockMvc.perform(get("/user")); object when I'm running the test.
Here is my code:
Controller
#RestController
public class UserController {
#Autowired
UserService userService;
#GetMapping("/user")
public ResponseEntity<List<String>> getUsers(){
return ResponseEntity.ok().body(userService.getUsers());
}
}
Contoller Test
#RunWith(SpringRunner.class)
#WebMvcTest(UserController.class)
public class UserControllerTest {
#MockBean
UserService userService;
private final Logger log = LoggerFactory.getLogger(UserControllerTest.class);
#Autowired
MockMvc mockMvc;
#Before
public void init(){
List<String> usrs = new ArrayList<>();
usrs.add("JUNIT-USER");
userService = Mockito.mock(UserService.class);
when(userService.getUsers()).thenReturn(usrs);
}
#Test
public void test1() throws Exception {
ResultActions resultActions = mockMvc.perform(get("/user"));
resultActions.andDo(mvcResult -> {
log.info(mvcResult.getResponse().getContentType());
log.info(mvcResult.getResponse().getContentAsString());
log.info(String.valueOf(mvcResult.getResponse().getContentLength()));
});
resultActions
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content().json("[\"JUNIT-USER\"]"));
}
}
The output of the log statements in the test is as follows:
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : application/json
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : []
2021-02-24 15:23:16.161 INFO 22197 --- [ main] com.vi.learn.UserControllerTest : 0
The test hence fails with the below assertionError:
java.lang.AssertionError: []: Expected 2 values but got 0
What am I doing wrong here?
Two existing methods
Using the mock () method
Using the #MockBean annotation
#MockBean
UserService userService;
or
userService = Mockito.mock(UserService.class);
You have to choose one of them so simply use #MockBean :
#Before
public void init(){
List<String> usrs = new ArrayList<>();
usrs.add("JUNIT-USER");
when(userService.getUsers()).thenReturn(usrs);
}

beanManager.fireEvent doesn't fire with OmniFaces 3.1

***** UPDATED *****
I have the following method in a Stateless Session Bean, deployed in an EAR on JBoss WildFly 12.0.0.Final which is called when the database is updated.
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
#Inject
private BeanManager beanManager;
public void onFoodsCosmeticsMedicinesChange(FoodsCosmeticsMedicines foodsCosmeticsMedicines) {
logger.info(">>>>> onFoodsCosmeticsMedicinesChange beanManager = {}", beanManager);
logger.info(">>>>> onFoodsCosmeticsMedicinesChange getBrand = {}", foodsCosmeticsMedicines.getBrand());
beanManager.fireEvent(new PushEvent(foodsCosmeticsMedicines.getBrand()));
}
PushBean is a POJO, contained in the WAR:
import org.omnifaces.cdi.Push;
import org.omnifaces.cdi.PushContext;
import javax.inject.Inject;
#Named
#ApplicationScoped
public class PushBean {
/**
*
*/
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
*
*/
#Inject
#Push(channel = "testChannel")
private PushContext testChannel;
/**
*
*/
public PushBean() {
}
/**
*
* #param pushEvent PushEvent
*/
public void onPush(#Observes PushEvent pushEvent) {
logger.info("***** onPersist pushEvent getMessage = {}", pushEvent.getMessage());
logger.info("***** pushContext = {}", testChannel);
testChannel.send(pushEvent.getMessage());
}
}
PushEvent:
public final class PushEvent {
private final String message;
public PushEvent(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
The OmniFaces 3.1 JAR is only in the WAR.
When the method 'onFoodsCosmeticsMedicinesChange' is called the console log shows:
INFO [com.notifywell.ejb.FoodsCosmeticsMedicinesEJB] (default task-4)
onFoodsCosmeticsMedicinesChange beanManager = Weld BeanManager for
NOTiFYwell.ear/NOTiFYwellJAR.jar/ [bean count=38]
INFO[com.notifywell.ejb.FoodsCosmeticsMedicinesEJB] (default task-4)
onFoodsCosmeticsMedicinesChange getBrand = BONNE MAMAN
But the following statement:
beanManager.fireEvent(new PushEvent(foodsCosmeticsMedicines.getBrand()));
Doesn't appear to be executed as I do not see the PushBean method 'onPersist' in PushBean being executed:
public void onPush(#Observes PushEvent pushEvent) {
Deployed on WildFly 12.0.0.Final on MacOS using EE8.
Any idea what I'm doing wrong?
The above code works. 'Schoolboy error', I had a typo in my build and the 'PushBean.class' was being put in the wrong place in my WAR.
It should have been in:
WEB-INF/classes/PushBean.class
I now see my event being fired in the 'onPush' method of PushBean:
13:18:30,598 INFO [com.notifywell.push.PushBean] (default task-1)
***** onPush pushEvent getMessage = BONNE MAMAN

Spring Boot Rest : Error 404 not found when posting JSON via Postman

I am trying to invoke a POST service via Postman. My application is running on embedded tomcat server. However when I try to invoke the service, the error I get is "No mapping found for HTTP request with URI [/findrouting] in DispatcherServlet with name 'dispatcherServlet'"
It is not even recognizing http:localhost:8080/
RoutingRequest and RoutingResponse are the POJOs with getters and setters.
Am I missing something here. I did check lots of examples but didn't find any solution to my problem.
Please see my code below :
package com.ab.hello.ambassador.server;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.ApplicationContext;
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(AmbassadorApplication.class, args);
System.out.println("List of Beans instantiated");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
}
}
package com.ab.hello.ambassador.server.controller;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.dp.connect.ambassador.server.RoutingRequest;
import com.dp.connect.ambassador.server.RoutingResponse;
#RestController
public class ApplicationController {
#RequestMapping("/")
public String index() {
return "Spring Boot POC Welcomes You!";
}
#RequestMapping(method = POST, value = "/findrouting", consumes = { APPLICATION_JSON_VALUE }, produces = {
APPLICATION_JSON_VALUE })
public RoutingResponse findRoute(#RequestBody RoutingRequest request) throws Exception {
// some business logic that would return response; as of now I have set it to null
RoutingResponse response = null;
return response;
}
}
Thanks for your time. After struggling for quite a long time. I figured out this piece of code. Added annotation #EnableWebMvc. This solved my problem.
#SpringBootApplication
#EnableWebMvc
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Try to define the path in your controller:
#RestController
#RequestMapping("/")
public class ApplicationController {
#RequestMapping
public String index() {
return "Spring Boot POC Welcomes You!";
}
#RequestMapping(method = POST, value = "/findrouting", consumes = { APPLICATION_JSON_VALUE }, produces = {
APPLICATION_JSON_VALUE })
public RoutingResponse findRoute(#RequestBody RoutingRequest request) throws Exception {
// some business logic that would return response; as of now I have set it to null
RoutingResponse response = null;
return response;
}
}
Change the below line
ApplicationContext ctx = SpringApplication.run(AmbassadorApplication.class, args);
with
ApplicationContext ctx = SpringApplication.run(Application.class, args);
according to spring docs , seems need to Override a config method:
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}

How to get oAuth2 access token when user call signup rest API in springboot?

currently I am working on Springboot security, its quite new for me. I followed youtube video tutorial Video
I am getting oauth2 access_token successfully when I use bellow code snippet:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, UserRepository repository, UserService service) throws Exception {
//Setup a default user if db is empty
User students = new User("stu1", "user", "user", "abc#gmail.com", "1234567890", "12th", "dwarka sec-12",
0, 0 , "may/29/2017", "", Arrays.asList(new Role("USER"), new Role("ACTUATOR")));
if (repository.count()==0){
service.save(students);
}
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
}
And Controller Class is:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/mathify/signup")
public User register(#RequestBody User user){
return userService.doSignup(user);
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
With above code snippet I can get access_token(/oauth/token), and I can also call other controller class private APIs without any issue.
but there is a problem with above code. What? In above code snippet User is hard coded, but when I want to get access_token at the time of user signup it's giving an exception.
2017-06-18 11:04:05.689 ERROR 8492 --- [nio-8080-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object] with root cause
java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer#6b66d7ac to already built object
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:196) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:133) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.apply(AuthenticationManagerBuilder.java:290) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.userDetailsService(AuthenticationManagerBuilder.java:187) ~[spring-security-config-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at com.techiesandeep.mathify.controller.LoginController.register(LoginController.java:40) ~[classes/:na]
for achieving above described feature I did some changes in my Application and Controller
Application Class is As:-
#SpringBootApplication
public class MathifyApplication {
#Autowired
private PasswordEncoder passwordEncoder;
public static void main(String[] args) {
SpringApplication.run(MathifyApplication.class, args);
}
}
and Controller class is as:-
#RestController
public class LoginController {
#Autowired
private UserService userService;
#Autowired
AuthenticationManagerBuilder builder;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private UserRepository repository;
#RequestMapping(value = "/mathify/getuser/{userId}", method = RequestMethod.GET)
public User getUser(#PathVariable String userId){
System.out.println("Userid "+userId);
return userService.getUser(userId);
}
#RequestMapping(method = RequestMethod.POST, value="/user/signup")
public User register(#RequestBody User user) throws Exception {
User u = userService.doSignup(user);
builder.userDetailsService(userDetailsService(repository)).passwordEncoder(passwordEncoder);
return u;
}
private UserDetailsService userDetailsService(final UserRepository repository) {
return userName -> new CustomUserDetails(repository.findByUsername(userName));
}
#GetMapping(value="/hi")
public String test(){
return "Oh ! I am fine without secuirity";
}
}
Any help would be appreciable.thanks
You can call another POST request to get access token.
I am not sure it's the best way, but worked fine with me.
Example code snip inside Signup Request mapping:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", auth_header);
/*auth_header should be Autorization header value that captured from signup request, which is generated by Basic Auth with clientID and secret, for example, "Basic bXktdHJ1c3RlZC1jbGllbnQ6c2VjcmV0" */
HttpEntity<String> entity = new HttpEntity<String>("",headers);
String authURL = "http://localhost:8080/oauth/token?grant_type=password&username=yourusername&password=yourpassword";
ResponseEntity<String> response = restTemplate.postForEntity(authURL, entity, String.class);
System.out.println(response.getBody());

Spring restful service test case fail HTTP status is 500

I want to implement test case for spring restful web services which return a json
MY controller test class is :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {WebAppContext.class,JpaTestConfiguration.class
})
#WebAppConfiguration
public class DominProfileRestControllerTest {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
private MediaType contentType = new MediaType(MediaType.APPLICATION_JSON.getType(),
MediaType.APPLICATION_JSON.getSubtype(),
Charset.forName("utf8"));
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testGetDomainProfile() throws Exception {
String profileId = domainProfile.getId().toString();
System.out.print("testing restful"+profileId);
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andExpect(jsonPath("$.city", is("Chandigrah")));
/* mockMvc.perform(get("/service/domainprofile/get/{id}",profileId).accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk())
.andExpect(content().contentType("text/plain;charset=ISO-8859-1"))
.andExpect(content().string("hello Prashant"));
*/
}
My Controller class Is :
#RestController
#RequestMapping("/service/domainprofile")
public class DominProfileRestController {
#Autowired
private JpaDomainProfileRepository jpaDomainProfileRepository;
#RequestMapping(value = "/get/{id}", method = RequestMethod.GET)
public DomainProfileResource getDomainProfile(#PathVariable String id) {
JpaDomainProfile domainProfile = jpaDomainProfileRepository.findOne(Long.valueOf(id));
DomainProfileResource domainProfileResource = new DomainProfileResource();
System.out.println("domainProfile.getCity()*************" + domainProfile.getCity());
System.out.println("domainProfile.getAddress()*************" + domainProfile.getAddress());
domainProfileResource.setCity(domainProfile.getCity());
domainProfileResource.setAddress(domainProfile.getAddress());
// return new ResponseEntity<DomainProfileResource>(domainProfileResource, HttpStatus.OK);
return domainProfileResource;
// return domainProfile;
}
}
When I run test case I got An error while we got values in domainprofile.city and domainprofile.address.
Error Is :
java.lang.AssertionError: Status
Expected :200
Actual :500
It Is Working Fine When I return a plain text
can you do this
mockMvc.perform(get("/service/domainprofile/get/{id}", profileId) )
.andDo(print());
this will print the full response with exception , now if you see HttpMessageNotWritableException which was the issue I was facing , you should try to serialize your object using jackson and see if it works (spring internally uses Jackson ). For example , If any of your fields are null the Serialization will fail.