Java将对象转换为抽象对象



我使用的是Java 1.8的SpringBoot。

我有两个对象,我想深度复制一个到另一个。

QuoteRequestDTO -> TravelRequirementDTO -> ItineraryDTO -> ServiceDTO

QuoteRequest -> TravelRequirement -> Itinerary -> Service

注意:实体对象来自一个我不能改变的外部库。我可以更改DTO对象。

例如,我想复制一个DTO到一个Entity

DTO

public class QuoteRequestDTO {    
protected TravelRequirementDTO travel;
...

public class TravelRequirementDTO {
protected ItineraryDTO required;
...

public class ItineraryDTO extends PayableDTO {
protected List<ServiceDTO> service;
...

public class ServiceDTO extends PayableDTO {
...

实体

public class QuoteRequest {
protected TravelRequirement travel;
...

public class TravelRequirement implements Serializable {
private static final long serialVersionUID = 1L;
protected Itinerary required;
...

public class Itinerary extends Payable implements Serializable {
private static final long serialVersionUID = 1L;
protected List<Service> service;
...

public abstract class Service extends Payable implements Serializable {
private static final long serialVersionUID = 1L;
...
<<p>

复制效用/strong>我已经试过了:

import com.fasterxml.jackson.databind.ObjectMapper;
public class CopyUtils {
public static <T>T deepCopy(Object sourceObject, T targetObject) {
ObjectMapper mapper = getJacksonObjectMapper();
T targetBean = (T) mapper.convertValue(sourceObject, targetObject.getClass());
return targetBean;
}
private static ObjectMapper getJacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return objectMapper;
}
}

用法:

public void getQuote(QuoteRequestDTO quoteRequestDTO) {
QuoteRequest quoteRequest = new QuoteRequest();
quoteRequest = CopyUtils.deepCopy(quoteRequestDTO, quoteRequest);
误差

得到以下错误:

无法构建com.mycompany.transit._2008a.Service的实例(不存在像默认构造函数一样的创建者):抽象类型需要映射到具体类型,具有自定义反序列化器,或者在[来源:未知;字节偏移量:#UNKNOWN](通过参考链:com.mycompany.transit._2008a.availability.QuoteRequest["travel"]- " mycompany.transit._2008a. travelrequirement ["required"]->com.mycompany.transit._2008a.Itinerary["service"]->java.util.ArrayList[0])

当我将ServiceDTO更改为摘要时类:

public abstract class ServiceDTO extends PayableDTO implements Serializable {
private static final long serialVersionUID = 1L;

得到以下错误:

com.fasterxml.jackson.databind.exc。InvalidDefinitionException:不能构造com.mycompany.restosgi.dto.transit.ServiceDTO的实例(不存在像默认构造函数一样的创建者):抽象类型需要映射到具体类型,具有自定义反序列化器,或者在[来源:(org.springframework.util.StreamUtils NonClosingInputStream美元);线:13、列:13](通过引用链:com.mycompany.restosgi.dto.transit.availability.QuoteRequestDTO("travel"→com.mycompany.restosgi.dto.transit.TravelRequirementDTO("required"→com.mycompany.restosgi.dto.transit.ItineraryDTO("service"→java.util.ArrayList [0])

是否有一种方法,我可以写一个通用的实用程序方法来深度复制对象到另一个对象,具有抽象对象?

可能的解决方案

是否有一种方法来添加一个转换器,创建相关的具体类(实现)?

Service需要是一个实现,例如TransitService

public class TransitService extends Service implements Serializable {
private static final long serialVersionUID = 1L;

可能的解决方案

根据以下Delta George的建议,我正在尝试以下方法:

public class ItineraryDTO extends PayableDTO {
protected List<ServiceDTO> service;
@JsonAnySetter
public void serService(String key, ArrayNode array) {
service = new ArrayList<>();
array.forEach(json -> service.add(toService(json)));
}
private ServiceDTO toService(JsonNode json) {
if (json.has("some unique property of flight")) {
return new ObjectMapper().convertValue(json, FlightDTO.class);
} else if (json.has("some unique property of transit")) {
return new ObjectMapper().convertValue(json, TransitServiceDTO.class);
} else return null;
}
...

但是,我不能让它调用serService方法。我想我需要添加一些Spring配置这样做吗?

同样,如果我使ServiceDTO抽象,它得到以下错误:

public abstract class ServiceDTO extends PayableDTO {

com.fasterxml.jackson.databind.exc。InvalidDefinitionException:不能构造com.clubtravel.restosgi.dto.transit.ServiceDTO的实例(不存在像默认构造函数一样的创建者):抽象类型需要映射到具体类型,具有自定义反序列化器,或者在[来源:(org.springframework.util.StreamUtils NonClosingInputStream美元);线:13、列:13](通过引用链:com.clubtravel.restosgi.dto.transit.availability.QuoteRequestDTO("travel"→com.clubtravel.restosgi.dto.transit.TravelRequirementDTO("required"→com.clubtravel.restosgi.dto.transit.ItineraryDTO("service"→java.util.ArrayList [0])在com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from (InvalidDefinitionException.java: 67)~ (jackson-databind-2.13.2.1.jar 2.13.2.1):

使用Jackson的@JsonAnySetter拦截传入对象作为JSON树数组,并根据每个对象的结构将每个对象转换为具体的POJO的概念实现:

@Data
@NoArgsConstructor
static abstract class Person {
}
@Data
@NoArgsConstructor
static class PersonA extends Person {
String a;
}
@Data
@NoArgsConstructor
static class PersonB extends Person {
String b;
}
@NoArgsConstructor
@ToString
static class People {
List<Person> team;
@JsonAnySetter
public void setTeam(String key, ArrayNode array) {
team = new ArrayList<>();
array.forEach(json -> team.add(toPerson(json)));
}
private Person toPerson(JsonNode json) {
if (json.has("a")) {
return new ObjectMapper().convertValue(json, PersonA.class);
} else if (json.has("b")) {
return new ObjectMapper().convertValue(json, PersonB.class);
} else return null;
}
}
public static void main(String[] args) throws JsonProcessingException {
String json = "{"team": [{"a": 123}, {"b": 45}]}";
People people = new ObjectMapper().readValue(json, People.class);
System.out.println(people);
// Prints: People(team=[PersonA(a=123), PersonB(b=45)])
}
// back to the OP's data model
public static class QuoteRequest {
protected TravelRequirement travel;
public TravelRequirement getTravel() {
return travel;
}
public void setTravel(TravelRequirement travel) {
this.travel = travel;
}
}
public static class TravelRequirement implements Serializable {
private static final long serialVersionUID = 1L;
protected Itinerary required;
public Itinerary getRequired() {
return required;
}
public void setRequired(Itinerary required) {
this.required = required;
}
}
public static class Itinerary extends Payable implements Serializable {
private static final long serialVersionUID = 1L;
protected List<Service> service;
public void service(List<Service> service) {
this.service = service;
}
@JsonAnyGetter
public Map<String, Object> getService() {
return Map.of("service", service);
}
@JsonAnySetter
public void setService(String key, ArrayNode array) {
service = new ArrayList<>();
array.forEach(json -> service.add(toService(json)));
}
private Service toService(JsonNode json) {
return getJacksonObjectMapper().convertValue(json, TransitService.class);
}
}
public static abstract class Service extends Payable implements Serializable {
private static final long serialVersionUID = 1L;
}
public static class TransitService extends Service implements Serializable {
private static final long serialVersionUID = 1L;
}
public static class Payable implements Serializable {
private static final long serialVersionUID = 1L;
}
private static ObjectMapper getJacksonObjectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();
objectMapper.configure(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
return objectMapper;
}
public static void main(String[] args) throws JsonProcessingException {
QuoteRequest qr = new QuoteRequest();
TravelRequirement tr = new TravelRequirement();
Itinerary i = new Itinerary();
i.service(List.of(new TransitService()));
tr.setRequired(i);
qr.setTravel(tr);
ObjectMapper mapper = getJacksonObjectMapper();
QuoteRequest qr2 = mapper.convertValue(qr, QuoteRequest.class);
System.out.println(qr2);
}

相关内容

  • 没有找到相关文章

最新更新