Укажите недопустимое свойство - MongoDB & Grails 3.3+ - PullRequest
0 голосов
/ 05 ноября 2018

Возникла очень странная проблема в Grails и MongoDB, когда в моей производственной среде я получаю следующую ошибку.

java.lang.IllegalArgumentException: Property [location] is not a valid property of class [domain].Tracking
        at org.grails.datastore.mapping.reflect.FieldEntityAccess$FieldEntityReflector.getPropertyReader(FieldEntityAccess.java:268)
        at org.grails.datastore.mapping.reflect.FieldEntityAccess$FieldEntityReflector.getProperty(FieldEntityAccess.java:286)
        at grails.gorm.validation.PersistentEntityValidator.validatePropertyWithConstraint(PersistentEntityValidator.groovy:319)
        at grails.gorm.validation.PersistentEntityValidator.validate(PersistentEntityValidator.groovy:76)
        at org.grails.datastore.gorm.GormValidationApi.doValidate(GormValidationApi.groovy:124)
        at org.grails.datastore.gorm.GormValidationApi.validate(GormValidationApi.groovy:153)
        at org.grails.datastore.gorm.GormValidateable$Trait$Helper.validate(GormValidateable.groovy:71)
        at org.grails.datastore.gorm.GormValidateable$Trait$Helper$validate$1.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
        at [domain].Tracking.validate(Tracking.groovy)
        at org.grails.datastore.gorm.GormInstanceApi.doSave(GormInstanceApi.groovy:332)
        at org.grails.datastore.gorm.GormInstanceApi.doSave(GormInstanceApi.groovy)
        at sun.reflect.GeneratedMethodAccessor113.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1225)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
        at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:947)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:930)
        at org.codehaus.groovy.runtime.InvokerHelper.invokeMethodSafe(InvokerHelper.java:92)
        at org.grails.datastore.gorm.GormInstanceApi$_save_closure5.doCall(GormInstanceApi.groovy:179)
        at sun.reflect.GeneratedMethodAccessor112.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
        at groovy.lang.Closure.call(Closure.java:418)
        at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom(ConvertedClosure.java:54)
        at org.codehaus.groovy.runtime.ConversionHandler.invoke(ConversionHandler.java:124)
        at com.sun.proxy.$Proxy111.doInSession(Unknown Source)
        at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:319)
        at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:40)
        at org.grails.datastore.gorm.GormInstanceApi.save(GormInstanceApi.groovy:178)
        at org.grails.datastore.gorm.GormEntity$Trait$Helper.save(GormEntity.groovy:151)
        at org.grails.datastore.gorm.GormEntity$Trait$Helper$save.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
        at [domain].Tracking.save(Tracking.groovy)
        at [domain].Tracking.save(Tracking.groovy)
        at org.grails.datastore.gorm.GormEntity$save$0.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:128)
        at autovision.web.BootStrap$_closure1.doCall(BootStrap.groovy:139)
        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.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:98)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:264)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1099)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1034)
        at groovy.lang.Closure.call(Closure.java:418)
        at groovy.lang.Closure.call(Closure.java:412)
        at grails.util.Environment.evaluateEnvironmentSpecificBlock(Environment.java:541)
        at grails.util.Environment.executeForEnvironment(Environment.java:534)
        at grails.util.Environment.executeForCurrentEnvironment(Environment.java:510)
        at org.grails.web.servlet.boostrap.DefaultGrailsBootstrapClass.callInit(DefaultGrailsBootstrapClass.java:74)
        at org.grails.web.servlet.context.GrailsConfigUtils.executeGrailsBootstraps(GrailsConfigUtils.java:65)
        at org.grails.plugins.web.servlet.context.BootStrapClassRunner.onStartup(BootStrapClassRunner.groovy:53)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy:261)
        at grails.boot.config.GrailsApplicationPostProcessor.onApplicationEvent(GrailsApplicationPostProcessor.groovy)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
        at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:393)
        at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:347)
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:883)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.finishRefresh(EmbeddedWebApplicationContext.java:144)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546)
        at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:84)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:393)
        at grails.boot.GrailsApp.run(GrailsApp.groovy:380)
        at grails.boot.GrailsApp$run.call(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
        at autovision.web.Application.main(Application.groovy:8)

Это происходит, когда я пытаюсь вставить новый объект отслеживания в БД следующим образом:

  Tracking tp = new Tracking()
  tp.setUser(user)
  nowCal.add(Calendar.MINUTE,i++)
  tp.setCreated(nowCal.getTime())
  tp.setSpeed(10f)
  tp.setLocation(new Point(points[1],points[0]))
  tp.save(flush:true)

  user.addToTracking(tp);

И мой класс отслеживания определен так:

import grails.mongodb.geo.Point

class Tracking {

    Point location

    Date created

    float speed

    static belongsTo = [user:User]

    static constraints = {
        speed nullable:true
    }

    static mapping = {
        location geoIndex:'2dsphere'
    }
}

Я действительно не вижу, в чем проблема, я думаю, что я все правильно определил, как показано в документации GORM: http://gorm.grails.org/latest/mongodb/manual/#geoSpatial

Другое дело, что этот код прекрасно работает при работе в режиме без поддержки.

так что выполнение grails run-app работает, но grails prod run-app не ..

Любая помощь будет высоко ценится.

Спасибо

Lee.

1 Ответ

0 голосов
/ 24 ноября 2018

У меня была такая же проблема, и после двух дней отладки наконец-то нашли обходной путь.

Проблема была вызвана следующим:

  • Существует служебный класс Grails под названием org.grails.datastore.mapping.reflect.FieldEntityAccess, который, очевидно, используется для доступа к полям сущностей с помощью отражения. Этот класс имеет внутренний класс с именем FieldEntityReflector. Каждый раз, когда создается экземпляр FieldEntityAccess, создается экземпляр FieldEntityReflector, созданный внутри. Все эти экземпляры хранятся в статической карте с именем REFLECTORS, ключами которой являются имена сущностей, очевидно, из соображений производительности.
  • Во время инициализации компонента, компонент mongoDatastore создает один FieldEntityAccess для каждого объекта, передавая DocumentPersistentEntity в качестве параметра конструктора.
  • Таким же образом, компонент grailsDomainClassMappingContext, не зная о mongoDatastore, создает свой собственный FieldEntityAccess для каждой сущности, передавая KeyValuePersistentEntity в качестве параметра. Эти FieldEntityAccess экземпляры и соответствующие им EntityReflectors не знают о монго и поэтому не поддерживают специфические для монго типы, такие как Point.
  • Учитывая, что REFLECTORS ключи карты являются именами сущностей, EntityReflectors, созданных последними для той же сущности, переопределяют ранее созданные отражатели и используются всеми EntityReflector экземплярами.
  • Когда grailsDomainClassMappingContext отражатели создаются последними, они используются, когда монго пытается сохранить и создать сущность и, следовательно, выдать ошибку.

Короче говоря, ошибка генерируется, когда grailsDomainClassMappingContext bean инициализируется после mongoDatastore bean.

В режиме разработки плагин UrlMappingsGrailsPlugin создает некоторые bean-компоненты, используемые для перезагрузки отображений URL. Эти бобы запускают создание экземпляра grailsDomainClassMappingContext bean перед mongoDatastore bean. Поскольку бобы Монго создаются позже, ошибка не выдается. Но в производственном режиме эти компоненты не создаются, и mongoDatastore создается до grailsDomainClassMappingContext, поэтому возникает ошибка.

Потенциальные решения

  1. Принудительно grailsDomainClassMappingContext создание экземпляра бина до mongoDatastore: Я не смог сделать это после нескольких попыток, возможно, из-за логики создания бина Grails.
  2. Принудительно UrlMappingsGrailsPlugin создание экземпляров даже в производственном режиме: Я предпочел не идти этим путем из-за возможных последствий для производительности.
  3. Используйте статический метод clearReflectors из FieldEntityAccess class , чтобы очистить все отражатели после инициализации системы: ** Я решил сделать это, и система начала работать. Я не тестировал его подробно, но смог правильно сохранить Point.

Чтобы вызвать метод, я создал бин в зависимости от grailsDomainClassMappingContext и mongoDatastore и вызвал FieldEntityAccess.clearReflectors()

package app.utils

import org.grails.datastore.mapping.mongo.MongoDatastore
import org.grails.datastore.mapping.reflect.FieldEntityAccess
import org.grails.datastore.mapping.model.MappingContext

class MongoDatastoreHolder {

    MongoDatastore mongo

    MappingContext context

    MongoDatastoreHolder(MappingContext context, MongoDatastore mongo) {
        this.context = context
        this.mongo = mongo
        FieldEntityAccess.clearReflectors()
    }
}

И определили этот боб в resources.groovy:

import app.utils.MongoDatastoreHolder

beans = {
    mongoDatastoreHolder(MongoDatastoreHolder, ref('grailsDomainClassMappingContext'), ref('mongoDatastore')) { bean ->
        bean.lazyInit = false
    }
}

Надеюсь, это поможет, и извините за мой плохой английский, это мой первый ответ на StackOverflow.

...