为简单起见,我将仅使用示例中的卡片对象,我不会将其包装为另一个对象。为了避免示例中的重复,我将使用这个基类来保存公共字段:
public abstract class BaseCard {
private String brand;
private String fundingMethod;
private String scheme;
//setters and getters
}
你的选择很少。
选项 1:
如果您知道从哪个 api 获得响应,则可以有两个类,每个类都以特定于 api 的格式保存expiry。从 api 1 获取数据时使用:
public class CardApi1 extends BaseCard {
private String expiry;
//setters and getters
}
对于 api 2:
public class CardApi2 extends BaseCard {
private Expiry expiry;
//setters and getters
}
到期对象如下所示:
public class Expiry {
private String month;
private String year;
//setters and getters
}
如果您正在调用 api 1,则反序列化为 CardApi1,否则为 CardApi2。
选项2:设置过期字段Object,这样任何东西都可以反序列化到其中。
public class CardApiMixed extends BaseCard {
private Object expiry;
//setters and getters
public String getExpiryAsString() {
return (String) this.expiry;
}
public Map<String, Object> getExpiryAsMap() {
@SuppressWarnings("unchecked")
Map<String, Object> expiry = (Map<String, Object>) this.expiry;
return expiry;
}
}
这样,无论您调用哪个 api,您都可以反序列化为一个类。缺点是,在检索expiry的时候,还是要知道数据来自哪个api,所以要使用正确的方法。
选项 3: 编写自定义反序列化器,无论使用哪个 api,都能正确解析字段。我个人会选择这个选项。解串器是这样的:
public class ExpiryResolvingCardDeserializer extends StdDeserializer<CardApiResolved> {
public ExpiryResolvingCardDeserializer() {
super(CardApiResolved.class);
}
@Override
public CardApiResolved deserialize(JsonParser parser, DeserializationContext context) throws IOException {
JsonNode node = parser.getCodec().readTree(parser);
CardApiResolved card = new CardApiResolved();
card.setBrand(node.get("brand").asText());
card.setFundingMethod(node.get("fundingMethod").asText());
card.setScheme(node.get("scheme").asText());
JsonNode expiryNode = node.get("expiry");
Expiry expiry = new Expiry();
if (expiryNode.isObject()) {
//that's for api 2
expiry.setMonth(expiryNode.get("month").asText());
expiry.setYear(expiryNode.get("year").asText());
} else {
//for api 1
String text = expiryNode.asText();
//assuming format is always mmYY, you can handle it in differently if there are other options
int splitIndex = 2;
expiry.setMonth(text.substring(0, splitIndex));
expiry.setYear(text.substring(splitIndex));
}
card.setExpiry(expiry);
return card;
}
}
总结一下,当expiry节点是对象时,像对象一样处理,从中获取月和年数据,如果是字符串,则将其拆分以提取月和年。像这样无论格式如何,expiry 总是被解析为Expiry 类。卡片类将如下所示:
@JsonDeserialize(using = ExpiryResolvingCardDeserializer.class)
public class CardApiResolved extends BaseCard {
private Expiry expiry;
//setters and getters
}
注意JsonDeserialize 注释指定了用于此类型的反序列化器。最后,一些单元测试可以使用并检查结果。 api 响应是测试资源中的文件。
public class CardApiTests {
private final ObjectMapper mapper = new ObjectMapper();
@Test
public void testCardApi1() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-1.json");
//map to CardApi1, when calling api 1
CardApi1 result = this.mapper.readValue(inputStream, CardApi1.class);
assertEquals("0139", result.getExpiry());
}
@Test
public void testCardApi2() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-2.json");
//map to CardApi2, when calling api 2
CardApi2 result = this.mapper.readValue(inputStream, CardApi2.class);
assertEquals("1", result.getExpiry().getMonth());
assertEquals("39", result.getExpiry().getYear());
}
@Test
public void testCardApiMixed_Api1() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-1.json");
CardApiMixed result = this.mapper.readValue(inputStream, CardApiMixed.class);
assertEquals("0139", result.getExpiryAsString());
}
@Test
public void testCardApiMixed_Api2() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-2.json");
CardApiMixed result = this.mapper.readValue(inputStream, CardApiMixed.class);
assertEquals("1", result.getExpiryAsMap().get("month"));
assertEquals("39", result.getExpiryAsMap().get("year"));
}
@Test
public void testCardApiResolved_Api1() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-1.json");
CardApiResolved result = this.mapper.readValue(inputStream, CardApiResolved.class);
assertEquals("01", result.getExpiry().getMonth());
assertEquals("39", result.getExpiry().getYear());
}
@Test
public void testCardApiResolved_Api2() throws Exception {
InputStream inputStream = ClassLoader.getSystemResourceAsStream("card-api-2.json");
CardApiResolved result = this.mapper.readValue(inputStream, CardApiResolved.class);
assertEquals("1", result.getExpiry().getMonth());
assertEquals("39", result.getExpiry().getYear());
}
}