Эта проблема меня озадачивает. Итак, у меня есть UserModel, где я храню последние известные координаты пользователя, используя объект org.springframework.data.mongodb.core.geo.GeoJsonPoint
, который переводится в
"lastKnownCoordinates": {
"type": "Point",
"coordinates": [77.596503, 12.966267]
}
У меня есть коллекции экскурсий, которые сопоставляются с объектом ExcursionsModel
. Каждая экскурсия имеет свойство геолокации, которое хранит свое местоположение, используя спецификацию GeoJsonPoint
, например:
"geolocation": {
"coordinates": [73.739978, 15.606188],
"type": "Point"
}
Теперь, когда пользователь пытается добавить ближайший фильтр, чтобы получить экскурсии на указанное расстояние, я добавляю $nearSphere
критерии к объекту запроса (org.springframework.data.mongodb.core.query.Query
), как это
if (userRequest.getDistInMeters() != null) {
query.addCriteria(Criteria.where("geolocation")
.nearSphere(userModel.getLastKnownCoordinates())
.maxDistance(userRequest.getDistInMeters())
);
}
Технически это должно означать следующее:
...
"geolocation" : {
$nearSphere: {
$geometry: {
type : "Point",
coordinates : [ 77.596503, 12.966267 ]
},
$maxDistance: 10000
}
}...
(если distInMeters = 10000)
Но, я это скорее переводится как:
...
"geolocation" : {
"$nearSphere" : {
"$geometry" : {
"$java" : Point [x=-3.703790, y=40.416775]
}
}
}...
Обратите внимание, что преобразование GeoJsonPoint
неверно. Я также получаю следующее исключение
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.
Полная стенограмма вывода:
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.] with root cause
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class org.springframework.data.mongodb.core.geo.GeoJsonPoint.
at org.bson.internal.CodecCache.getOrThrow(CodecCache.java:57)
at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:64)
at org.bson.internal.ChildCodecRegistry.get(ChildCodecRegistry.java:52)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:197)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:195)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.writeValue(DocumentCodec.java:195)
at org.bson.codecs.DocumentCodec.writeMap(DocumentCodec.java:212)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:154)
at org.bson.codecs.DocumentCodec.encode(DocumentCodec.java:45)
at org.bson.BsonDocumentWrapper.getUnwrapped(BsonDocumentWrapper.java:195)
at org.bson.BsonDocumentWrapper.isEmpty(BsonDocumentWrapper.java:115)
at com.mongodb.internal.operation.DocumentHelper.putIfNotNullOrEmpty(DocumentHelper.java:43)
at com.mongodb.internal.operation.FindOperation.getCommand(FindOperation.java:792)
at com.mongodb.internal.operation.FindOperation.access$1600(FindOperation.java:77)
at com.mongodb.internal.operation.FindOperation$4.create(FindOperation.java:858)
at com.mongodb.internal.operation.CommandOperationHelper.executeCommandWithConnection(CommandOperationHelper.java:219)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:631)
at com.mongodb.internal.operation.FindOperation$1.call(FindOperation.java:625)
at com.mongodb.internal.operation.OperationHelper.withReadConnectionSource(OperationHelper.java:462)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:625)
at com.mongodb.internal.operation.FindOperation.execute(FindOperation.java:77)
at com.mongodb.client.internal.MongoClientDelegate$DelegateOperationExecutor.execute(MongoClientDelegate.java:190)
at com.mongodb.client.internal.MongoIterableImpl.execute(MongoIterableImpl.java:135)
at com.mongodb.client.internal.MongoIterableImpl.iterator(MongoIterableImpl.java:92)
at com.example.comercial.backend.dao.ExcursionDao.getAllExcursions(ExcursionsDao.java:140)
at com.example.comercial.backend.service.ExcursionsService.getAllExcursions(ExcursionsService.java:70)
at com.example.comercial.backend.controller.ExcursionsController.getAllExcursions(ExcursionsController.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:652)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:289)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Фрагмент кода из класса ExcursionsDao
, где возникает исключение:
...
FindIterable<Document> findIterable = mongoTemplate.getCollection("excursions")
.find(query.getQueryObject())
.skip(pageable.getPageSize() * (pageable.getPageNumber() - 1))
.limit(pageable.getPageSize());
if (userRequest.getOrderBy() != null && userRequest.getSortOrder() != null) {
if (userRequest.getSortOrder().getSortOrder().equals(SortOrder.ASC.getSortOrder())) {
findIterable.sort(Sorts.ascending(userRequest.getOrderBy().getOrderBy()));
} else {
findIterable.sort(Sorts.descending(userRequest.getOrderBy().getOrderBy()));
}
}
ArrayList<ExcursionModel> excursionModelList = new ArrayList<>();
for (Document document : findIterable) { // Line 140 where the exception is thrown
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
excursionModelList.add(objectMapper.convertValue(document, ExcursionModel.class));
}
Я использую значения по умолчанию для соединения монго, которое фактически инициализируется с помощью GeoJsonCodecProvider.
Из класса MongoClientSettings:
public final class MongoClientSettings {
private static final CodecRegistry DEFAULT_CODEC_REGISTRY =
fromProviders(asList(new ValueCodecProvider(),
new BsonValueCodecProvider(),
new DBRefCodecProvider(),
new DBObjectCodecProvider(),
new DocumentCodecProvider(new DocumentToDBRefTransformer()),
new IterableCodecProvider(new DocumentToDBRefTransformer()),
new MapCodecProvider(new DocumentToDBRefTransformer()),
new GeoJsonCodecProvider(),
new GridFSFileCodecProvider(),
new Jsr310CodecProvider(),
new BsonCodecProvider()));
Какие альтернативы я пробовал, но они не сработали
1. Я написал следующий сериализатор (взято из ответа SO, который я забыл) для объекта GeoJsonPoint
public class GeoJsonPointSerializer extends JsonSerializer<GeoJsonPoint> {
@Override
public void serialize(final GeoJsonPoint value, final JsonGenerator gen, final SerializerProvider serializers)
throws IOException {
gen.writeStartObject();
gen.writeStringField("type", value.getType());
gen.writeArrayFieldStart("coordinates");
gen.writeObject(value.getCoordinates());
gen.writeEndArray();
gen.writeEndObject();
}
}
и использовал его для свойства геолокации в ExcursionsModel
вот так
@JsonSerialize(using = GeoJsonPointSerializer.class)
@GeoSpatialIndexed(name = "geoIndex", type = GeoSpatialIndexType.GEO_2DSPHERE)
private GeoJsonPoint geolocation;
2. Я создал экземпляр CodecRegistry
и добавил к нему PointCodec
вместе с реестрами кодеков по умолчанию из MongoClientSettings
, а затем инициализировал класс FilterIterable
с этим реестром кодеков.
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(
MongoClientSettings.getDefaultCodecRegistry(),
CodecRegistries.fromCodecs(new PointCodec(MongoClientSettings.getDefaultCodecRegistry()))
);
FindIterable<Document> findIterable = mongoTemplate.getCollection("excursions").withCodecRegistry(codecRegistry)
.find(query.getQueryObject())
.skip(pageable.getPageSize() * (pageable.getPageNumber() - 1))
.limit(pageable.getPageSize());
Я получаю одно и то же исключение во всех случаях.
Примечание. Я знаю о других вопросах на StackOverflow, которые выглядят похожими на этот, но их цель немного отличается от того, чего я хочу достичь. Я хочу использовать объект запроса, чтобы сохранить динамический запрос.
Зависимости, которые я использую:
весна-загрузка-стартер-данные-mongodb | 2.3.3.ВЫПУСК
основной драйвер mongodb | 4.0.5
весна-данные-mongdb | 3.0.3.ВЫПУСК