1

I have a DTO class that should serve json via a spring-mvc @RestController.

I want to provide different version/views on the same object. Especially, there are fields that are only used in VERSION_1 of the api, and some only in VERSION_2.

Problem: I could add @JsonView for this, but my goal is also to rename those fields. Some fields should actually replace the same name from previous versions.

Example:

public class Person {
    @JsonView(View.Version_1.class)
    @JsonProperty("name")
    private String name; //eg only the firstname

    @JsonView(View.Version_2.class)
    @JsonProperty("name")
    private NameDTO namedto; //now changing to first+last name

    static class NameDTO {
       private String firstname;
       private String lastname;
    }
}

@RestController 
public class MyServlet {
    @GetMapping("/person/{id}")
    @JsonView(View.Version_1.class)
    public PersonDTO person1(int id) {
        //...
    }

    @GetMapping("/person_new/{id}")
    @JsonView(View.Version_2.class)
    public PersonDTO person2(int id) {
        //...
    }
}

So, depending on the view/version, you would get the same json field firstname, but with different content.

In this example, using V1 would give:

{"name": "john"}

Whereas using V2 should result in:

{"name": {"firstname": "john", "lastname": "doe"}}

BUT not with he code above, as jackson complains:

com.fasterxml.jackson.databind.JsonMappingException: Conflicting getter definitions for property "name".

Is that possible at all?

membersound
  • 81,582
  • 193
  • 585
  • 1,120

1 Answers1

0

I found a way using: https://github.com/jonpeterson/spring-webmvc-model-versioning

Basic idea is to add a custom VersionedModelConverter that is applied on @VersionedModelConverter annotated webservice response classes.

@Configuration
@Import(VersionedModelResponseBodyAdvice.class)
public class SpringMvcVersioningConfiguration {
   //register in jackson. spring-boot automatically registers any module beans
   @Bean
   public Model versioningModel() {
       return new VersioningModule();
   }
}

@GetMapping
@VersionedResponseBody(defaultVersion = "2.0")
public Person person() {
}

@JsonVersionedModel(currentVersion = "3.0"  toPastConverterClass = PersonConverter.class)
public class Person {
}

public class PersonConverter implements VersionedModelConverter {
    @Override
    public ObjectNode convert(ObjectNode modelData, String modelVersion, String targetModelVersion, JsonNodeFactory nodeFactory) {
        Double modelv = Double.valueOf(modelVersion);
        Double targetv = Double.valueOf(targetVersion);
        //todo if-else based on model version

        Object node = modelData.remove("fieldname");
        //node.change...
        modelData.set("fieldname_renamed", node);
    }
}
membersound
  • 81,582
  • 193
  • 585
  • 1,120