public static String convertToSnakeCaseIfSupported(String name, Class<?> specType) { RosettaNaming rosettaNaming = getAnnotation(specType, RosettaNaming.class); boolean snakeCasing = rosettaNaming != null && (rosettaNaming.value().equals(LowerCaseWithUnderscoresStrategy.class) || rosettaNaming.value().equals(SnakeCaseStrategy.class)); if (snakeCasing && !name.contains("_")) { return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name); } return name; }
@Test public void customPropertyNamingStrategyField() throws Exception { this.context.register(JacksonAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.jackson.property-naming-strategy:CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES"); this.context.refresh(); ObjectMapper mapper = this.context.getBean(ObjectMapper.class); assertThat(mapper.getPropertyNamingStrategy(), is(instanceOf(LowerCaseWithUnderscoresStrategy.class))); }
@Test public void customPropertyNamingStrategyClass() throws Exception { this.context.register(JacksonAutoConfiguration.class); EnvironmentTestUtils.addEnvironment(this.context, "spring.jackson.property-naming-strategy:com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy"); this.context.refresh(); ObjectMapper mapper = this.context.getBean(ObjectMapper.class); assertThat(mapper.getPropertyNamingStrategy(), is(instanceOf(LowerCaseWithUnderscoresStrategy.class))); }
/** * Creates client applying default configuration and then customizations. Example: * <pre> * {@code * new FeignClient(apiUrl, builder -> builder.requestInterceptor(template -> * template.header("Authorization", "bearer " + token))); * } * </pre> * @param url endpoint url * @param customizations custom configuration that should be applied after defaults */ public FeignClient(String url, Function<Builder, Builder> customizations) { Objects.requireNonNull(url); Objects.requireNonNull(customizations); final ObjectMapper mapper = new ObjectMapper(); mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); mapper.setPropertyNamingStrategy(new LowerCaseWithUnderscoresStrategy()); // avoid duplication of slashes final String targetUrl = StringUtils.removeEnd(url, "/"); // first applies defaults and then custom configuration final Builder builder = customizations.apply(Feign.builder() .encoder(new JacksonEncoder()) .decoder(new JacksonDecoder(mapper)) .options(new Request.Options(CONNECT_TIMEOUT, READ_TIMEOUT)) .logger(new ScramblingSlf4jLogger(FeignClient.class)) .logLevel(feign.Logger.Level.BASIC) .errorDecoder(new CompositeErrorDecoder(new FeignErrorDecoderHandler("description")))); this.applicationResource = builder.target(CcApplicationResource.class, targetUrl); this.organizationResource = builder.target(CcOrganizationResource.class, targetUrl); this.serviceResource = builder.target(CcServiceResource.class, targetUrl); this.serviceBindingResource = builder.target(CcServiceBindingResource.class, targetUrl); this.spaceResource = builder.target(CcSpaceResource.class, targetUrl); this.userResource = builder.target(CcUserResource.class, targetUrl); this.buildpackResource = builder.target(CcBuildpacksResource.class, targetUrl); this.quotaResource = builder.target(CcQuotaResource.class, targetUrl); }
@Bean public ObjectMapper objectMapper() { return new ObjectMapper() .setPropertyNamingStrategy(new LowerCaseWithUnderscoresStrategy()) .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); }