2016-03-18 1 views
4

Я написал приложение SpringBoot, которое потребляет апию отдыха и представляет отдых api. У моей модели pojo есть свойства camelCase. Json, который использует приложение, имеет имена свойств under_score. Json, созданный приложением, имеет имена свойств under_score. Я хотел бы использовать PropertyNamingStrategy, который будет автоматически конвертировать между именами Java и json во время сортировки/отмены сортировки.Как установить PropertyNamingStrategy для RestTemplate в SpringBoot?

У меня есть конфигурация 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 POJO, чтобы JSon для ответа. Однако, когда я потребляю rest api, через RestTemplate, я не вижу, чтобы это вызывалось, и мои возникающие 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

Спасибо за ответ. Я реализовал это, но он все еще не работает. Когда я удаляю аннотации @JsonProperty в своих pojos, я все еще вижу, что только свойства с простыми именами, такие как «описание», заполняются при вызове отдыха. Если я установил точку останова в экземпляре UpperCaseUnderscoreStrategy.translate(), он никогда не останавливается на достигнутом, поэтому ясно, что шаблон останова не вызывает его. – Ezward

+0

Я могу видеть, когда отладчик выбирает MappingJackson2HttpMessageConverter из списка messageConverters. Я проследил дальше в ObjectMapper, и я вижу, что DeserializationConfig, возвращаемый ObjectMapper.getDeserializationConfig(), имеет значение _propertyNameStrategy null, поэтому все, что мы сделали до сих пор, не попало в конвейер десериализации. – Ezward

+0

Хорошо, я понял это. Ваш ответ был очень полезным. Я узнал, что мой код низкого уровня обновлял RestTemplate для каждого вызова, поэтому сконфигурированный шаблон был проигнорирован. Как только я изменил autowire остальной шаблон на мой низкий уровень, все сработало. Теперь я вижу, что метод translate() называется ожидаемым. Спасибо за вашу помощь. – Ezward