2016-03-18 42 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

相关问题