Как я могу избежать преобразования пустого HashMap в null в morphia?

Мы используем org.mongodb.morphia для преобразования объектов BasicDBObjects перед сохранением. Одна из возникающих проблем заключается в том, что в некоторых случаях объект для преобразования содержит пустой HashMap, размер которого равен 0, после преобразования HashMap преобразуется в значение null. Таким образом, NullPointerException добавляет более поздний доступ. Хочу обратиться за помощью к знатокам, есть ли способ избежать этого? Я имею в виду, что после преобразования это все еще HashMap с размером 0.

Часть класса для преобразования:

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
}

код для конвертации:

// 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();
}

объект создается в другом месте. После некоторой отладки я обнаружил, что объект содержит пустую карту (следующие данные, скопированные из отладчика IntelliJ IDEA):

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

и тот, что после преобразования:

[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

Как видите, он преобразуется в null, чего мы пытаемся избежать. Спасибо


person Junius    schedule 22.01.2014    source источник


Ответы (3)


Прежде чем вызывать morphia.mapPackage(), сделайте следующее:

    morphia.getMapper().getOptions().storeEmpties = true;

Вероятно, это должно вернуться к пустой карте для вас.

person evanchooly    schedule 22.01.2014
comment
Спасибо за ответ. Я попробовал это. К сожалению, это не работает для меня. - person Junius; 23.01.2014
comment
Вы сделали это перед вызовом morphia.mapPackage()? - person evanchooly; 23.01.2014
comment
Я вызвал getOptions().storeEmpties=true, но никогда не вызывал morphia.mapPackage(). Я использовал его следующим образом: final MappedClass mc = mapper.getMappedClass(obj.getClass()); финальная карта‹String, Object› map = mapper.toDBObject(obj).toMap(); В этом суть? - person Junius; 24.01.2014
comment
Как только вы установите это значение, вам нужно будет вызвать mapPackage(). В идеале вы должны сделать это при первом создании экземпляра morphia. - person evanchooly; 24.01.2014
comment
Я думаю, что это не может работать. Единственный способ - настроить MapOfValuesConverter, поскольку он всегда преобразует пустую карту в null. - person Junius; 26.01.2014
comment
Я отправил запрос на включение, который исправляет это: github.com/mongodb/morphia/pull/571 - person Scott B; 02.02.2014

Я предполагаю, что не могу избежать этого без настройки MapOfValuesConverter. Из исходного кода видно, что пустая карта всегда будет преобразована в 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;
}  
person Junius    schedule 26.01.2014

Если morphia.getMapper().getOptions().setStoreEmpties(true); у вас не работает, другим решением будет использование @PostLoad аннотации для проверьте, есть ли у вас нулевая коллекция, и при необходимости создайте пустую.

import java.util.*;
import org.mongodb.morphia.annotations.*;
import org.bson.types.ObjectId;

@Entity
public class Model {
    @Id
    private ObjectId id;
    private Map<String, String> map;

    protected Model() {}

    public Model(HashMap<String, String> map) {
        super();
        setMap(map);
    }

    public void setMap(HashMap<String, String> map) {
        this.map = map;
        checkForNullMap();
    }

    @PostLoad
    private void checkForNullMap() {
        if (map == null) {
            map = new HashMap<String, String>();
        }
    }
}
person Gabriel Saca    schedule 27.04.2015