java - Java - 在DTO中,动态字段类型

我使用Spring-MVC,并且有一个类似于下面的mtf来接收来自客户端(一个foo实体)的JSON数据,以便将它保存到JPA中:


public class FooDTO {



 public Integer id;


 public String label;


 public Double amount;


 public List<Integer> states;


 ...



但是,当客户端想要编辑foo实体时,我必须像下面那样构造它,


public class FooDTO {



 public Integer id;


 public String label;


 public Double amount;


 public List<SimpleDto> states;


 ...



使用SimpleDto


public class SimpleDto {


 public Integer value;


 public String label;


}



差异只是states类型,有时是List<SimpleDto>,有时是List<Integer>我不想创建另一个dto。

那么如何在我的dto(json)中实现动态字段类型?

P.S JSON数据由com.fasterxml.jackson.core处理

时间:

在DTO类型中使用spring类型转换器,这样客户机可以发布一个stateId,转换器将解析给定ID的正确DTO类型。

下面是一个例子:https://www.baeldung.com/spring-type-conversions

我建议不要添加另一个促进重复的DTO。然而,你仍然需要添加另一个将专用于你自己的服务,你只需使用层次结构来定义DTO 。


public class FooDTO {



 public Integer id;


 public String label;


 public Double amount;


}



通过扩展通用细节DTO来定义响应DTO,以提供详细信息,例如,FooDTO如下所示:


public class FooDetailsOutDTO extends FooDTO {



 public List<Integer> states;



}



如需编辑,您可以按如下方式定义DTO,


public class FooUpdateDetailsInDTO extends FooDTO {



 public List<SimpleDto> states;



}



可以将jsonCreator注释和两个构造函数用于项POJO ,如果数组1-arg构造函数中存在基元,则使用,如果有完全设置对象2-arg构造函数,将使用,请参见下面的示例:


import com.fasterxml.jackson.annotation.JsonCreator;


import com.fasterxml.jackson.annotation.JsonCreator.Mode;


import com.fasterxml.jackson.annotation.JsonProperty;


import com.fasterxml.jackson.databind.ObjectMapper;


import java.util.List;



public class JsonApp {



 public static void main(String[] args) throws Exception {


 String json ="{"id":1,"label":"LABEL","amount":1.23,"states":[1,{"value":2},{"value":3,"label":"LAB"}]}";


 ObjectMapper mapper = new ObjectMapper();



 Foo foo = mapper.readValue(json, Foo.class);


 System.out.println(foo);


 }


}



class Foo {



 private Integer id;


 private String label;


 private Double amount;


 private List<State> states;



 // getters, setters, toString


}



class State {



 private Integer value;


 private String label;



 @JsonCreator(mode = Mode.DELEGATING)


 public State(@JsonProperty("value") Integer value) {


 this(value, null);


 }



 @JsonCreator


 public State(@JsonProperty("value") Integer value, @JsonProperty("label") String label) {


 this.value = value;


 this.label = label;


 }



 // getters, setters, toString


}



上面的代码打印:


Foo{id=1, label='LABEL', amount=1.23, states=[State{value=1, label='null'}, State{value=2, label='null'}, State{value=3, label='LAB'}]}



使用的版本:2.9.8

另一种建模方法:


 public class FooDTO {



 public Integer id;


 public String label;


 public Double amount;


 //not null!


 public List<Integer> states;


 //nullable!!


 ... List<String> stateLabels;


 // you should ensure"stable/consistent index/ordering" (relative to states)


 ...



...并因此,将此用于"get "(单独访问标签)和"post "(省略标签;)

‐------------------------‐-----

更重要的是:


 Map<Integer, String> states; // !?



你可以只在SimpleDto中添加返回整数的getter

使用简单的java流在FooDTO中添加返回List<Integer>的getter,该流使用DTO getter映射到整数,


states.stream().map(SimpleDto::getValue).collect(Collectors.toList());



编写dto


public class FooDTO {



 public Integer id;


 public String label;


 public Double amount;


 public List<Object> states;


}



使你的DTO在服务类中扮演角色,并且处理异常

使用自定义deserialier是解决问题的一种方法


 public class DynamicDeserializer extends JsonDeserializer {


 @Override


 public Object deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {


 String requestString = jp.readValueAsTree().toString();


 JSONArray jo = new JSONArray(requestString);


 List<SimpleDto> simpleDtoList = new ArrayList<>();


 List<Integer> integers = new ArrayList<>();


 if(jo!=null && jo.length()>0) {


 for (int i = 0; i < jo.length(); i++) {


 Object string = jo.get(0);


 if(string!=null && string instanceof JSONObject){


 JSONObject value = jo.getJSONObject(i);


 SimpleDto simpleDto = new SimpleDto();


 simpleDto.setValue(value.getInt("value"));


 simpleDtoList.add(simpleDto);


 }else{


 integers.add(jo.getInt(0));


 }


 }


 }



 return integers.isEmpty() ? simpleDtoList:integers;


 }


}



发送和打印请求的控制器


@PostMapping("/test")


 public Optional<TestObject> testDynamicMapper(


 @RequestBody final TestObject testObject) {


 List<Object> states = testObject.getStates();



 for (Object object:states) {


 if(object instanceof SimpleDto){


 SimpleDto dto = (SimpleDto)object;


 System.out.println(dto.getValue());


 }


 if(object instanceof Integer){


 Integer dto = (Integer)object;


 System.out.println(dto);


 }


 }



 return Optional.of(testObject);


 }



generic类,其中有一个通用映射


public class TestObject implements Serializable {



 @JsonDeserialize(using = DynamicDeserializer.class)


 private List<Object> states;



 public List<Object> getStates() {


 return states;


 }



 public void setStates(List<Object> states) {


 this.states = states;


 }



}



对象列表的输入有效载荷


{


"states": [


 {


"label":"1",


"value": 0


 }


 ]


}



整数列表的输入有效负载


{


"states": [


 1,2


 ]


}



你可以使用genericsList<Integer> states更改为List<?> states

...