Reputation: 3357
I have an Angular 2
service that POSTs login data to a Spring Boot
@RestContoller
The login request body:
{"_username": "test", "_password": "test"}
The Rest Controller:
@RestController
public class AuthControl {
@Autowired
AuthenticationService authenticationService;
@RequestMapping(value = "/someurl", method = RequestMethod.POST)
public LoginDto authenticate(HttpServletResponse response, LoginRequestDto requestDto) throws IOException, JSONException {
return authenticationService.authenticate(requestDto, response);
}
}
Jackson unmarshalls the request into this POJO
public class LoginRequestDto {
private String _username;
private String _password;
public LoginRequestDto() { }
public LoginRequestDto(String u, String p) {
this._username = u;
this._password = p;
}
// getters and setters
}
However, when Jackson unmarshalls the POJO the field values are set to null, rather than "test"/"test". As a result, the login attempt fails with a bad credentials message. I'm wondering if i'm missing a library or something that is resulting in the improper setting of these fields.
Dependencies from pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency><!-- implements Thymeleaf HTML5 parsing -->
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
Tthe only exception logged is a UsernameNotFoundException thrown by my implmentation of Spring Security's UserDetailsService. Using the debugger, I can manually parse the values from the request and set the values into the POJO. After doing this, the request completes, so it seems clear that the issue is in the unmarshalling phase.
Any thoughts or suggestions would be greatly appreciated.
Upvotes: 0
Views: 2601
Reputation: 2427
That is due to Jackson using the default constructor, by default, when deserializing. You need to use the @JsonCreator
annotation to let jackson know which the constructor you want to use is and the the annotation @JsonProperty
to let it know how to bind the params with the json properties.
public class LoginRequestDto {
private String _username;
private String _password;
public LoginRequestDto() { }
@JsonCreator
public LoginRequestDto(@JsonProperty("_username") String u,
@JsonProperty("_password") String p) {
this._username = u;
this._password = p;
}
// getters and setters
}
Have a look to the section Using constructors or factory methods at the jackson-annotations project.
Update your request mapping method specifying it consumes json and add the @RequestBody annotation to the method param
@RestController
public class AuthControl {
@Autowired
AuthenticationService authenticationService;
@RequestMapping(value = "/someurl", method = RequestMethod.POST, consumes = { MediaType.APPLICATION_JSON_VALUE })
public LoginDto authenticate(HttpServletResponse response, @RequestBody LoginRequestDto requestDto) throws IOException, JSONException {
return authenticationService.authenticate(requestDto, response);
}
}
Upvotes: 1