3

I know enums are used when we are expecting only a set of values to be passed. We don't want the caller to pass anything other than the well defined set. And this works very well inside a project. Because you know what you've to pass.

But consider 2 projects, I am using the models of 1st project in 2nd.

Second project has a method like this.

 public void updateRefundMode(RefundMode refundMode) 

 enum RefundMode("CASH","CARD","GIFT_VOUCHER")

Now, I realise RefundMode can be PHONEPE also, So If I start passing this to 1st project, it would fail at their end (Unable to desirialize enum PHONEPE). Although I've added this enum at my end.

Which is fine, because If my first project doesn't know about the "PHONEPE", then it doesn't know how to handle it, so he has to update the models too.

But my problem is, Let's imagine a complex Object am trying to pass, which also takes this RefundMode, when I pass a new RefundMode just this field should be become null or ignored at their end right ? Rather than not accepting the whole object, and breaking the entire flow/request.

Is there a way I can specify jackson (jsonproperties) to just ignore that field if an unknown value is being passed. Curious to know.. (Although In that case, I am breaking the rule of ENUM) So, why not keep a String which solves all the problem ?

tom redfern
  • 30,562
  • 14
  • 91
  • 126
  • 3
    What you're describing is a bigger problem that has to be solved _somehow._ Enums aren't really responsible for it -- any other inheritance structure would have the same issue. You might e.g. use [protocol buffers](https://developers.google.com/protocol-buffers), in which enum values that aren't known by the receiving server are always treated as a special UNKNOWN value; you might require the receiving code to be updated to accept values before they ever get sent, you might use some kind of versioning... – Louis Wasserman Sep 10 '20 at 20:14
  • @pyb s answer I think is spot on. But one thing I'd add to that is that in cases like this, you role out the client implementation well before the server / sender. That way, most people will hopefully be ready for the change by the time it starts being used – ControlAltDel Sep 10 '20 at 20:23
  • 1
    *"just this field should be become null or ignored at their end right ?"* Absolutely not. Since project 1 doesn't know how to handle it, simply null'ing the value is not a solution, because the code will end up doing something wrong. Better reject that up front, rather than accepting the data and failing terribly later on, where you might no longer be able to track where the *corrupt* data came from. – Andreas Sep 10 '20 at 21:08
  • Thanks LouisWasserman, ControlAltDel, Andreas for sharing your thoughts. It helps :) – Keerthi Kumar S G Sep 13 '20 at 17:36

1 Answers1

4

It's all about contracts.

When you are in a client/server situation, being a mobile app and a web server, or a Java library (jar) and another Java project, you have to keep the contracts in mind.

As you observed, a change in contracts need to be propagated to both parties: the client and the server (supplier).

One way of working with this is to use versioning. You may say: "Version 1: those are the refund modes.". Then the mobile app may call the web server by specifying the contract version in the URL: /api/v1/refund?mode=CASH

When the contract needs to be changed, you need to consider what to do with the clients. In the case of mobile apps, the users might not have updated their app to the latest version, so their app may still be calling /api/v1 (and not supporting new refund modes). In that case, you may want to support both /api/v1 and /api/v2 (with the new refund mode) in your web server.

As your example shows, it is not always possible to transparently adapt one contract version to another (in your example, there is no good equivalent to PHONEPE in the original enum). If you have to deal with contract updates, I suggest explicitly writing code to them (you can use dedicated JSON schemas, classes and services) instead of trying to bridge the gaps. Think of what would happen with a third, fourth version.

Edit: to answer your last question, you can ignore unknown fields in JSON by following this answer (with the caveats explained above): https://stackoverflow.com/a/59307683/2223027

Edit 2: in general, using Enums is a form of strong typing. Sure, you could use Strings, or even bits, but then it would be easier to make mistakes, like using GiftVoucher instead of GIFT_VOUCHER.

pyb
  • 4,813
  • 2
  • 27
  • 45
  • 1
    Thanks @pyb, for such detailed explanations. Although the edits 1 and 2 are very basics, I just didn't think about them while asking this question. Thanks once again for detailed explanation :) – Keerthi Kumar S G Sep 13 '20 at 17:40