Details

    • Type: New Feature
    • Status: Open
    • Priority: Major - P3
    • Resolution: Unresolved
    • Affects Version/s: 2.4
    • Fix Version/s: undecided
    • Component/s: API
    • Labels:
      None
    • # Replies:
      8
    • Last comment by Customer:
      false
    • Story Points:
      1

      Description

      Add support for encoding/decoding java enums

        Issue Links

          Activity

          Hide
          antoine Antoine Girbal (Inactive) added a comment -

          there is no representation for enum in json / bson, so would have to use integers or strings.
          integer is much more compact, but string is more resilient in case items are reordered in enum.

          We could add convenience so that:

          • serialize: if value object is enum, calls name() or index() to obtain value.
          • deserialize: add "Enum getEnum(String key, Enum enms[] )" that would automatically find the Enum and return it.

          For the reflectionDBObject it may be more interesting, if we can automatically handle enums from objects.
          comments welcome.

          Show
          antoine Antoine Girbal (Inactive) added a comment - there is no representation for enum in json / bson, so would have to use integers or strings. integer is much more compact, but string is more resilient in case items are reordered in enum. We could add convenience so that: serialize: if value object is enum, calls name() or index() to obtain value. deserialize: add "Enum getEnum(String key, Enum enms[] )" that would automatically find the Enum and return it. For the reflectionDBObject it may be more interesting, if we can automatically handle enums from objects. comments welcome.
          Show
          gerhardb Gerhard Balthasar added a comment - See also: http://ghads.wordpress.com/2011/04/12/mongodb-and-java-enums/
          Hide
          amare A Mare added a comment -

          Please, can you do something about it?
          It looks like the DB mapping APIs such as Spring Data MongoDB can handle the case of enum, so we're covered from the point of view of persistence.
          But simple things like

          query.getQueryObject().toString()

          fail simply because serialization does not work for BasicDBObject with enumerations, since there is no appropriate serializer in JSONSerializers.
          A direct use of Enum.name() could do just fine in an EnumSerializer.

          Thank you.

          Show
          amare A Mare added a comment - Please, can you do something about it? It looks like the DB mapping APIs such as Spring Data MongoDB can handle the case of enum , so we're covered from the point of view of persistence. But simple things like query.getQueryObject().toString() fail simply because serialization does not work for BasicDBObject with enumerations, since there is no appropriate serializer in JSONSerializers . A direct use of Enum.name() could do just fine in an EnumSerializer . Thank you.
          Hide
          mathieucarbou Mathieu Carbou added a comment - - edited

          You can easily override the encoder. This is at least half of the job done. I've done it liek this:

          DefaultDBEncoder.FACTORY = new DBEncoderFactory() {
              @Override
              DBEncoder create() {
                  return new DefaultDBEncoder() {
                      @Override
                      protected void _putObjectField(String name, Object val) {
                          if (val?.class?.enum) {
                              super.putString(name, val.name())
                          } else {
                              super._putObjectField(name, val)
                          }
                      }
                  }
              }
          }

          The code is in groovy but it can be easily translated to Java.

          And to be able to use enums in queries, I had to override in the classpath the class ClassMapBasedObjectSerializer: i took the source, put it in the package com.mongo.util and added this default constructor:

          ClassMapBasedObjectSerializer() {
              _serializers.put(Enum.class, new AbstractObjectSerializer() {
                  @Override
                  public void serialize(Object obj, StringBuilder buf) {
                      buf.append(((Enum) obj).name());
                  }
              });
          }

          Show
          mathieucarbou Mathieu Carbou added a comment - - edited You can easily override the encoder. This is at least half of the job done. I've done it liek this: DefaultDBEncoder.FACTORY = new DBEncoderFactory() { @Override DBEncoder create() { return new DefaultDBEncoder() { @Override protected void _putObjectField(String name, Object val) { if (val?. class ?. enum ) { super .putString(name, val.name()) } else { super ._putObjectField(name, val) } } } } } The code is in groovy but it can be easily translated to Java. And to be able to use enums in queries, I had to override in the classpath the class ClassMapBasedObjectSerializer: i took the source, put it in the package com.mongo.util and added this default constructor: ClassMapBasedObjectSerializer() { _serializers.put(Enum. class , new AbstractObjectSerializer() { @Override public void serialize(Object obj, StringBuilder buf) { buf.append(((Enum) obj).name()); } }); }
          Hide
          trisha.gee@10gen.com Trisha Gee (Inactive) added a comment -

          We could add support for Enums, but there are a number of problems with doing it by default:

          • If stored as a String, when decoding the string from MongoDB, the driver will not know this String type represents an enumeration. How do we prompt it to decode this into the enum and not into a simple String object?
          • If we knew this String represented an enum, how do we turn it into the correct enum? This is bound to require some use of reflection, which has an impact on performance so we prefer not to use it in the core Java driver.
          • Different users may want different representations for their enums. It's not uncommon to use a char or int representation for brevity. How could you specify which representation you wanted?

          In summary, adding support for enums is possible, but it's tricky, especially from the decoding side. As a general guideline, support for anything other than the BSON primitives is best left to ODMs, which are designed to cater for more complex objects.

          Show
          trisha.gee@10gen.com Trisha Gee (Inactive) added a comment - We could add support for Enums, but there are a number of problems with doing it by default: If stored as a String, when decoding the string from MongoDB, the driver will not know this String type represents an enumeration. How do we prompt it to decode this into the enum and not into a simple String object? If we knew this String represented an enum, how do we turn it into the correct enum? This is bound to require some use of reflection, which has an impact on performance so we prefer not to use it in the core Java driver. Different users may want different representations for their enums. It's not uncommon to use a char or int representation for brevity. How could you specify which representation you wanted? In summary, adding support for enums is possible, but it's tricky, especially from the decoding side. As a general guideline, support for anything other than the BSON primitives is best left to ODMs, which are designed to cater for more complex objects.
          Hide
          mathieucarbou Mathieu Carbou added a comment - - edited

          I completely agree for deserialization. This is up to the application in my opinion. Otherwise it lead to a custom schema structure for enum wich is not easy to query.

          But for serialzation, I strongly think that the Java driver is not well developped since it makes a lot of static calls without letting the user have any control over how objects are serialized. In my example, I would have liked something like this:

          Mongo driver = new ...
          driver.addSerializer(Enum, mySerializer)

          and this method call would modify the encoder behavior and also the serializer behavior.

          Show
          mathieucarbou Mathieu Carbou added a comment - - edited I completely agree for deserialization. This is up to the application in my opinion. Otherwise it lead to a custom schema structure for enum wich is not easy to query. But for serialzation, I strongly think that the Java driver is not well developped since it makes a lot of static calls without letting the user have any control over how objects are serialized. In my example, I would have liked something like this: Mongo driver = new ... driver.addSerializer(Enum, mySerializer) and this method call would modify the encoder behavior and also the serializer behavior.
          Hide
          trisha.gee@10gen.com Trisha Gee (Inactive) added a comment -

          That's a valid concern, but the 3.0 driver will have a new (and hopefully better) way to deal with serialisation.

          Show
          trisha.gee@10gen.com Trisha Gee (Inactive) added a comment - That's a valid concern, but the 3.0 driver will have a new (and hopefully better) way to deal with serialisation.
          Hide
          jeff.yemin Jeff Yemin added a comment - - edited

          Hi Mathieu,

          I was just reviewing this ticket, and after re-reading your comment I realized that the driver can already do what you asked for via org.bson.BSON.addEncodingHook.

          Just create a class that implements org.bson.Transformer, e.g.

          class EnumTransformer implements Transformer {
                  public Object transform(Object o) {
                      return o.toString();  // convert any object (including an Enum) to its String representation
                  }
              }

          and register an instance as an encoding hook for all classes that extend Enum:

                  BSON.addEncodingHook(Enum.class, new EnumTransformer());

          If you need to, you can specialize the Transformer for particular Enum types, e.g.

                  BSON.addEncodingHook(MyEnum.class, new MyEnumTransformer());

          Show
          jeff.yemin Jeff Yemin added a comment - - edited Hi Mathieu, I was just reviewing this ticket, and after re-reading your comment I realized that the driver can already do what you asked for via org.bson.BSON.addEncodingHook. Just create a class that implements org.bson.Transformer, e.g. class EnumTransformer implements Transformer { public Object transform(Object o) { return o.toString(); // convert any object (including an Enum) to its String representation } } and register an instance as an encoding hook for all classes that extend Enum: BSON.addEncodingHook(Enum. class , new EnumTransformer()); If you need to, you can specialize the Transformer for particular Enum types, e.g. BSON.addEncodingHook(MyEnum. class , new MyEnumTransformer());

            People

            • Votes:
              9 Vote for this issue
              Watchers:
              8 Start watching this issue

              Dates

              • Created:
                Updated:
                Days since reply:
                50 weeks, 1 day ago
                Date of 1st Reply: