Расширение отображения HashMap для Spring JPA - PullRequest
0 голосов
/ 04 марта 2019

Я решил создать следующий объект:

public class ScoreMap<T> extends HashMap<T, Double>

И я хотел бы сохранить их в БД:

@ElementCollection(fetch = FetchType.EAGER)
private Map<String, Double> keywords = new ScoreMap<>();

, который прекрасно работает.Все сохранено, как и ожидалось.


Теперь при извлечении кажется, что я не могу вернуть ScoreMap без TypeCasting:

public ScoreMap<String> getKeywords()
{
    return (ScoreMap<String>)keywords;
}

и при этом я получаю следующую ошибку:

Servlet.service() for servlet [dispatcherServlet] in context with path [/myApp] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: org.hibernate.collection.internal.PersistentMap cannot be cast to entity.ScoreMap (through reference chain: java.util.ArrayList[0]->entity.Document["document_knowledge"]->entity.DocumentKnowledge_$$_jvst505_2["keywords"])] with root cause
java.lang.ClassCastException: org.hibernate.collection.internal.PersistentMap cannot be cast to entity.ScoreMap

Я пытался изменить ScoreMap на:

public class ScoreMap<T> extends HashMap<T, Double> implements Map<T, Double>

С теми же результатами.


Мне нужноверните ScoreMap , чтобы использовать там другие методы.

Я знаю, что могу просто foreach и легко воссоздать объект, но я бы хотел, чтобы я мог этого избежать.

Так, как лучше всего подойти к этой ситуации?Я просто проектирую это явно неправильно или я что-то упускаю?

1 Ответ

0 голосов
/ 04 марта 2019

Я бы предложил вам другой подход. Делегирование .

Вместо расширения HashMap<K, V>, почему бы вам просто не реализовать интерфейс Map<K, V> и не принять другой экземпляр Map в качестве аргумента конструктора?

class ScoreMap<T> implements Map<T, Double> {
   private final Map<T, Double> delegate;

   ScoreMap(final Map<T, Double> delegate) {
      this.delegate = delegate;
   }

   ...

   @Override
   public Double get(final Object key) {
      // Apply custom logic, if needed
      return delegate.get(key);
   }

   // And so on...
}

Затем используйте getter и setter

@Entity
@...
class YourEntity {
   ...

   private Map<String, Double> keywords;

   @ElementCollection(fetch = FetchType.EAGER)
   public ScoreMap<String> getKeywords() {
      // This is fine as we know the Map will always be a ScoreMap
      return (ScoreMap<String>) keywords;
   }

   public void setKeywords(final Map<String, Double> keywords) {
      this.keywords = new ScoreMap<>(keywords);
   }
}

Как вы можете видеть каждый раз, когда Hibernate будет устанавливать Mapвы оберните его внутри ScoreMap, имея дополнительную и настраиваемую логику.

А для вашего интереса Hibernate PersistentMap реализует интерфейс Map, поэтому он может быть принят вашим ScoreMap.


Документация Hibernate гласит

В качестве требования постоянные коллекционные поля должны быть объявлены как тип интерфейса (см. Пример 7.2, «Отображение коллекции с использованием @»).OneToMany и @JoinColumn »).Фактический интерфейс может быть java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap или как угодно («все что угодно»).означает, что вам придется написать реализацию org.hibernate.usertype.UserCollectionType).

Так что я отредактирую свой пример выше.
И в качестве последнего средства вы можете взглянуть наUserCollectionType

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...