Getting 404 not found when hitting spring boot end point - spring

When trying to hit the rest api end point of spring boot application I get 404 not found, below is the project structure snapshot attached
This is my project structure
Controller -
#RestController
#RequestMapping("/users")
public class UserRestController {
private final UserService userService;
public UserRestController(UserService userService){
this.userService = userService;
}
#RequestMapping(value = "/create", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
public void createUser(#RequestBody final UserDTO user){
userService.saveUser(user);
}
}

You are not scanning your controllers.
In the image you shared #ComponentScan only scans Service folder. But your controllers are in RestController folder.
Use #ComponentScan without any arguments. By default it will scan for beans in current folder and its sub folder.
e.g #ComponentScan()

#SpringBootApplication covers #EnableAutoConfiguration, #ComponentScan, #Configuration.
#RequestMapping(value = "/create", method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
and for this, you can simply do
#PostMapping(value ="/create"
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
Lets test it in postman, it should be POST and url must be
localhost:<your port>/users/create. Dont forget to add your UserDTO in your Postman Body.
In case you missing it, your application must be up and running.

imporatant Please check your HTTP method type when call end point form postman.it must be "post"
Bro if you are using Spring boot. then no need to write #EnableAutoConfiguration, #ComponentScan, #Configuration.
#SpringBootApplication Covers all these.
You just check your url it should be like http://localhost:8080/users/create
used autowired
#autowired
private final UserService userService;

Related

Spring Secured Rest Controller is not found in WebMVCTest

When using #Secured on a REST-Controller, implementing an interface, the Controller is not found in a #WebMvcTest. Either removing the #Secured annotation or removing the implements on the class will make it run in the test.
#Controller
#RequestMapping(path="/failing")
public class FailingTestController implements MyPasswordApi {
#RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE, path = "/test")
#Secured("ROLE_USER")
public ResponseEntity<GetEntity> getMethod()
and
#Controller
#RequestMapping(path = "/running")
public class RunningTestController {
#RequestMapping(method = GET, produces = MediaType.APPLICATION_JSON_VALUE, path = "/test")
#Secured("ROLE_USER")
public ResponseEntity<GetEntity> getMethod() {
are both used in different jUnit-5 Tests. The "RunningTest" will succeed (i.e. the GET-Request will have status 200), whereas the "FailingTest" will end up with a status 404. Using the injected RequestMapppingHanderMapping one can see, that the controller with the inheritance is not bound.
In fact, in the application, both controllers are found.
My question is, how to test an controller implementing security and an interface.
A testcase is found on github: https://github.com/sanddorn/Spring-Boot-Security-Rest-Showcase
The real answer could only be found in the github-repo (see question). The root problem was to annotate the application class with #SpringBootApplication and #EnableGlobalMethodSecurity like
#SpringBootApplication
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class TestApplication {
public static void main(String []argv) {
SpringApplication.run(TestApplication.class);
}
}
Using a different configuration class like
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class TestConfiguration {
}
and removing all extra annotation to the application-class solves the problem.
You are using wrong annotation, replace Controller to RestController
#RestController
#RequestMapping(path = "/running")
public class RunningTestController {
}

calling a method by class level annotated with #RequestMapping that includes an autowired class

I am trying to call a method that is annotated with #RequestMapping(signIn) through a class level (from method: authentication) like so:
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request)
{
UserController user = new UserController();
return user.signIn(request, null);
}
and my controller looks like:
#Autowired
private UserManager userManager;
#RequestMapping(value = /signin, method = RequestMethod.POST)
public #ResponseBody Response signIn(HttpServletRequest request) {
JsonObject json = Misc.parseJson(request);
String lang = Misc.getLang(request);
user.setEmail(Misc.getEmail(json));
user.setPassword(Misc.getEncryptedPassword(json));
return ResponseUtils.success(userManager.auth(user, lang));
}
user manager is annotated with #component:
#Component
public class UserManager {
public User auth(User user, String lang) {
....
return user;
}
}
Problem is when I call the method "signIn" and just new-up a UserController instance through "/authenticate" mapping, the UserManager becomes NULL. So now I'm assuming that autowiring doesn't work when it's done this way.
Is there any other way to call the signIn method? I would hate to copy paste an already existing code to another class just to get this to work...
Autowiering only works in spring managed bean. If you create a class with new keyword, it is not a spring managed bean and autowiering would not work.
You can try to autowire the class which contains the method which is annotated or better put the code in a service class which can be used by both methods.
It's not problem with #Autowired .There are two type of Annotation
firstly method base annotation and field level annotation. You just used field level annotation.Check your import class with "org.springframework.beans.factory.annotation.Autowired" or it can be problem with initiation of "UserManager"
I don't know why you not moving logic into separate Service classs, but try this:
UserController.java
public UserController(UserManager userManager) {
this.userManager = userManager;
}
and then inside controller where authentication resource method is located:
#Autowired UserManager userManager;
#RequestMapping(value = /authenticate, method = RequestMethod.POST)
public #ResponseBody Response authentication(HttpServletRequest request) {
UserController user = new UserController(userManager);
return user.signIn(request);
}
So in the end I just separated the logic instead. Though one solution that I tried and I could have used was to just add another mapping to the signIn method instead of adding a new method in the other class since the logic was similar. Still I opted for a separate logic instead since there were a lot of unnecessary code in the signIn method for my purpose.

Spring controllers not being found

I am trying to create a RESTful service using spring web reactive. I have a controller that has the usual structure
package com.hcl.bc4sc.server.controller;
...
#RestController
#RequestMapping("/api/v1/registrar/enroll")
public class ControllerV1RegistrarEnroll {
...
#RequestMapping(method = RequestMethod.POST, consumes = "application/json")
public Mono<ResponseEntity> registrarEnrollPost(#RequestBody final UserInfo userInfo) {
...
I am using #ComponentScan to get the controller registered like this
#Configuration
#ComponentScan(basePackages = "com.hcl.bc4sc.server.controller")
public class ServerInitialization {
...
The various beans in my ServerInitialization class are being defined, so I know that ServerInitialization is being processed by Spring.
I am wondering if the problem might be with the way I am starting Spring and the HttpServer like this:
public static void boot() throws TimeoutException {
final GenericApplicationContext context
= new AnnotationConfigApplicationContext(DelegatingWebReactiveConfiguration.class,
ServerInitialization.class);
final HttpHandler handler = DispatcherHandler.toHttpHandler(context);
final ServerConfig config = context.getBean(ServerConfig.class);
applicationContext = Optional.of(context);
// Reactor Netty
final Function<HttpChannel, Mono<Void>> adapter
= new ReactorHttpHandlerAdapter(handler);
final HttpServer server = HttpServer.create(config.getHost(), config.getPort());
httpServer = Optional.of(server);
server.ws("", adapter).startAndAwait();
}
When I try to test this I use the url http://localhost/api/v1/registrar/enroll. It returns a 404.
If I should be starting my service differently, could somebody please point me at a good complete working example?
As per the code you mentioned in question, your controller is in
com.hcl.bc4sc.server.config
But the scan you are doing is for package:
com.hcl.bc4sc.server.controller
You should first fix this ambiguity. And let know of if it still fails. Startup Logs would help.

Spring Boot - Test for controller fails with 404 code

I want to write a test for controller. Here is test snippet:
#RunWith(SpringRunner.class)
#WebMvcTest(WeatherStationController.class)
#ContextConfiguration(classes = MockConfig.class)
public class WeatherStationControllerTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private IStationRepository stationRepository;
#Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
controller code snippet:
#RestController
#RequestMapping(value = "stations")
public class WeatherStationController {
#Autowired
private WeatherStationService weatherService;
#RequestMapping(method = RequestMethod.GET)
public List<WeatherStation> getAllWeatherStations() {
return weatherService.getAllStations();
}
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public WeatherStation getWeatherStation(#PathVariable String id) {
return weatherService.getStation(id);
}
MockConfig class:
#Configuration
#ComponentScan(basePackages = "edu.lelyak.repository")
public class MockConfig {
//**************************** MOCK BEANS ******************************
#Bean
#Primary
public WeatherStationService weatherServiceMock() {
WeatherStationService mock = Mockito.mock(WeatherStationService.class);
return mock;
}
Here is error stack trace:
java.lang.AssertionError: Status
Expected :200
Actual :404
I can get what is wrong here.
How to fix test for controller?
HTTP code 404, means no resource found (on the server) for your request, which I think that your controller is not visible(let me say is not scanned) by spring boot.
A simple solution is scanning a parent package in MockConfig class, so spring can pick up all beans,
#ComponentScan(basePackages = "edu.lelyak") // assuming that's the parent package in your project
if you don't like this approach, you can add the controller's package name in basePackages
#ComponentScan(basePackages = {"edu.lelyak.controller","edu.lelyak.repository")
BTW, you don't have to manually set up WeatherStationService in MockConfig class, Spring boot can inject a mock for you and automatically reset it after each test method, you should just declare it in your test class:
#MockBean
private IStationRepository stationRepository;
On the other hand, you should mock weatherService.getAllStations() before calling get("/stations") in your test method (as you're not running integration test), so you can do:
List<WeatherStation> myList = ...;
//Add element(s) to your list
Mockito.when(stationService.getAllStations()).thenReturn(myList);
You can find more in :
Testing improvements in Spring Boot 1.4
Spring Boot features: Testing
I had the same issue. The controller was not getting picked up despite specifying it with #WebMvcTest(MyController.class). This meant all of its mappings were ignored, causing the 404. Adding #Import(MyController.class) resolved the issue, but I didn't expect the import to be necessary when I'm already specifying which controller to test.
I am not sure why your test is not working. But I got another solution which works for me.
#SpringBootTest
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();
}
#Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
After some debugging, it appears that the target controller is simply not registered as a method handler. Spring scans the beans for the presence of RestController annotation.
But the problem is that the annotation could be found only if the bean is proxied via CGLIB, but for the case when we use WebMvcTest it's proxied by JDK.
As a result, I searched for the configuration which is responsible for making the choice, and the one was finally found AopAutoConfiguration. So when SpringBootTest is used this one is autoloaded when you need WebMvcTest+PreAuthorize in your controllers, then simply use:
#Import(AopAutoConfiguration.class)
I import external configuration class by #ContextConfiguration(classes = MyConfig.class)
When I changed in MyConfig annotation #Configuration into #TestConfiguration it started to work properly.
I couldn't find a good answer but I could find one of the causes.
I was using in my tests the #PreAuthorize on the RestController.
You can mock the Oauth with this tip on the integration tests that use SpringBootTest. For SpringBootTest, this works very well too, but using SpringBootTest you load a lot of other resources (like JPA) that is not necessary to do a simple Controller test.
But with #WebMvcTest this not works as expected. The use of the WithMockOAuth2Scope annotation can be enough to stop the 401 error from authentication problem, but after that the WebMvcTest can't find the rest endpoint, returning the 404 error code.
After removing the #PreAuthorize on Controller, the test with WebMvcTest pass.
Based on the accepted answer, in my case I had copied and modified the file based on another test, but forgot to change the name for the controller on the top of the class, that being the reason why it was not finding the resource, as the error says.
#RunWith(SpringRunner.class)
#WebMvcTest(AnswerCommandController.class)
public class AnswerCommandControllerTest {
Here is a different approach to the controller test that worked for me.
Assumption: The class WeatherStationService is a #SpringBootApplication
Then, the test class below should work for you:
#RunWith(SpringRunner.class)
#SpringApplicationConfiguration(WeatherStationService.class)
#WebIntegrationTest
public class WeatherStationControllerTest {
#Autowired
private WebApplicationContext context;
MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
}
#Test
public void shouldReturnCorrectStation() throws Exception {
mockMvc.perform(get("/stations")
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk();
}
}
With this test setup, you should no longer need the MockConfig class.
In my case it was about a missing starting slash /
I've appended / to both RequestMapping value and MockHttpServletRequestBuilder post urlTemplate parameters as first character.
In case anyone is wondering.
If we don't use #ContextConfiguration, #WebMvcTest annotation will load the REST controller class. Otherwise, when we use use #ContextConfiguration, seems ContextConfiguration clear the context REST controller config. We need to add the REST controller to ContextConfiguration such as:
#ContextConfiguration(classes = {MockConfig.class, WeatherStationController.class})

Spring MVC web application - enabling / disabling controller from property

I have a web application running in Tomcat and using Spring MVC to define controllers and mappings. I have the following class:
#Controller("api.test")
public class TestController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public #ResponseBody String test(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
// body
}
}
I would like to make this controller and the ".../test" path available according to a property defined somewhere (e.g. file). If the property is, lets say, false, I would like the app to behave as if that path doesn't exist and if it is true, to behave normally. How can I do this? Thanks.
If you are using Spring 3.1+, make the controller available only in the test profile:
#Profile("test")
class TestController {
...
}
then enable that profile by e.g. passing the following system property at Tomcat boot:
-Dspring.profiles.active=test
To disable the controller simply omit the given profile.
Another way of doing it , may be simpler way of doing it, is to use #ConditionalOnProperty annotation with your RestController/Controller.
#RestController("api.test")
#ConditionalOnProperty(name = "testcontroller.enabled", havingValue = "true")
public class TestController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String test(HttpServletRequest httpRequest, HttpServletResponse httpResponse) {
// body
}
}
Here testcontroller.enabled property in your yml properties say ,if not set to true , the TestController Bean is never created.
Tip: I suggest you to use RestController instead of Controller as its has #ResponseBody added by default. You can use #ConditionalOnExpression to arrive at the same solution but is little slower due to SpEL evaluation.

Resources