spring - Customized ObjectMapper not used in test -


i using spring framework, version 4.1.6, spring web services , without spring boot. learn framework, writing rest api , testing make sure json response received hitting endpoint correct. specifically, trying adjust objectmapper's propertynamingstrategy use "lower case underscores" naming strategy.

i using the method detailed on spring's blog create new objectmapper , add list of converters. follows:

package com.myproject.config;  import com.fasterxml.jackson.databind.propertynamingstrategy; import org.springframework.context.annotation.*; import org.springframework.http.converter.httpmessageconverter; import org.springframework.http.converter.json.jackson2objectmapperbuilder; import org.springframework.http.converter.json.mappingjackson2httpmessageconverter; import org.springframework.web.servlet.config.annotation.enablewebmvc; import org.springframework.web.servlet.config.annotation.webmvcconfigureradapter;  import java.util.list;  @configuration @enablewebmvc public class webconfig extends webmvcconfigureradapter {      @override     public void configuremessageconverters(list<httpmessageconverter<?>> converters) {         jackson2objectmapperbuilder builder = jacksonbuilder();         converters.add(new mappingjackson2httpmessageconverter(builder.build()));     }      public jackson2objectmapperbuilder jacksonbuilder() {         jackson2objectmapperbuilder builder = new jackson2objectmapperbuilder();         builder.propertynamingstrategy(propertynamingstrategy.camel_case_to_lower_case_with_underscores);          return builder;     } } 

then run following test (using junit, mockmvc, , mockito) verify changes:

package com.myproject.controller;  import org.junit.before; import org.junit.test; import org.junit.runner.runwith; import org.mockito.injectmocks; import org.mockito.mock; import org.mockito.mockitoannotations; import org.springframework.http.mediatype; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.springjunit4classrunner; import org.springframework.test.context.web.annotationconfigwebcontextloader; import org.springframework.test.context.web.webappconfiguration; import org.springframework.test.web.servlet.mockmvc; import org.springframework.test.web.servlet.mvcresult; import org.springframework.test.web.servlet.setup.mockmvcbuilders;  import static org.mockito.mockito.when; import static org.springframework.test.web.servlet.request.mockmvcrequestbuilders.get; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.content; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.status;  // along other application imports...  @runwith(springjunit4classrunner.class) @webappconfiguration @contextconfiguration(classes = {webconfig.class}, loader = annotationconfigwebcontextloader.class) public class mycontrollertest {      @mock     private mymanager mymanager;      @injectmocks     private mycontroller mycontroller;      private mockmvc mockmvc;      @before     public void setup() {         mockitoannotations.initmocks(this);         this.mockmvc = mockmvcbuilders.standalonesetup(this.mycontroller).build();     }       @test     public void testmycontrollerwithnameparam() throws exception {         myentity expected = new myentity();         string name = "expected";         string title = "expected title";          // set myentity data.         expected.setid(1); // random id.         expected.setentityname(name);         expected.setentitytitle(title)          // when mymanager instance asked myentity name parameter,         // return expected.         when(this.mymanager.read(name)).thenreturn(expected);          // assert proper results.         mvcresult result = mockmvc.perform(                 get("/v1/endpoint")                     .param("name", name))                 .andexpect(status().isok())                 .andexpect((content().contenttype("application/json;charset=utf-8")))                 .andexpect(jsonpath("$.entity_name", is(name))))                 .andexpect(jsonpath("$.entity_title", is(title)))                 .andreturn();          system.out.println(result.getresponse().getcontentasstring());     } } 

however, returns response of:

{"id": 1, "entityname": "expected", "entitytitle": "expected title"} 

when should get:

{"id": 1, "entity_name": "expected", "entity_title": "expected title"} 

i have implemented webapplicationinitializer scans package:

package com.myproject.config;  import org.springframework.web.webapplicationinitializer; import org.springframework.web.context.contextloaderlistener; import org.springframework.web.context.support.annotationconfigwebapplicationcontext; import org.springframework.web.servlet.dispatcherservlet;  import javax.servlet.servletcontext; import javax.servlet.servletexception; import javax.servlet.servletregistration;  public class webappinitializer implements webapplicationinitializer {      public void onstartup(servletcontext servletcontext) throws servletexception {         annotationconfigwebapplicationcontext ctx = new annotationconfigwebapplicationcontext();         ctx.scan("com.myproject.config");         ctx.setservletcontext(servletcontext);          servletregistration.dynamic servlet = servletcontext.addservlet("dispatcher", new dispatcherservlet(ctx));         servlet.setloadonstartup(1);         servlet.addmapping("/");          servletcontext.addlistener(new contextloaderlistener(ctx));     } } 

using debugger within intellij, can see builder created , added, somewhere down line resulting objectmapper not used. must missing something, examples i've managed find don't seem mention is! i've tried eliminating @enablewebmvc , implementing webmvcconfigurationsupport, using mappingjackson2httpmessageconverter bean, , setting objectmapper bean no avail.

any appreciated! please let me know if other files required.

thanks!

edit: doing more digging , found this. in link, author appends setmessageconverters() before he/she builds mockmvc , works author. doing same worked me well; however, i'm not sure if work in production repositories aren't flushed out yet. when find out submit answer.

edit 2: see answer.

i looked understanding why works way did. reiterate, process of getting customized objectmapper work in test (assuming mockmvc being created standalone) follows:

  1. create webconfig class extends webmvcconfigureradapter.
  2. in webconfig class, create new @bean returns mappingjackson2httpmessageconverter. mappingjackson2httpmessageconverter has desired changes applied (in case, passing jackson2objectmapperbuilder propertynamingstrategy set camel_case_to_lower_case_with_underscores.)
  3. also in webconfig class, @override configuremessageconverters() , add mappingjackson2httpmessageconverter (2) list of message converters.
  4. in test file, add @contextconfiguration(classes = { webconfig.class }) annotation inform test of @bean.
  5. use @autowired inject , access @bean defined in (2).
  6. in setup of mockmvc, use .setmessageconverters() method , pass injected mappingjackson2httpmessageconverter. test use configuration set in (2).

the test file:

package com.myproject.controller;  import org.junit.before; import org.junit.test; import org.junit.runner.runwith; import org.mockito.injectmocks; import org.mockito.mock; import org.mockito.mockitoannotations; import org.springframework.http.mediatype; import org.springframework.test.context.contextconfiguration; import org.springframework.test.context.junit4.springjunit4classrunner; import org.springframework.test.context.web.annotationconfigwebcontextloader; import org.springframework.test.context.web.webappconfiguration; import org.springframework.test.web.servlet.mockmvc; import org.springframework.test.web.servlet.mvcresult; import org.springframework.test.web.servlet.setup.mockmvcbuilders;  import static org.mockito.mockito.when; import static org.springframework.test.web.servlet.request.mockmvcrequestbuilders.get; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.content; import static org.springframework.test.web.servlet.result.mockmvcresultmatchers.status;  // along other application imports...  @runwith(springjunit4classrunner.class) @webappconfiguration @contextconfiguration(classes = {webconfig.class}) public class mycontrollertest {      /**      * note converter needs autowired test in order      * mockmvc recognize in setup() method.      */     @autowired     private mappingjackson2httpmessageconverter jackson2httpmessageconverter;      @mock     private mymanager mymanager;      @injectmocks     private mycontroller mycontroller;      private mockmvc mockmvc;      @before     public void setup() {         mockitoannotations.initmocks(this);         this.mockmvc = mockmvcbuilders             .standalonesetup(this.mycontroller)             .setmessageconverters(this.jackson2httpmessageconverter) // important!             .build();     }       @test     public void testmycontrollerwithnameparam() throws exception {         myentity expected = new myentity();         string name = "expected";         string title = "expected title";          // set myentity data.         expected.setid(1); // random id.         expected.setentityname(name);         expected.setentitytitle(title)          // when mymanager instance asked myentity name parameter,         // return expected.         when(this.mymanager.read(name)).thenreturn(expected);          // assert proper results.         mvcresult result = mockmvc.perform(                 get("/v1/endpoint")                     .param("name", name))                 .andexpect(status().isok())                 .andexpect((content().contenttype("application/json;charset=utf-8")))                 .andexpect(jsonpath("$.entity_name", is(name))))                 .andexpect(jsonpath("$.entity_title", is(title)))                 .andreturn();          system.out.println(result.getresponse().getcontentasstring());     } } 

and configuration file:

package com.myproject.config; import com.fasterxml.jackson.databind.propertynamingstrategy; import org.springframework.context.annotation.*; import org.springframework.http.converter.httpmessageconverter; import org.springframework.http.converter.json.jackson2objectmapperbuilder; import org.springframework.http.converter.json.mappingjackson2httpmessageconverter; import org.springframework.web.servlet.config.annotation.enablewebmvc; import org.springframework.web.servlet.config.annotation.webmvcconfigureradapter;  import java.util.list;  @configuration @enablewebmvc public class webconfig extends webmvcconfigureradapter {      @override     public void configuremessageconverters(list<httpmessageconverter<?>> converters) {         converters.add(jackson2httpmessageconverter());     }      @bean     public mappingjackson2httpmessageconverter jackson2httpmessageconverter() {         mappingjackson2httpmessageconverter converter = new mappingjackson2httpmessageconverter();         jackson2objectmapperbuilder builder = this.jacksonbuilder();         converter.setobjectmapper(builder.build());          return converter;     }      public jackson2objectmapperbuilder jacksonbuilder() {         jackson2objectmapperbuilder builder = new jackson2objectmapperbuilder();          builder.propertynamingstrategy(propertynamingstrategy.camel_case_to_lower_case_with_underscores);          return builder;     } } 

deploying generated war file tomcat 7 in xampp shows naming strategy being used correctly. reason believe works way because standalone setup, default set of message converters used unless otherwise specified. can seen in comment setmessageconverters() function within standalonemockmvcbuilder.java (version 4.1.6, \org\springframework\test\web\servlet\setup\standalonemockmvcbuilder.java):

   /**      * set message converters use in argument resolvers , in return value      * handlers, support reading and/or writing body of request      * , response. if no message converters added list, default      * list of converters added instead.      */     public standalonemockmvcbuilder setmessageconverters(httpmessageconverter<?>...messageconverters) {         this.messageconverters = arrays.aslist(messageconverters);         return this;     } 

therefore, if mockmvc not explicitly told one's changes message converters during building of mockmvc, not use changes.


Comments

Popular posts from this blog

yii2 - Yii 2 Running a Cron in the basic template -

asp.net - 'System.Web.HttpContext' does not contain a definition for 'GetOwinContext' Mystery -

mercurial graft feature, can it copy? -