20

I have a simple test to my RestController. I expect that $[1].parent_idreturns Long as an object and not integer primitive. It will return Long if parent_id is in a long number range and > integer number range (such as : 2147483650L).

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@WebAppConfiguration
public class TransactionServiceControllerTest {

@Before
public void setup() throws Exception {
    this.mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    // I copy this from my RestController class
    this.transactions = Arrays.asList(
            new Transaction(100d, "car", null),
            new Transaction(100d, "table", 12L)
     );
}

@Test
public void readSingleBookmark() throws Exception {
   mockMvc.perform(MockMvcRequestBuilders.get("/transaction/"))
   .andExpect(content().contentType(contentType)) // ok
   .andExpect(jsonPath("$", hasSize(2))) // ok
   //omitted
   andExpect(jsonPath("$[1].parent_id",is(this.transactions.get(1).getParentId())));
} //assertion fail

Expected: is <12L>
but: was <12>

Result from another test :

Expected: is <12L>
but: was <2147483650L> //return Long instead int

this is my JacksonConfiguration

@Configuration
public class JacksonConfiguration {

    @Bean
    @Primary
    public ObjectMapper objectMapper() {
        final ObjectMapper objectMapper = new ObjectMapper();

        //supposed to be this is the magic trick but it seems not..
        objectMapper.enable(DeserializationFeature.USE_LONG_FOR_INTS);


        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_ABSENT);
        objectMapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);
        return objectMapper;
    }
}

And my POJO

public class Transaction {

private double ammount;

private String type;

private Long parentId;

public Transaction(Double ammount, String type, Long parentId) {
  //omitted
}
//setter and getter omitted
}

MyRestController

@RestController
@RequestMapping("transaction")
public class TransactionServiceController {

@RequestMapping(method = RequestMethod.GET)
List<Transaction> getTransaction() {
    return
            Arrays.asList(
                    new Transaction(100d, "car", null),
                    new Transaction(100d, "table", 12L)
            );
    }
}

And Application.java

@SpringBootApplication
public class Application {
    public static void main(String[] args){
        SpringApplication.run(Application.class,args);
    }
}
slawalata
  • 389
  • 1
  • 2
  • 14
  • Just a friendly note that if you find one of the answers to your question acceptable, feel free to [accept it](http://stackoverflow.com/help/accepted-answer) if you want to. – Sam Brannen Sep 10 '16 at 10:49
  • I am really sorry that today (after 1 year) I just realise that I hit the wrong button. I thought accepting answer were ```up button```. But it is a ```check button ``` which has been explained thoroughly in ```Stackoverflow new user welcoming how to```. many thank to SamBrenner to friendly (almost neglected) reminder. – slawalata Jun 27 '17 at 09:54
  • No worries. Cheers! ;-) – Sam Brannen Jun 28 '17 at 10:10

2 Answers2

22

Since Spring 5.2 you can provide type as a third argument of jsonPath() method:

public static <T> ResultMatcher jsonPath(String expression, Matcher<T> matcher, Class<T> targetType)

So in this case it will be:

andExpect(jsonPath("$[1].parent_id",is(this.transactions.get(1).getParentId()), Long.class));

Source: Spring Javadoc API

komidawi
  • 386
  • 3
  • 8
18

Update

  • Spring Framework 4.3.3 and 5.0.0 added first-class support for explicit conversions for request content for use with MockRestServiceServer.
  • Spring Framework 4.3.15 and 5.0.5 will add first-class support for explicit conversions for response content for use with MockMvc.

Original Answer

One option (which I haven not personally verified) would be to try a different JsonProvider. This can be set via com.jayway.jsonpath.Configuration.setDefaults(Defaults).

If you are sure that the Long can always be safely narrowed to an int, you could use the following:

andExpect(jsonPath("$[1].parent_id",is(this.transactions.get(1).getParentId().intValue())));

And the only other option is to write a custom Matcher that converts the incoming Integer to a Long before performing the actual matching.

Sam Brannen
  • 29,611
  • 5
  • 104
  • 136