Post entity returning null for testresttemplate - resttemplate

I am doing my integration test using test rest template but for postForEntity method I am getting null as response body, but I saw examples which were working fine on that but I am unable to resolve my issue,
PFB my test case
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ActiveProfiles("test")
public class PersonControllerTests {
#Autowired
private TestRestTemplate restTemplate;
#MockBean
private PersonRepository mockRepository;
#Before
public void init() {
List<Person> list = new ArrayList<>();
Person p1 = new Person("dumm1", "lastName1",22);
Person p2 = new Person("dumm2", "lastName2",32);
p1.setId(1l);
list.add(p2);
list.add(p1);
when(mockRepository.findAll()).thenReturn(list);
when(mockRepository.findById(1l)).thenReturn(Optional.of( p1 ));
}
#Test
public void createPerson() throws Exception {
Person p = new Person("dummy1", "dumm2", 11);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Person> httpEntity = new HttpEntity<Person>(p,headers);
ResponseEntity<String> response = restTemplate
.withBasicAuth("user", "password")
.postForEntity("/persons/create", httpEntity, String.class);
assertEquals(HttpStatus.OK, response.getStatusCode());
//assertEquals(MediaType.APPLICATION_JSON, response.getHeaders().getContentType());
assertEquals(11, response.getBody());
}
PFB my original code:
#RestController
#RequestMapping("/persons")
public class PersonController {
#Autowired
PersonRepository personRepository;
#GetMapping("/all")
public Iterable<Person> getAllUser() {
return personRepository.findAll();
}
#PostMapping(value ="/create",consumes = MediaType.APPLICATION_JSON_VALUE)
public Person createUser( #RequestBody Person person) {
return personRepository.save(person);
}
}
I believe I am doing some silly mistake but unable to understand

You are using #MockBean for your PersonRepository. Without any stubbing setup, Mockito returns null for reference types.
That's why return personRepository.save(person); returns null during your test.
You can stub your mock to simulate its behavior:
// import static org.mockito.ArgumentMatchers.any;
when(personRepository.save(ArgumentMatchers.any(Person.class))).thenAnswer(invocation -> {
Person person = invocation.getArgument(0);
// I assume you have an id field
person.setId(42L);
return person;
});

Related

Getting NullPointerEXception using Mockito Test case error 400

I'm Adding 3 Categories using Post Request and for every Category, 3 respective Courses are added to the same. Finally I need to get an array of Categories containing list of courses.
But while performing Test Driven Development using Mockito, I', recieving a null Pointer Exception with status code 400.
Kindly help me in the same.
Test.java
#RunWith(value = MockitoJUnitRunner.class)
#WebMvcTest(Controller.class)
class Test {
#Autowired
MockMvc mvc;
#MockBean
service s;
#MockBean
Controller cont;
#MockBean
StatusResultMatchers sr;
#org.junit.jupiter.api.Test
void catTest() throws Exception {
Course c1=new Course(1,"Technology",100,50,7415);
Course c2=new Course(2,"Technology",100,50,7415);
Course c3=new Course(3,"Technology",100,50,7415);
Course[] c= {c1,c2,c3};
List<Course> cl=new ArrayList<Course>();
cl.add(c1);
cl.add(c2);
cl.add(c3);
Category ca=new Category(7415,"java","very gud", cl);
when(s.getAllContents()).thenReturn(cl);
mvc.perform(get("/getcourse")).andExpect(sr.is2xxSuccessful()).andReturn();
}
}
Controller.java
#RestController
public class Controller {
#Autowired
private service cs;
#RequestMapping(value="/addcat", method=RequestMethod.POST)
public void addcat(#RequestBody Category[] categ) throws Exception{
for(int i=0;i<3;i++)
cs.cat[i]=categ[i];
}
#RequestMapping(value="/addcour", method=RequestMethod.POST)
public void addcour(#RequestBody Course[] cour) {
for(Category c:cs.cat) {
cs.co=null;
for(int i=0;i<3;i++) {
if(cour[i].getCategoryId()==c.getCategoryId()) {
cs.co.add(cour[i]);
c.setCourseList(cs.co);
}
}
}
}
#RequestMapping(value="/getcat", method=RequestMethod.GET)
public #ResponseBody Category[] getcat(){
return cs.getAllCategories();
}
#RequestMapping(value="/getcourse", method=RequestMethod.GET)
public #ResponseBody List<Course> getcourse(#RequestBody Map<Category,List<Course> > cour){
return cs.getAllContents();
}
}
Service.java
#Service
public class service {
public List<Course> co=new ArrayList<Course>();
public Category[] cat=new Category[3];
public List<Course> getAllContents() {
return co;
}
public Category[] getAllCategories() {
return cat;
}
}
Test Output
MockHttpServletRequest:
HTTP Method = GET
Request URI = /getcourse
Parameters = {}
Headers = []
Body = <no character encoding set>
Session Attrs = {}
Handler:
Type = com.example.demo.controller.Controller$MockitoMock$138133307
Method = com.example.demo.controller.Controller$MockitoMock$138133307#getcourse(Map)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotReadableException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 400
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
2020-06-03 17:38:59.573 INFO 26360 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
I have updated my code. Now, NullPOinterException is not there. But I'm getting an empty list "ActualCourse".
Please find d code below:
Test.java
#RunWith(value = MockitoJUnitRunner.class)
#WebMvcTest(Controller.class)
class Test {
#Autowired
MockMvc mvc;
#MockBean
service testService;
#MockBean
Controller targetController;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#org.junit.jupiter.api.Test
void catTest() throws Exception {
// Mock Data
Course c1=new Course(1,"Technology",100,50,7415);
Course c2=new Course(2,"Technology",100,50,7415);
Course c3=new Course(3,"Technology",100,50,7415);
List<Course> expectedCourse=new ArrayList<Course>();
expectedCourse.add(c1);
expectedCourse.add(c2);
expectedCourse.add(c3);
Category expectedCategory=new Category(7415,"java","very gud", expectedCourse);
when(testService.addcour()).thenReturn(expectedCourse);
List<Course> actualCourse = targetController.addcour();
assertEquals(expectedCourse,actualCourse);
}
Controller.java
#RestController
public class Controller {
#Autowired
private service cs;
#RequestMapping(value="/addcat", method=RequestMethod.POST)
public List<Category> addcat(#RequestBody Category[] categ) throws Exception{
return cs.addcat(categ);
}
#RequestMapping(value="/addcour", method=RequestMethod.POST)
public List<Course> addcour() {
return cs.addcour();
}
#RequestMapping(value="/getcat", method=RequestMethod.GET)
public #ResponseBody List<Category> getcat(){
return cs.getAllCategories();
}
#RequestMapping(value="/getcourse", method=RequestMethod.GET)
public #ResponseBody List<Course> getcourse(){
return cs.getAllCourses();
}
}
Service.java
#Service
public class service {
public List<Category> cat=new ArrayList<Category>();
public List<Course> c=new ArrayList<Course>();
List<Course> empty=new ArrayList<Course>();
List<Category> category=new ArrayList<Category>();
public List<Category> addcat(Category[] categ) {
int flagcat=0,flagcourse=0;
Category c1=new Category(7415,"Technology","Java",empty);
Category c2=new Category(2,"Technology","Java",empty);
Category c3=new Category(7314,"Technology","Java",empty);
Category c4=new Category(4,"Technology","Java",empty);
Category c5=new Category(8415,"Technology","Java",empty);
Category c6=new Category(6,"Technology","Java",empty);
category=Arrays.asList(c1,c2,c3,c4,c5,c6);
Iterator icat=category.iterator();
Iterator icourse=c.iterator();
Object ncourse=new Object();
Object ncat=new Object();
while(icat.hasNext()) {
List<Course> co=new ArrayList<Course>();
flagcat++;
flagcourse=0;
ncat=icat.next();
while(icourse.hasNext()) {
ncourse=icourse.next();
if(((Category) ncourse).getCategoryId()==((Category) ncat).getCategoryId()) {
flagcourse++;
co.add((Course) ncourse);
if(flagcourse==3) {
((Category) ncat).setCourseList(co);
break;
}
}
}
cat.add((Category) icat);
if(flagcat==3) {
break;
}
}
return cat;
}
public List<Course> addcour() {
Course c1=new Course(1,"Technology",100,50,7415);
Course c2=new Course(2,"Technology",100,50,7415);
Course c3=new Course(3,"Technology",100,50,7415);
Course c4=new Course(4,"Technology",100,50,7314);
Course c5=new Course(5,"Technology",100,50,7314);
Course c6=new Course(6,"Technology",100,50,7314);
Course c7=new Course(7,"Technology",100,50,8415);
Course c8=new Course(8,"Technology",100,50,8415);
Course c9=new Course(9,"Technology",100,50,8415);
Course c10=new Course(10,"Technology",100,50,8415);
List<Course> c=Arrays.asList(c1,c2,c3,c4,c5,c6,c7,c8,c9,c10);
return c;
}
public List<Course> getAllCourses() {
return c;
}
public List<Category> getAllCategories() {
return cat;
}
}
Output
org.opentest4j.AssertionFailedError: expected: <[com.example.demo.Course#6ecc02bb, com.example.demo.Course#31973858, com.example.demo.Course#65514add]> but was: <[]>
at org.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:55)
at org.junit.jupiter.api.AssertionUtils.failNotEqual(AssertionUtils.java:62)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182)
at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177)
at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:1124)
at com.example.demo.test.Test.catTest(Test.java:75)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:567)
at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:686)
at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:149)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:140)
at org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:84)
at org.junit.jupiter.engine.execution.ExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(ExecutableInvoker.java:115)
at org.junit.jupiter.engine.execution.ExecutableInvoker.lambda$invoke$0(ExecutableInvoker.java:105)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:104)
at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:98)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:212)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:208)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:137)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:71)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:135)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1507)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:139)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$7(NodeTestTask.java:125)
at org.junit.platform.engine.support.hierarchical.Node.around(Node.java:135)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:123)
at org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:122)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:80)
at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:51)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:229)
at org.junit.platform.launcher.core.DefaultLauncher.lambda$execute$6(DefaultLauncher.java:197)
at org.junit.platform.launcher.core.DefaultLauncher.withInterceptedStreams(DefaultLauncher.java:211)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:191)
at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:137)
at org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:89)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:542)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:770)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:464)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
It seems you have some design issues in your code. In your controller, the getcourse method is receiving a request body Map<Category,List<Course> > cour, but the HTTP method is a GET, you're not supposed to send data in a GET method (check this answer and this for more context).
On the other side, your getcourse is not using the cour parameter, so refactor this method as:
#RequestMapping(value="/getcourse", method=RequestMethod.GET)
public #ResponseBody List<Course> getcourse(){
return cs.getAllContents();
}
Let me know if it works.

object reference not set to instance of an object issues in unit testing of asp.net mvc

I am the beginner of writing unit tests for asp.net. I created a simple project and try to start my testing journey. However, I met two errors with the same issue:"object reference not set to instance of an object" The first place is in the home controller as below:
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
Here is my test method:
public class HomeControllerUnitTests
{
ILogger<HomeController> _logger;
[Fact]
public void Error_ActionExecutes_ReturnsAViewResult()
{
// Arrange
var homeController = new HomeController(_logger);
// Act
var result = homeController.Error() as ViewResult;
// Assert
Assert.Null(result.ViewData.Model);
}
}
The second place is in the Movie Controller:
public class MoviesController : Controller
{
private readonly MvcMovieContext _context;
public MoviesController(MvcMovieContext context)
{
_context = context;
}
// GET: Movies
public async Task<IActionResult> Index()
{
return View(await _context.Movie.ToListAsync());
}
}
My test method is as below:
public class MoviesControllerUnitTests
{
private Mock<MvcMovieContext> _mock;
[Fact]
public async Task Index_ActionExecutes_ReturnsAViewResult()
{
// Arrange
MoviesController controller = new MoviesController(_mock.Object);
// Act
var result = await controller.Index() as Task<ViewResult>;
// Assert
Assert.IsType<ViewResult>(result);
}
}
Please help me and thanks in advance.
Below the Object reference not set to an instance of an object line there should be an indication about which file and line the error occurred, which helps you to determine which variables are null (but you could also use the debugger).
For the MoviesControllerUnitTests this probably is the _mock variable, so be sure to initialize it as shown in the docs, e.g.:
private Mock<MvcMovieContext> _mock = new Mock<MvcMovieContext>();
For the HomeControllerUnitTests you might need to mock the Activity or set a HttpContext (see e.g. this question).

How to preserve HttpServletRequest autowiring when testing with SpringMVC Mockito and PowerMockito

Hi I'm trying to write some tests with Mockito and PowerMockito (I need to mock private methods) for a rest service written with SpringMVC and I'm facing the following issue
This is the semplified version of the controller
#Controller
#RequestMapping(value = "/test")
public class SimpleController {
#Autowired
private HttpServletRequest httpRequest;
#RequestMapping(value = "/simpleservice", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
#ResponseBody
public SimpleServiceResponse simpleService(#RequestBody SimpleServiceRequest simpleServiceRequest, HttpServletRequest httpServletRequest) {
SimpleServiceResponse simpleServiceResponse=new SimpleServiceResponse(simpleServiceRequest.getValue());
httpRequest.getHeader("Header");
return simpleServiceResponse;
}
}
and this is the correspoding test class
#WebAppConfiguration
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"classpath:WebApplicationContext.xml","classpath:SimpleApplicationContext.xml"})
#PrepareForTest(WebController.class)
#TestExecutionListeners({DependencyInjectionTestExecutionListener.class})
public class TestSimpleControllerMockito {
private Logger logger = LoggerFactory.getLogger(TestSimpleControllerMockito.class.getName());
private ObjectMapper objectMapper= new ObjectMapper();
#InjectMocks
private SimpleController controller;
#Test
public void testSimpleService() throws Exception {
MockitoAnnotations.initMocks(this);
SimpleService mockedSimple = mock(SimpleService.class);
when(mockedSimple.doSimpleService(any(SimpleServiceRequest.class))).thenReturn(new SimpleServiceResponse("MockMock"));
SimpleController mockedController=PowerMockito.spy(controller);
SimpleServiceRequest simpleServiceRequest= new SimpleServiceRequest("ciao");
String requestAsStr=objectMapper.writeValueAsString(simpleServiceRequest);
MockMvc mMockMvc=MockMvcBuilders.standaloneSetup(mockedController).build();
MvcResult result= mMockMvc.perform(post("/test/simpleservice").content(requestAsStr).contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
String content = result.getResponse().getContentAsString();
SimpleServiceResponse simpleServiceResponse=objectMapper.readValue(content,SimpleServiceResponse.class);
Assert.assertEquals("MockMockMockedSessionManager",simpleServiceResponse.getValue());
}
}
When running the test case I got a NullPointerEception on httpRequest.getHeader("Header");
My guess is that using the #InjectMocks annotation and then using
SimpleController mockedController=PowerMockito.spy(controller);
is the cause of the NullPointerException. I don't know how to preserve the #Autowire annotation processing on the controller Object. I already found a workaround, but it requires to write some redundant code.
Is there a way to make the #autowired annotation work?
Thanks a lot.
P.S.
the SimpleServiceXXX classes are like this one:
public class SimpleServiceResponse {
private String value;
public SimpleServiceResponse() {
}
public SimpleServiceResponse(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

spring MVC use #JsonView on spring-data Page

I'm using Spring-MVC, Spring-data-jpa, jackson on a Jhipster project.
I managed to use the #JsonView annotation on an object and it works well when the method in the rest controller return a type ResponseEntity<List<MyObject>> but I can't make it work when the method return type is ResponseEntity<Page<MyObject>>.
I've tried to set MapperFeature.DEFAULT_VIEW_INCLUSION to true (which default is false). When I do it, all attributes are serialized. But filtering through #JsonView does not work anymore.
I can't modify the Page object because it's a Spring-data object.
I'm looking for a way to tell jackson to include all attributes of the Page object.
Here is my code:
My entity:
#Entity
#Table(name = "T_REGION")
public class Region implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "code", nullable = false)
private Integer code;
#Column(name = "name", length = 60, nullable = false)
#JsonView(View.Summary.class)
private String name;
// Getters and setters
}
My rest controller:
#RestController
#RequestMapping("/api")
public class RegionResource {
#RequestMapping(value = "/regionsearch1",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#JsonView(View.Summary.class)
public ResponseEntity<Page<Region>> findAll1(
#RequestParam(value = "page" , required = false) Integer offset,
#RequestParam(value = "per_page", required = false) Integer limit,
Sort sort)
throws URISyntaxException {
Pageable pageRequest = PaginationUtil.generatePageRequest(offset, limit, sort);
Page<Region> page = regionRepository.findAll(pageRequest);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/regionsearch1", pageRequest);
return new ResponseEntity<>(page, headers, HttpStatus.OK);
}
#RequestMapping(value = "/regionsearch2",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
#JsonView(View.Summary.class)
public ResponseEntity<List<Region>> findAll2(
#RequestParam(value = "page" , required = false) Integer offset,
#RequestParam(value = "per_page", required = false) Integer limit,
Sort sort)
throws URISyntaxException {
Pageable pageRequest = PaginationUtil.generatePageRequest(offset, limit, sort);
Page<Region> page = regionRepository.findAll(pageRequest);
HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/regionsearch2", pageRequest);
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
}
findAll1 returns:
[
{
"name": "Ile-de-France"
},
{
"name": "Champagne-Ardenne"
},
....
]
findAll2 returns:
{}
The object Page has no #JsonView on its attributes therefore no attributes are serialized.
I can't find a way to tell Jackson to include all Page attributes even when #JsonView is used.
Any ideas ?
Another way to return all page elements is to create your own implementation for the Page interface (including the JsonView you want):
JsonPage
public class JsonPage<T> extends org.springframework.data.domain.PageImpl<T> {
public JsonPage(final List<T> content, final Pageable pageable, final long total) {
super(content, pageable, total);
}
public JsonPage(final List<T> content) {
super(content);
}
public JsonPage(final Page<T> page, final Pageable pageable) {
super(page.getContent(), pageable, page.getTotalElements());
}
#JsonView(JsonViews.UiView.class)
public int getTotalPages() {
return super.getTotalPages();
}
#JsonView(JsonViews.UiView.class)
public long getTotalElements() {
return super.getTotalElements();
}
#JsonView(JsonViews.UiView.class)
public boolean hasNext() {
return super.hasNext();
}
#JsonView(JsonViews.UiView.class)
public boolean isLast() {
return super.isLast();
}
#JsonView(JsonViews.UiView.class)
public boolean hasContent() {
return super.hasContent();
}
#JsonView(JsonViews.UiView.class)
public List<T> getContent() {
return super.getContent();
}
}
Next return this class to the controller layer:
Service
#Override
public Page<User> findAll(final int page) {
PageRequest pr = new PageRequest(page, pageSize, new Sort(Sort.Direction.DESC, "dateCreated"));
return new JsonPage<User>(userRepository.findAll(pr), pr);
}
Controller
#JsonView(JsonViews.UiView.class)
#RequestMapping(method = RequestMethod.GET, value = "{page}")
public Page<User> getUsers(#PathVariable final int page) {
return userService.findAll(page);
}
I have done like this , it's working well
package com.natixis.spring.ws.configuration;
import java.io.IOException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.domain.Page;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
#Configuration
public class JacksonAdapter extends WebMvcConfigurerAdapter {
#Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
return new Jackson2ObjectMapperBuilder()
.failOnUnknownProperties(false)
.serializationInclusion(Include.NON_EMPTY)
.serializerByType(Page.class, new JsonPageSerializer());
}
public class JsonPageSerializer extends JsonSerializer<Page<?>>{
#Override
public void serialize(Page<?> page, JsonGenerator jsonGen, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
ObjectMapper om = new ObjectMapper()
.disable(MapperFeature.DEFAULT_VIEW_INCLUSION)
.setSerializationInclusion(Include.NON_EMPTY);
jsonGen.writeStartObject();
jsonGen.writeFieldName("size");
jsonGen.writeNumber(page.getSize());
jsonGen.writeFieldName("number");
jsonGen.writeNumber(page.getNumber());
jsonGen.writeFieldName("totalElements");
jsonGen.writeNumber(page.getTotalElements());
jsonGen.writeFieldName("last");
jsonGen.writeBoolean(page.isLast());
jsonGen.writeFieldName("totalPages");
jsonGen.writeNumber(page.getTotalPages());
jsonGen.writeObjectField("sort", page.getSort());
jsonGen.writeFieldName("first");
jsonGen.writeBoolean(page.isFirst());
jsonGen.writeFieldName("numberOfElements");
jsonGen.writeNumber(page.getNumberOfElements());
jsonGen.writeFieldName("content");
jsonGen.writeRawValue(om.writerWithView(serializerProvider.getActiveView())
.writeValueAsString(page.getContent()));
jsonGen.writeEndObject();
}
}
}
Regards,
RĂ©gis LIMARE
I know this is an old question, but you can use something like this for a Page of objects
#Configuration
public class JacksonAdapter implements WebMvcConfigurer {
#Bean
public Jackson2ObjectMapperBuilder jacksonBuilder() {
return new Jackson2ObjectMapperBuilder().failOnUnknownProperties(false).serializerByType(Page.class,
new JsonPageSerializer());
}
public class JsonPageSerializer extends JsonSerializer<Page> {
#Override
public void serialize(Page page, JsonGenerator jsonGen, SerializerProvider serializerProvider)
throws IOException {
ObjectMapper om = new ObjectMapper().disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
jsonGen.writeStartObject();
jsonGen.writeFieldName("size");
jsonGen.writeNumber(page.getSize());
jsonGen.writeFieldName("number");
jsonGen.writeNumber(page.getNumber());
jsonGen.writeFieldName("totalElements");
jsonGen.writeNumber(page.getTotalElements());
jsonGen.writeFieldName("last");
jsonGen.writeBoolean(page.isLast());
jsonGen.writeFieldName("totalPages");
jsonGen.writeNumber(page.getTotalPages());
jsonGen.writeObjectField("sort", page.getSort());
jsonGen.writeFieldName("first");
jsonGen.writeBoolean(page.isFirst());
jsonGen.writeFieldName("numberOfElements");
jsonGen.writeNumber(page.getNumberOfElements());
jsonGen.writeFieldName("content");
jsonGen.writeRawValue(
om.writerWithView(serializerProvider.getActiveView()).writeValueAsString(page.getContent()));
jsonGen.writeEndObject();
}
}
}
I've encountered the same problem and I solved it by setting MapperFeature.DEFAULT_VIEW_INCLUSION to true, but you should annotate all fields in classes where you want to apply your view with JsonView or JsonIgnore annotation so they wouldn't be included by default in json.

How to test POST spring mvc

My problem is to how to call this. I could do
MyObject o = new MyObject();
myController.save(o, "value");
but this is not what I would like to do. I would like the MyObject to be in the request post body? How can this be done?
#Requestmapping(value="/save/{value}", method=RequestMethod.POST)
public void post(#Valid MyObject o, #PathVariable String value{
objectService.save(o);
}
Just to be clear I am talking about unit testing.
Edit:
#RequestMapping(value = "/", method = RequestMethod.POST)
public View postUser(ModelMap data, #Valid Profile profile, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
return dummyDataView;
}
data.put(DummyDataView.DATA_TO_SEND, "users/user-1.json");
profileService.save(profile);
return dummyDataView;
}
See sample code below that demonstrates unit testing a controller using junit and spring-test.
#RunWith(SpringJUnit4ClassRunner.class)
#TestExecutionListeners({
DependencyInjectionTestExecutionListener.class,
DirtiesContextTestExecutionListener.class,
TransactionalTestExecutionListener.class })
#Transactional
#ContextConfiguration(locations = {
"classpath:rest.xml"
})
public class ControllerTest{
private MockHttpServletRequest request;
private MockHttpServletResponse response;
#Autowired
private RequestMappingHandlerAdapter handlerAdapter;
#Autowired
private RequestMappingHandlerMapping handlerMapping;
#Before
public void setUp() throws Exception
{
this.request = new MockHttpServletRequest();
request.setContentType("application/json");
this.response = new MockHttpServletResponse();
}
#Test
public void testPost(){
request.setMethod("POST");
request.setRequestURI("/save/test"); //replace test with any value
final ModelAndView mav;
Object handler;
try{
MyObject o = new MyObject();
//set values
//Assuming the controller consumes json
ObjectMapper mapper = new ObjectMapper();
//set o converted as JSON to the request body
//request.setContent(mapper.writeValueAsString(o).getBytes());
request.setAttribute("attribute_name", o); //in case you are trying to set a model attribute.
handler = handlerMapping.getHandler(request).getHandler();
mav = handlerAdapter.handle(request, response, handler);
Assert.assertEquals(200, response.getStatus());
//Assert other conditions.
}
catch (Exception e)
{
}
}
}
You need to use RequestBody:
#Requestmapping(value="/save/{value}", method=RequestMethod.POST)
public void post(#RequestBody MyObject o, #PathVariable String value{
objectService.save(o);
}
general info about request body documentation : http://static.springsource.org/spring/docs/3.0.x/reference/mvc.html#mvc-ann-requestbody

Resources