Spring -Data MongoDB проблема с полем, который является интерфейсом
Я использую Spring -Data for MongoDB:
Информация о версии - org.mongodb.mongo-java-driver версия 2.10.1,
org.springframework.data.spring-data-mongodb версия 1.2.1.RELEASE.
У меня есть случай, похожий на тот, который определен в здесь, который (извините за форматирование...):
Я только начал разрабатывать некоторые приложения на Java с помощью Spring -data-mongodb и столкнулся с проблемой, которую я не смог решить:
У меня есть пара документов beans следующим образом:
@Document(collection="myBeanBar")
public class BarImpl implements Bar {
String id;
Foo foo;
// More fields and methods ...
}
@Document
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)
Решение, которое было дано, состояло в том, чтобы использовать аннотацию @TypeAlias в абстрактном классе, которая рассказала структуре использовать конкретную реализацию (в данном случае FooImpl).
В моем случае у меня есть интерфейс, а не abstract:
@Document(collection="myBeanBar")
public class BarImpl implements Bar {
String id;
IFoo foo;
// More fields and methods ...
}
Я очень неохотно размещаю аннотацию на интерфейсе IFoo, который даст реализацию по умолчанию, вместо этого я хотел бы рассказать структуре, что эта реализация по умолчанию по умолчанию в контексте реализации Класс BarImpl, аналогичный @JsonTypeInfo:
@Document(collection="myBeanBar")
public class BarImpl implements Bar {
String id;
@JsonTypeInfo(use = Id.CLASS, defaultImpl = FooImpl.class)
IFoo foo;
// More fields and methods ...
}
Я нашел этот ответ, который более или менее говорит, чтобы избежать использования интерфейсов. но я был бы рад узнать, нет ли лучшего варианта.
Любые идеи?
Спасибо!
Ответы
Ответ 1
Моя проблема аналогична вопросу, но созданное исключение немного отличается:
Could not instantiate bean class [class name]: Specified class is an interface
Это происходит, когда одно из полей моего класса DB объявляется как интерфейс. Сохранение этого поля прекрасное, но исключение вызывается при чтении его из MongoDB. Наконец, я нашел решение, которое использует org.springframework.core.convert.converter.Converter
.
TWOstrong > шаги, 1. постройте класс, реализующий Converter
; 2. зарегистрируйте конвертер в контексте сервлета. И ДА, вам не нужно изменять какой-либо существующий код, например добавление аннотации.
Ниже приведен мой модельный класс, где поле Data
является интерфейсом:
@Document(collection="record")
public class Record {
@Id
private String id;
// Data is an interface
private Data data;
// And some other fields and setter/getter methods of them
}
Конвертер:
@ReadingConverter
public class DataReadConverter implements Converter<DBObject, Data> {
@Override
public Data convert(DBObject source) {
// Your implementation to parse the DBObject,
// this object can be BasicDBObject or BasicDBList,
// and return an object instance that implements Data.
return null;
}
}
Последнее, что нужно сделать, это зарегистрировать конвертер, моя конфигурация находится в xml:
<mongo:mongo id="mongo" />
<mongo:db-factory mongo-ref="mongo" dbname="example" />
<mongo:mapping-converter>
<mongo:custom-converters>
<mongo:converter>
<beans:bean class="com.example.DataReadConverter" />
</mongo:converter>
</mongo:custom-converters>
</mongo:mapping-converter>
<beans:bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
<beans:constructor-arg name="mongoDbFactory" ref="mongoDbFactory" />
<beans:constructor-arg name="mongoConverter" ref="mappingConverter" />
</beans:bean>
Разверните приложение и повторите попытку. Он должен правильно проанализировать DBObject из MongoDB в поле интерфейса.
Версия моего приложения Spring MongoDB: spring - * - 4.1.0 и spring -data-mongodb-1.6.0.
Ответ 2
Это действительно плохая идея определить интерфейсы как поле в объекте данных.
Интерфейс означает возможность некоторого объекта что-то сделать, но не предоставляет никакой информации о полях. Вам действительно нужно использовать интерфейсы? Вы можете избежать этого? Даже при использовании абстрактного определения класса будет лучше идея.
P.S. Конечно, мой ответ не может быть помечен как правильный ответ в любом случае.