如何在 Spring Boot 中为 RestTemplate 设置 PropertyNamingStrategy?
How to set PropertyNamingStrategy for RestTemplate in SpringBoot?
我编写了一个 SpringBoot 应用程序,它消耗一个休息 api 并提供一个休息 api。我的模型 pojo 有驼峰命名的属性。应用使用的 json 具有 under_score 属性 个名称。该应用生成的 json 具有 under_score 属性 个名称。我想使用一个 PropertyNamingStrategy,它将在 marshalling/unmarshalling 期间自动在 Java 和 json 名称之间进行转换。
我有 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 应该可以提供帮助。有没有一种方法可以设置 RestTemplate 将使用的 PropertyNamingStrategy 将传入的 json 名称从 under_score 转换为驼峰命名法?
感谢您的帮助。
创建 RestTemplate
时,您需要将 objectMapper
设置为您的。
此外,您应该将您的自定义 ObjectMapper 声明为 @Bean
,以便它由 Spring 构造为单例并为您管理。对 PropertyNamingStrategy
执行相同的操作,而不是 'newing' 并将 class 声明为静态。
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;
}
}
而您的 class 位于单独的文件中?它不需要是静态的。
/**
* 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();
}
}
一个更简短的答案是使用 Spring 的 objectMapper。好处是它在 application.properties
中共享相同的配置。因此,您可以设置 spring.jackson.property-naming-strategy=SNAKE_CASE
或其他任何设置,并且它在包括 RestTemplate 在内的整个应用程序中都是一致的。代码如下
@Configuration
@RequiredArgsConstructor
public class HTTPConfig {
public final ObjectMapper objectMapper; // provided by spring
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
.messageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
.build();
}
}
只需在您将在请求响应中发送或接收的 POJO 上方添加此注释。
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
P.S。该策略可以根据要求而有所不同。
我建议你使用这个方法。您也可以将其添加为 spring bean。
private RestTemplate getRestTemplate() {
final RestTemplate restTemplate = new RestTemplate();
final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
final MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE));
messageConverters.add(jsonMessageConverter);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
我编写了一个 SpringBoot 应用程序,它消耗一个休息 api 并提供一个休息 api。我的模型 pojo 有驼峰命名的属性。应用使用的 json 具有 under_score 属性 个名称。该应用生成的 json 具有 under_score 属性 个名称。我想使用一个 PropertyNamingStrategy,它将在 marshalling/unmarshalling 期间自动在 Java 和 json 名称之间进行转换。
我有 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 应该可以提供帮助。有没有一种方法可以设置 RestTemplate 将使用的 PropertyNamingStrategy 将传入的 json 名称从 under_score 转换为驼峰命名法?
感谢您的帮助。
创建 RestTemplate
时,您需要将 objectMapper
设置为您的。
此外,您应该将您的自定义 ObjectMapper 声明为 @Bean
,以便它由 Spring 构造为单例并为您管理。对 PropertyNamingStrategy
执行相同的操作,而不是 'newing' 并将 class 声明为静态。
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;
}
}
而您的 class 位于单独的文件中?它不需要是静态的。
/**
* 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();
}
}
一个更简短的答案是使用 Spring 的 objectMapper。好处是它在 application.properties
中共享相同的配置。因此,您可以设置 spring.jackson.property-naming-strategy=SNAKE_CASE
或其他任何设置,并且它在包括 RestTemplate 在内的整个应用程序中都是一致的。代码如下
@Configuration
@RequiredArgsConstructor
public class HTTPConfig {
public final ObjectMapper objectMapper; // provided by spring
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
.messageConverters(new MappingJackson2HttpMessageConverter(objectMapper))
.build();
}
}
只需在您将在请求响应中发送或接收的 POJO 上方添加此注释。
@JsonNaming(PropertyNamingStrategy.UpperCamelCaseStrategy.class)
P.S。该策略可以根据要求而有所不同。
我建议你使用这个方法。您也可以将其添加为 spring bean。
private RestTemplate getRestTemplate() {
final RestTemplate restTemplate = new RestTemplate();
final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
final MappingJackson2HttpMessageConverter jsonMessageConverter = new MappingJackson2HttpMessageConverter();
jsonMessageConverter.setObjectMapper(new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE));
messageConverters.add(jsonMessageConverter);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}