【问题标题】:Point not a valid property - MongoDB & Grails 3.3+Point not a valid property - MongoDB & Grails 3.3+
【发布时间】:2019-04-08 20:18:39
【问题描述】:

在 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);

我的 Tracking 类是这样定义的:

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

另一件事是这段代码在非 prod 模式下运行时运行良好。

所以执行 grails run-app 有效,但 grails prod run-app 无效..

任何帮助将不胜感激。

谢谢

李。

【问题讨论】:

    标签: mongodb grails grails-orm geospatial geo


    【解决方案1】:

    我也遇到了同样的问题,经过两天的调试终于找到了解决办法。

    问题是由以下原因引起的:

    • 有一个名为org.grails.datastore.mapping.reflect.FieldEntityAccess 的Grails 实用程序类,显然用于使用反射访问实体字段。该类有一个名为FieldEntityReflector 的内部类。每次创建FieldEntityAccess 实例时,都会在内部创建一个FieldEntityReflector 实例。所有这些实例都存储在名为 REFLECTORS 的静态映射中,其键是实体名称,显然是出于性能原因。
    • 在 bean 初始化期间,mongoDatastore bean 为每个实体创建一个 FieldEntityAccess,并传递一个 DocumentPersistentEntity 作为构造函数参数。
    • 同样,grailsDomainClassMappingContext bean,不知道mongoDatastore 为每个实体创建自己的FieldEntityAccess,将KeyValuePersistentEntity 作为参数传递下来。那些FieldEntityAccess 实例和它们对应的EntityReflectors 不知道mongo,因此不支持像Point 这样的mongo 特定类型。
    • 鉴于 REFLECTORS 映射键是实体名称,EntityReflectors 为同一实体最后创建,覆盖先前创建的反射器,并被所有 EntityReflector 实例使用。
    • grailsDomainClassMappingContext 反射器最后创建时,它们会在 mongo 尝试持久化和实体化并因此引发错误时使用。

    简而言之,grailsDomainClassMappingContext bean 在mongoDatastore bean 之后初始化时会抛出错误。

    在开发模式下,UrlMappingsGrailsPlugin 插件会创建一些 bean,用于允许重新加载 url 映射。这些 bean 在 mongoDatastore bean 之前触发 grailsDomainClassMappingContext bean 的实例化。由于稍后创建了 mongo bean,因此不会引发错误。但是,在生产模式下,并没有创建这些 bean,并且 mongoDatastore 是在 grailsDomainClassMappingContext 之前创建的,因此会引发错误。

    可能的解决方案

    1. mongoDatastore 之前强制grailsDomainClassMappingContext bean 实例化:经过多次尝试,我无法做到这一点,可能是因为grails bean 实例化逻辑。
    2. 即使在生产模式下也强制 UrlMappingsGrailsPlugin 实例化:由于可能会影响性能,我不想这样做。
    3. 使用FieldEntityAccess类的静态方法clearReflectors在系统初始化后清除所有反射器:**我决定这样做,系统开始工作。我尚未对其进行深入测试,但能够正确坚持 Point

    为了调用该方法,我根据grailsDomainClassMappingContextmongoDatastore 创建了一个bean,并调用了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中定义了那个bean:

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

    希望对您有所帮助,抱歉我的英语不好,这是我的第一个 StackOverflow 答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 1970-01-01
      • 2013-03-02
      • 2017-04-01
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      相关资源
      最近更新 更多