如何将@JsonView与@JsonProperty结合起来?

时间:2018-03-08 15:00:16

标签: json spring-mvc jackson

我有一个DTO课程,应该通过json spring-mvc提供@RestController

我想在同一个对象上提供不同的版本/视图。特别是,有些字段仅在api的VERSION_1中使用,有些仅在VERSION_2中使用。

问题:我可以为此添加@JsonView,但我的目标也是重命名这些字段。某些字段实际上应该替换与先前版本相同的名称。

示例:

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) {
        //...
    }
}

因此,根据视图/版本,您将获得相同的json字段firstname,但内容不同。

在此示例中,使用V1将给出:

{"name": "john"}

使用V2应该导致:

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

但不是他上面的代码,杰克逊抱怨道:

  

com.fasterxml.jackson.databind.JsonMappingException:冲突   属性的getter定义" name"。

这可能吗?

1 个答案:

答案 0 :(得分:0)

我找到了一种方法: https://github.com/jonpeterson/spring-webmvc-model-versioning

基本思想是添加一个应用于VersionedModelConverter带注释的Web服务响应类的自定义@VersionedModelConverter

@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);
    }
}