Spring 5.0/Spring Boot 2.0にしたらMockMvcを使ったテストが406 Not Acceptableを返してくる話

Content-Type周りの挙動で死んでしまった回

使っているSpringは5.1.0、Spring Bootは2.0.6です。

元はこんなコード。

   @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
            .setMessageConverters(httpMessageConverter());
    }

    @Test
    public void testGetMailSuppression() throws Exception {
        // setup
        String someId = ...;
        // 省略
        
        // exercise
        mvc.perform(get("/endpoint/{id}", someId)
            // verify
            .andExpect(status().isOk()); // なぜか406が帰ってくる
    }

ContentNegotiationManager周りに変更が入っているので、以下のコードを追加しました。

   @Before
    public void setUp() {
+       ContentNegotiationManagerFactoryBean factoryBean =
+           new ContentNegotiationManagerFactoryBean();
+       factoryBean.setFavorPathExtension(false); // この辺の設定はWebMvcの設定で使ってるやつ
+       factoryBean.afterPropertiesSet();
        this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
+           .setContentNegotiationManager(factoryBean.build())
            .setMessageConverters(httpMessageConverter());
    }

    @Test
    public void testGetMailSuppression() throws Exception {
        // setup
        String someId = ...;
        // 省略
        
        // exercise
        mvc.perform(get("/endpoint/{id}", someId)
            // verify
            .andExpect(status().isOk()); // なぜか406が帰ってくる
    }

まとめ

よく分からず、適当なコードを書いたら直ってしまった回・・・ 挙動の違いはまた今度見てみます。

この辺が影響してそう。

Spring Boot 1.5.x を使っているプロジェクトでSpring Bootを2系にしたら @Scheduledが動かないことがある

Spring Boot 1.5.xでは動いていた @Scheduledをつけた定期処理が Spring Boot 2.xでは動かないことがあります。

EnableSchedulingを自分のアプリケーションのConfigurationクラスにつけてください。 どこにもつけてないんだと思います。

ちょっとハマったよ。

余談

じゃあ、元々なんで動いてたの?

以前はここについてた。ちなみに2.x系で対応するクラスを見つけられなかった。 spring-boot/MetricExportAutoConfiguration.java at v1.5.17.RELEASE · spring-projects/spring-boot · GitHub

Jackson 2.9からupdateValue/readerForUpdatingでデータのマージがされる

こんにちは。紅葉の季節ですね。 最近寒くて辛い。Spring Bootのアップデートもうまくいってなくて辛い。

今日も今日とて、アップデートでハマったメモを書きます。

ObjectMapper#readerForUpdatingを使っているあなた。気をつけましょう。

あるキーに対して、上記APIを使ってアップデートをかけた場合にCollection, Mapの場合 2.9からマージされるようになったようです。

以下のミニマムなケースがバージョン前後で非互換性を生むことになります。 安易に使用してはいけません。もちろん。

public class JacksonTest {
    
    @Test
    public void test() throws IOException {
        // setup: map
        HashMap<String, Object> map = new HashMap<>();
        ArrayList<String> list = new ArrayList<>();
        list.add("test");
        map.put("key", list);
        
        // setup: otherMap
        HashMap<String, Object> otherMap = new HashMap<>();
        otherMap.put("key", Collections.singletonList("test"));
        
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode jsonNode = objectMapper.valueToTree(otherMap);
        objectMapper.readerForUpdating(map)
            .readValue(jsonNode);
        
        // jackson 2.9から、同じキーの値はマージされる。
        JsonAssert.with(objectMapper.writeValueAsString(map))
            .assertEquals("$.key.size()", 2); // 2.8だとこのアサーションが落ちる。
    }
}

終わりに

気をつけましょう。 自分で調べた限りだと、この挙動は現状設定で対処出来ない部分です。アノテーションでも解決不可です。 ObjectMapper.setDefaultMergeableを使えば回避できそうです。 お疲れ様でした。コードを修正しましょう。

Jacksonの層でHackするのは辞めてほしい。