Search code examples
javajsonspring-bootjacksonresttemplate

How to have different @JsonProperty based on environment in spring boot


I have a class which is used as a request to hit another service.

It has few fields like below.

public class RequestClass {

  @JsonProperty("123")
  private String name;

  @JsonProperty("124")
  private String email;

  @JsonProperty("129")
  private String mobile;

}

The upstream service requires the request with field id like 123, 124, 129,etc.

These field id will be different for test and production environment.

Is there any better way to do it other than having different RequestClass?


Solution

  • You could create a config class where you keep track of the actual id according to your environment and map them using jackson's @JsonAnyGetter.

    So for example if you have the following application.properties (I'm using multi-document props here, but you could also have application.properties per profile):

    spring.profiles.active=dev
    #---
    spring.config.activate.on-profile=dev
    application.requestClass.nameId=123
    #---
    spring.config.activate.on-profile=test
    application.requestClass.nameId=456
    

    Then, you'd create your config class (I'm using Lombok's @Data for getter/setters):

    @Configuration
    @Data
    public class RequestClassConfig {
    
        @Value("${application.requestClass.nameId}")
        private String nameId;
    
        @PostConstruct
        public void postConstruct() {
            RequestClass.config = this;
        }
    }
    

    and finally your DTO with @JsonAnyGetter:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class RequestClass {
    
        public static RequestClassConfig config;
    
        @JsonIgnore
        private String name;
    
        @JsonAnyGetter
        public Map<String, Object> any() {
            final var map = new HashMap<String, Object>();
    
            map.put(config.getNameId(), this.name);
            return map;
        }
    
    }
    

    Note that you can do the same for the remaining props, I've just omitted those for brevity.

    Now for a quick test run:

    @SpringBootApplication
    public class App {
    
        public static void main(String[] args) throws JsonProcessingException {
            SpringApplication.run(App.class, args);
            final var mapper = new ObjectMapper();
            final var req = new RequestClass();
            req.setName("test");
    
            System.out.println(mapper.writeValueAsString(req));
        }
    
    }
    

    This will print {"123":"test"} to the console if the dev profile is active and {"456":"test"} if the test profile is active.