简体   繁体   中英

Serialization and Deserialization property inconsistencies

I have 2 services A and service B .

Some upstream is calling service A with request sample json as:

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

I need to make request for service B from service A like this:

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

As you can see there is an issue in mapping fields of ServiceARequest to ServiceBRequest as casing of some the properties are not same, but the type of them are same.

So what should I do in this case? Do I need to create 2 classes with same name and different property names, then I need to put them under different packages, OR if I use the same classes for A, B and C, then field names can only be either pwid or pwId

How to do this kind of mapping from ServiceARequest structure to ServiceBRequest structure here and then inverse mapping from ServiceBResponse to ServiceARequest, using MapStruct ? Structure of ServiceBRequest and ServiceBResponse are exactly same.

Updated after discussion in the comments section.

I don't see that you have to use mapstruct here. I mean you can, but first you would need to create POJOs you would like to map, so as I understood it should be ServiceARequest class mapped to ServiceBRequest, and here is the problem. Cause both POJOs has properties of classes A and C, but A and C have different fields names depending on parent type, which means you will have to define class A for ServiceARequest, then different version of class A for ServiceBRequest and so on. And then mapping would be quite simple and strightforward, but you end up with a bunch of classes with quite similar structure, so it doesn't look great and neat.

I would approach it differently. Inside your code you can use same classes for A and C, it doesn't matter. What matters is different json structure for your requests. So whenever you requests serialized/deserialized you have to make sure that json structure is correct, which means you only have to care about serialization/deserialization. And here @JsonAlias can be handy.

If I understood correclty you get following json coming to your serviceA:

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

That json is mapped to class ServiceARequest , which can be implemented as follows (note: all classes must have setters and getters, I just ommit them to make the code shorter):

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 and C classes:

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() {
    }
}

With those annotations your incoming json will be mapped to ServiceARequest perfeclty. Then you need to send a request to service B, so you need to define ServiceBRequest class:

public class ServiceBRequest {

    @JsonProperty("CCM")
    private ServiceARequest ccm;

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

Then just create a new instance of ServiceBRequest and it can be sent to the service B. Here is the test code:

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

The output I got:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM