2013-02-15 3 views
2

Я только начал разработку некоторые приложения в Java с пружинным-данных MongoDB и наткнулся на какой-то вопрос, который я не смог решить:SD MongoDB полиморфизм в поддокументе

Есть несколько документов фасолью, как это:

@Document(collection="myBeanBar") 
public class BarImpl implements Bar { 
    String id; 
    Foo foo; 
    // More fields and methods ... 
} 

@Docuemnt 
public class FooImpl implements Foo { 
    String id; 
    String someField; 
    // some more fields and methods ... 
} 

И у меня есть хранилище класс с методом, который просто вызывает найти похожее на это:

public List<? extends Bar> findByFooField(final String fieldValue) { 
    Query query = Query.query(Criteria.where("foo.someField").is(fieldValue)); 
    return getMongoOperations().find(query, BarImpl.class); 
} 

Сохранение Бар работает нормально, было бы сохранить его в Монго вместе с атрибут «_class» для Foo и Bar. Однако, найти какой-то атрибут в Foo будет сгенерировано исключение, как это:

Exception in thread "main" java.lang.IllegalArgumentException: No property someField found on test.Foo! 
    at org.springframework.data.mapping.context.AbstractMappingContext.getPersistentPropertyPath(AbstractMappingContext.java:225) 
    at org.springframework.data.mongodb.core.convert.QueryMapper.getPath(QueryMapper.java:202) 
    at org.springframework.data.mongodb.core.convert.QueryMapper.getTargetProperty(QueryMapper.java:190) 
    at org.springframework.data.mongodb.core.convert.QueryMapper.getMappedObject(QueryMapper.java:86) 
    at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1336) 
    at org.springframework.data.mongodb.core.MongoTemplate.doFind(MongoTemplate.java:1322) 
    at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:495) 
    at org.springframework.data.mongodb.core.MongoTemplate.find(MongoTemplate.java:486) 

Который, после некоторого копания, имеет некоторый смысл, поскольку нигде в запросе типа бетона поддокумента уточняется и Субъект Информация Bar говорит, что тип foo - Foo (не FooImpl), который, в свою очередь, не может иметь свойств, потому что это интерфейс.

Мой вопрос: есть ли способ указать его или обойти эту проблему без объявления типа субдокумента как конкретного типа?

Я пару раз просматривал его в Интернете и изучал документацию, API и исходный код, но я не могу найти четкий способ сделать это. Я очень благодарен за вашу помощь.

спасибо.

+0

После некоторого тестирования я заметил, что когда я сохраняю объект, а затем извлекаю документы из mongodb, все работает отлично. Однако, когда это первое первое чтение из MongoDB, я получаю исключение BeanInstantiationException. По-видимому, objectCallback не имеет соответствующего TypeMapper, который может разрешить интерфейс для конкретного класса для создания экземпляра для DBObject. – Russell

ответ

3

У меня была аналогичная проблема, у меня есть класс, который реализует интерфейс и, когда я использую findAll я получаю ошибку:

org.springframework.data.mapping.model.MappingInstantiationException: Could not instantiate bean class [test.MetaClasse]: Specified class is an interface.

После отладки SpringData кода, я понял, что Mapper использует @TypeAlias для обнаружения типа он должен создать экземпляр, поэтому я просто положил @TypeAlias("FullClassName") на мои версии test.MetaClasse, и это сработало!

Я тестировал вашу ситуацию, и она будет работать!

+0

Есть ли альтернатива этому решению? С точки зрения дизайна это кажется очень бедным. Вы должны добавить аннотацию @TypeAlias ​​к каждой реализации 'Foo'. – jtcotton63

+0

Кроме того, этот подход делает рефакторы очень сложными. Что делать, если мне нужно переименовать класс? Все ссылки _alias в БД теперь бесполезны. Что делать, если мне нужно сделать абстракцию класса, а затем добавить дочерние реализации? И снова ссылки _alias теперь бесполезны. Я должен был бы написать сценарий, чтобы пройти через данные и изменить их все. Должно быть лучшее решение. – jtcotton63

Смежные вопросы