2016-03-18 39 views
4

我寫了一個SpringBoot應用程序,它會消耗一個休息api並呈現一個休息api。我的模型pojo的有camelCase命名的屬性。應用程序使用的json具有under_score屬性名稱。該應用產生的json具有under_score屬性名稱。我想使用PropertyNamingStrategy,它將在編組/解組期間自動在Java和json名稱之間進行轉換。如何在SpringBoot中爲RestTemplate設置PropertyNamingStrategy?

我有Java配置,試圖設置一個命名策略,可以處理這個;

/** 
* Configuration for Rest api. 
* <p> 
* Created by emurphy on 2/25/16. 
*/ 
@Configuration 
    public class RestConfig 
    { 
     /** 
     * Bean to make jackson automatically convert from 
     * camelCase (java) to under_scores (json) in property names 
     * 
     * @return ObjectMapper that maps from Java camelCase to json under_score names 
     */ 
     @Bean 
     public ObjectMapper jacksonObjectMapper() 
     { 
      return new ObjectMapper().setPropertyNamingStrategy(new UpperCaseUnderscoreStrategy()); 
     } 

     /** 
     * Property naming strategy that converts both ways between camelCase and under_score 
     * property names. 
     */ 
     public static class UpperCaseUnderscoreStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase 
     { 
      /** 
      * Converts camelCase to under_score and 
      * visa versa. The idea is that this 
      * name strategy can be used for both 
      * marshalling and unmarshaling. 
      * 
      * For example, "userName" would be converted to 
      * "user_name" and conversely "user_name" would 
      * be converted to "userName". 
      * 
      * @param input formatted as camelCase or under_score string 
      * @return input converted to opposite format 
      */ 
      @Override 
      public String translate(String input) 
      { 
       if (input == null || input.length() == 0) 
       { 
        return input; // garbage in, garbage out 
       } 

       // 
       // we always take the first character; 
       // this preserves initial underscore 
       // 
       StringBuilder sb = new StringBuilder(); 

       final int length = input.length(); 
       int i = 0; 

       // 
       // skip initial underscores 
       // 
       while ((i < length) && ('_' == input.charAt(i))) 
       { 
        sb.append(input.charAt(i)); 
        i += 1; 
       } 

       while (i < length) 
       { 
        // 
        // find underscores, remove and capitalize next letter 
        // 
        while ((i < length) && ('_' != input.charAt(i)) && !Character.isUpperCase(input.charAt(i))) 
        { 
         sb.append(input.charAt(i)); 
         i += 1; 
        } 

        if(i < length) 
        { 
         if('_' == input.charAt(i)) 
         { 
          // underscore to uppercase 

          // 
          // skip underscores 
          // 
          while ((i < length) && ('_' == input.charAt(i))) 
          { 
           // skip underscores 
           i += 1; 
          } 

          // 
          // capitalize 
          // 
          if (i < length) 
          { 
           sb.append(Character.toUpperCase(input.charAt(i))); 
           i += 1; 
          } 
         } 
         else // uppercase to unscore + lowercase 
         { 
          sb.append('_'); 
          sb.append(Character.toLowerCase(input.charAt(i))); 
          i += 1; 
         } 
        } 
       } 
       return sb.toString(); 
      } 
     } 

當我的休息服務將Java pojos轉換爲json響應時,我可以看到命名策略的翻譯方法。但是,當我通過RestTemplate使用rest api時,我沒有看到這個被調用,並且我的結果pojos沒有從傳入的json正確初始化;所有名稱需要翻譯的屬性都是空的。這迫使我在大多數屬性上使用@JsonProperty。我有很多屬性和很多pojos - 這是SpringBoot應該幫助的非常不雅的樣板解決方案。有沒有一種方法可以設置PropertyNamingStrategy,RestTemplate將用來將傳入的json名稱從under_score轉換爲camelCase?

感謝您的幫助。

+0

什麼是你的配置類的頂部註釋? – pczeus

+0

對不起,我已經更新了問題中的代碼。基本上在配置。我的主要配置是在另一個文件中,並具有At SpringBootApplication註釋。 – Ezward

回答

4

創建RestTemplate時,您需要將objectMapper設置爲您的。 此外,你應該聲明你的自定義ObjectMapper爲@Bean,所以它由Spring構建爲單例併爲你管理。對PropertyNamingStrategy做同樣的事情,而不是「新建」它並將該類聲明爲靜態。

public class RestConfig 
{ 
    /** 
    * Bean to make jackson automatically convert from 
    * camelCase (java) to under_scores (json) in property names 
    * 
    * @return ObjectMapper that maps from Java camelCase to json under_score names 
    */ 
    @Bean 
    public ObjectMapper jacksonObjectMapper() 
    { 
     return new ObjectMapper().setPropertyNamingStrategy(propertyNamingStrategy()); 
    } 

    @Bean 
    public PropertyNamingStrategy propertyNamingStrategy() 
    { 
     return new UpperCaseUnderscoreStrategy(); 
    } 

    @Bean 
    public RestTemplate restTemplate() { 
     RestTemplate restTemplate = new RestTemplate(); 
     List<HttpMessageConverter<?>> messageConverters = new ArrayList<>(); 
     MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter(); 
     jsonMessageConverter.setObjectMapper(jacksonObjectMapper()); 
     messageConverters.add(jsonMessageConverter); 
     restTemplate.setMessageConverters(messageConverters); 

     return restTemplate; 
    } 
} 

而你的課是在一個單獨的文件?它不需要是靜態的。

/** 
    * Property naming strategy that converts both ways between camelCase and under_score 
    * property names. 
    */ 
    public static class UpperCaseUnderscoreStrategy extends PropertyNamingStrategy.PropertyNamingStrategyBase 
    { 
     /** 
     * Converts camelCase to under_score and 
     * visa versa. The idea is that this 
     * name strategy can be used for both 
     * marshalling and unmarshaling. 
     * 
     * For example, "userName" would be converted to 
     * "user_name" and conversely "user_name" would 
     * be converted to "userName". 
     * 
     * @param input formatted as camelCase or under_score string 
     * @return input converted to opposite format 
     */ 
     @Override 
     public String translate(String input) 
     { 
      if (input == null || input.length() == 0) 
      { 
       return input; // garbage in, garbage out 
      } 

      // 
      // we always take the first character; 
      // this preserves initial underscore 
      // 
      StringBuilder sb = new StringBuilder(); 

      final int length = input.length(); 
      int i = 0; 

      // 
      // skip initial underscores 
      // 
      while ((i < length) && ('_' == input.charAt(i))) 
      { 
       sb.append(input.charAt(i)); 
       i += 1; 
      } 

      while (i < length) 
      { 
       // 
       // find underscores, remove and capitalize next letter 
       // 
       while ((i < length) && ('_' != input.charAt(i)) && !Character.isUpperCase(input.charAt(i))) 
       { 
        sb.append(input.charAt(i)); 
        i += 1; 
       } 

       if(i < length) 
       { 
        if('_' == input.charAt(i)) 
        { 
         // underscore to uppercase 

         // 
         // skip underscores 
         // 
         while ((i < length) && ('_' == input.charAt(i))) 
         { 
          // skip underscores 
          i += 1; 
         } 

         // 
         // capitalize 
         // 
         if (i < length) 
         { 
          sb.append(Character.toUpperCase(input.charAt(i))); 
          i += 1; 
         } 
        } 
        else // uppercase to unscore + lowercase 
        { 
         sb.append('_'); 
         sb.append(Character.toLowerCase(input.charAt(i))); 
         i += 1; 
        } 
       } 
      } 
      return sb.toString(); 
     } 
    } 
+0

感謝您的回覆。我已經實現了這個,但它仍然不起作用。當我在pojos中刪除@JsonProperty註釋時,我仍然可以看到只有名稱簡單的屬性(如「description」)纔會在我進行其他調用時填充。如果我在UpperCaseUnderscoreStrategy.translate()的實例中設置了一個斷點,它永遠不會停在那裏,所以很明顯剩下的模板沒有調用它。 – Ezward

+0

我可以在調試時看到從messageConverters列表中選擇了MappingJackson2HttpMessageConverter。我追溯到了ObjectMapper,我可以看到ObjectMapper.getDeserializationConfig()返回的DeserializationConfig的_propertyNameStrategy值爲null,所以我們迄今爲止所做的任何操作都沒有進入反序列化管道。 – Ezward

+0

好的,我已經弄明白了。你的回答非常有幫助。我發現我的低級代碼在每次調用時都會新建一個RestTemplate,所以配置的模板被忽略。一旦我改變自動將其餘模板自動裝入我的低級別,一切都奏效了。現在我看到translate()方法按預期方式被調用。謝謝你的幫助。 – Ezward

相關問題