Search code examples
mongodbmorphia

How can I avoid converting an empty HashMap to null in morphia?


We are using org.mongodb.morphia to convert objects BasicDBObjects before persistence. One issue encountered is that in some cases the object to convert contains an empty HashMap whose size is 0, after conversion, the HashMap is converted to null. So NullPointerException throw in later accessing. I want to ask experts for help, Is there any way to avoid this? I mean, after conversion, it's still an HashMap with size 0.

Part of the class to be converted:

public class ProjectServiceAdapterConfig {
    @NotNull
    private String serviceAdapterId;

    @NotNull
    private String projectId;

    @Embedded
    @Flatten
    private Map<String, Map<String, String>> connections = new HashMap<>();

    //......  setter and getter skipped here
}

code for conversion:

// create a mapper with default MapperOptions
private Mapper createMapper() {
    return new Mapper();
}

ReplaceableItem objectToItem(final ProjectServiceAdapterConfig obj) {
    final Mapper mapper = createMapper();
    final MappedClass mc = mapper.getMappedClass(obj.getClass());

    final Map<String, Object> map = mapper.toDBObject(obj).toMap();
}

the obj is created in other place. After some debug, I found that, the obj contains an empty Map(following data copied from IntelliJ IDEA debugger):

connections = {java.util.LinkedHashMap@8890} size = 1
  [0] = {java.util.LinkedHashMap$Entry@8894}"accounts" ->  size = 0
    key: java.lang.String = {java.lang.String@8895}"accounts"
    value: java.util.LinkedHashMap = {java.util.LinkedHashMap@8896} size = 0

and the one after converted:

[2] = {java.util.LinkedHashMap$Entry@8910}"connections" ->  size = 1
  key: java.lang.String = {java.lang.String@8911}"connections"
  value: com.mongodb.BasicDBObject = {com.mongodb.BasicDBObject@8912} size = 1
    [0] = {java.util.LinkedHashMap$Entry@8923}"accounts" -> null
      key: java.lang.String = {java.lang.String@8895}"accounts"
      value:  = null

As you can see , it's converted to null which we try to avoid. Thanks


Solution

  • I assume I cannot avoid it without customizing the MapOfValuesConverter. See from the source code that the empty map will be always converted to null:

    @Override
    public Object encode(Object value, MappedField mf) {
      if (value == null)
        return null
    
      Map<Object, Object> map = (Map<Object, Object>) value;
      if ((map != null) && (map.size() > 0)) {
        Map mapForDb = new HashMap();
        for (Map.Entry<Object, Object> entry : map.entrySet()) {
          String strKey = converters.encode(entry.getKey()).toString();
          mapForDb.put(strKey, converters.encode(entry.getValue()));
        }
        return mapForDb;
      }
      return null;
    }