[JAVA-2981] Manage Enum type as Map keys Created: 18/Sep/18  Updated: 11/Dec/18  Resolved: 11/Dec/18

Status: Closed
Project: Java Driver
Component/s: BSON, POJO
Affects Version/s: 3.0.0
Fix Version/s: None

Type: Improvement Priority: Major - P3
Reporter: Farid BG Assignee: Ross Lawley
Resolution: Won't Fix Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Hello,

Current limitation of the MapCodec is that it only manages Map<K,V> with K being necessarily String.

It could be quite easy and useful to extend this to Enums in a first step, and to any type that can be serialized/deserialized to/from String.

An idea to be able to manage any type as a map's key is to introduce a kind of "key codec" interface that defines how should a certain type be encoded/decoded if it appears as a map's key. It could even be a converter rather than a general codec since we know that the target type is necessarily String.

 

Cheers

Farid



 Comments   
Comment by Ross Lawley [ 11/Dec/18 ]

Hi fbg,

I'm glad you were able to use the PropertyCodecProvider to meet your requirements. This is a good example of why the abstraction was introduced and how it can be used. I can see why a custom Key Converter might help reduce the boiler plate with your abstraction, alternative approaches could be custom Map implementations that allow Codecs / PropertyCodecProviders to handle the conversion of types.

There are no current plans to allow alternative types as keys for Maps by default - for that reason I'm closing this ticket as Won't Fix. However, I will happily review should there be more demand for such a feature. So please comment if you feel this is a missing feature in the PojoCodec.

Ross

Comment by Farid BG [ 10/Dec/18 ]

Hi Ross,

Thank you for you response.

I had a look at the examples you provided. My problem with creating a custom Codec for each Map with a different key type is that there would be a lot a code duplication. Basically, the whole logic is the same except for the way the key is encoded/decoded to/from a string.

The reason I think that Enum types should be managed out of the box is that their string representation is quite obvious; whether it should be the name() or toString() or ordinal() is a matter of convention. I personally think the name() would be the most adequate choice, as the method is final, and the output string of that method enables to find the right instance of the enum. Although the ordinal() method bears the same properties as the aforementionned, it does not visually convey the same information as the name of the enum. Developers will usually name their Enums in a meaningful way that is understandable directly, even outside the scope of the application, i.e. someone reading a document directly in the db would better understand it if he sees meaningful strings as keys rather than numbers. Performance wise, I don't think it makes any difference if its the name() or ordinal() since they are all stored as strings in the db. I ruled out the toString() earlier on since it can be overridden by the developer, and the mecanism for decoding the enum would be more painful, although not impossible.

I did manage to create my own custom MapPropertyCodecProvider. I wrote it in a way that manages Strings and Enums out of the box. It can also manage any other type, given that you provide a KeyConverter for each key type you want to manage, which is an interface I defined with methods to convert to and from a String. The problem with this approach is that the KeyConverters I provide to my custom MapPropertyCodecProvider before registering it to the Pojo Codec are not reachable outside the scope of my MapPropertyCodecProvider. Say I need to create another custom PropertyCodecProvider that needs to deals with Pojos as keys (like a multimap for example), well i'll have to manually register the (possibly) same KeyConverters to that PropertyCodecProvider as well. To summarize, there is no centralized repository of KeyConverters. But hey, nothing is perfect!

As I said in the issue's description, I don't expect such a mechanism to be implemented on the short-term, as it involves some considerable design choices to be made, in addition to determining whether this is really a feature required by users; plus there is a way to manage it manually with the current driver. But the management of Enums would be quite useful and easy to incorporate into the current MapCodecProvider, so I am quite eager to see this feature implemented.

Thank you again for your help.

Farid

Comment by Ross Lawley [ 10/Dec/18 ]

Hi fbg,

Thanks for the ticket, encoding Map's with an Enum Key could be explicitly controlled by custom codecs for use within Document classes, however, the lack of type information when decoding into a Document wouldn't make it feasible for the general case.

I believe the current Codec infrastructure is flexible enough to handle this process for Pojo Codecs. As Pojo classes can provide their own PropertyCodecProvider to handle encoding nested / complex types. One such example in tests uses an Integer for a map key. The InvalidMapModel isn't valid out the box but a test can be seen in the PojoCustomTest that shows by providing a InvalidMapPropertyCodecProvider the map key can be roundtripped.

Should Map<Enum, T> be supported out the box? This I'm slightly less convinced about because there are multiple ways to store the value of an Enum - theres the toString value, the name value or even the ordinal position. Finally, there is a chance of receiving data that doesn't match an Enum value at all. A simple Map<String, Object> doesn't have these limitations.

Have you considered providing a custom Codec for Map<Enum, T> or using a custom PropertyCodecProvider?

Ross

Generated at Thu Feb 08 08:58:30 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.