【问题标题】:Serialization and Deserialization property inconsistencies序列化和反序列化属性不一致
【发布时间】:2021-05-22 04:01:05
【问题描述】:

我有 2 个服务 A服务 B

一些上游正在使用请求示例 json 调用服务 A:

type of given request model class here is ServiceARequest
{
  "A": {
    "pwId": 0,
    "pwType": 0,
    "pwMode": 0 
  },
  "B": "string",
  "C": {
    "ccNum": "string"
    }
}

我需要像这样从服务 A 请求服务 B:

type of given request model class here is ServiceBRequest
{ "CCM": {
    "A": {
    "pwid": 0,
    "pwyype": 0,
    "pwmode": 0 
  },
  "B": "string",
  "C": {
    "ccnum": "string"
    }
  }
}

如您所见,ServiceARequestServiceBRequestma​​pping 字段存在问题,因为某些属性的大小写不同,但它们的类型相同。

那么在这种情况下我该怎么办?我是否需要创建 2 个具有相同名称和不同属性名称的类,然后我需要将它们放在不同的包下,或者如果我对 A、B 和 C 使用相同的类,那么字段名称只能是 pwid pwId

如何进行这种从 ServiceARequest 结构到 ServiceBRequest 的映射 在这里构造然后从 ServiceBResponse 到 ServiceARequest 的逆映射,使用 MapStruct? ServiceBRequest 和 ServiceBResponse 的结构完全相同。

【问题讨论】:

  • 我认为这可能会有所帮助:Mapping Multiple JSON Fields to a Single Java Field
  • @SergeiTonoian,我阅读了博客,但我仍然不清楚,在我的情况下应该如何完成。
  • 我不太了解这与 MapStruct 的关系。你能分享一些yohr pojos / mappers吗
  • @tusharRawat 我已经发布了一个示例如何在您的情况下完成
  • @Filip,我需要以某种方式使用 MapStruct 来定义 Mapper 接口,以便我在内部完成映射,而不是在外部完成。

标签: java spring-boot lombok mapstruct


【解决方案1】:

在 cmets 部分讨论后更新。

我不认为你必须在这里使用 mapstruct。我的意思是你可以,但首先你需要创建你想要映射的 POJO,所以据我所知,它应该是映射到 ServiceBRequest 的 ServiceARequest 类,这就是问题所在。因为两个 POJO 都具有类 A 和 C 的属性,但是 A 和 C 根据父类型具有不同的字段名称,这意味着您必须为 ServiceARequest 定义 A 类,然后为 ServiceBRequest 定义不同版本的 A 类等等。然后映射会非常简单明了,但是你最终会得到一堆结构非常相似的类,所以它看起来不是很好和整洁。

我会以不同的方式处理它。在您的代码中,您可以对 A 和 C 使用相同的类,这没关系。重要的是您的请求的不同 json 结构。所以每当你请求序列化/反序列化时,你必须确保 json 结构是正确的,这意味着你只需要关心序列化/反序列化。而这里@JsonAlias 可以派上用场。

如果我理解正确,您会收到以下 json 进入您的 serviceA:

{
  "A": {
    "pwId": 0,
    "pwType": 0,
    "pwMode": 0 
  },
  "B": "string",
  "C": {
    "ccNum": "string"
    }
}

那个json映射到ServiceARequest类,可以如下实现(注意:所有的类都必须有setter和getter,我只是省略了它们以使代码更短):

public class ServiceARequest {

    @JsonProperty("A")
    private A a;

    @JsonProperty("B")
    private String b;

    @JsonProperty("C")
    private C c;

    //you have to define an empty constructor
    public ServiceARequest() {
    }
}

A 和 C 类:

public class A {

    @JsonProperty("pwid")
    @JsonAlias("pwId")
    private int pwId;

    @JsonProperty("pwtype")
    @JsonAlias("pwType")
    private int pwType;

    @JsonProperty("pwmode")
    @JsonAlias("pwMode")
    private int pwMode;

    public A() {
    }
}

public class C {

    @JsonProperty("ccnum")
    @JsonAlias("ccNum")
    private String ccNum;

    public C() {
    }
}

通过这些注释,您传入的 json 将被映射到 ServiceARequest 完美。然后需要向服务B发送请求,所以需要定义ServiceBRequest类:

public class ServiceBRequest {

    @JsonProperty("CCM")
    private ServiceARequest ccm;

    @JsonCreator
    public ServiceBRequest(@JsonProperty("CCM") ServiceARequest serviceARequest) {
        this.ccm = serviceARequest;
    }
}

然后只需新建一个ServiceBRequest实例,就可以发送给服务B了。下面是测试代码:

ObjectMapper mapper = new ObjectMapper();

//Json from your example mapped to serviceARequest
ServiceARequest serviceARequest = mapper.readValue("{\n" +
                "  \"A\": {\n" +
                "    \"pwId\": 0,\n" +
                "    \"pwType\": 0,\n" +
                "    \"pwMode\": 0 \n" +
                "  },\n" +
                "  \"B\": \"string\",\n" +
                "  \"C\": {\n" +
                "    \"ccNum\": \"string\"\n" +
                "    }\n" +
                "}", ServiceARequest.class);

// create a new instance of serviceBRequest passing serviceARequest as parameter 
// (we need serviceARequest to be a field CCM inside serviceBRequest)
ServiceBRequest serviceBRequest = new ServiceBRequest(serviceARequest);

//map serviceBRequest to json and print
System.out.println(mapper.writeValueAsString(serviceBRequest));

我得到的输出:

{"CCM":{"A":{"pwid":0,"pwtype":0,"pwmode":0},"B":"string","C":{"ccnum":"string"}}}

【讨论】:

  • 我想使用 MapStruct 接口设计模式在内部做映射,而不是使用我自己的 Mapper,那么是否可以使用 MapStruct 做这个映射
  • @tusharRawat 好吧,您要映射的内容还不是很清楚。 MapStruct 将一个类映射到另一个类,那么您要精确映射哪些类?如果从 ServiceARequest 到 ServiceBRequest 并为 A 和 C 使用相同的类,那么我有一个问题 - 为什么?如果 ServiceARequest 和 ServiceBRequest 是您自己的类,为什么它们不能具有相同的结构?假设您将 ServiceARequest 映射到 ServiceBRequest 之后您如何处理 ServiceBRequest?
  • 好的。比如说,我有服务 A 和服务 B 的 API 规范,我不能更改任何人的 API 规范。在 API 规范中,我们得到了两个服务的 json(请求/响应结构),所以如果我想从服务 A 使用服务 B,那么我必须按照服务 B 的 API 合同的给定请求结构发送请求,因此我还需要根据Probelm语句中提到的服务B的Request Json来设计类及其成员变量。
  • 好的,那么我们可以使用 MapStruct 来实现吗?
猜你喜欢
  • 1970-01-01
  • 2021-05-26
  • 1970-01-01
  • 2017-12-09
  • 2013-10-09
  • 2014-05-16
  • 1970-01-01
  • 1970-01-01
  • 2014-04-24
相关资源
最近更新 更多