grails 4没有枚举常量?

Posted

技术标签:

【中文标题】grails 4没有枚举常量?【英文标题】:grails 4 no enum constant? 【发布时间】:2022-01-11 11:46:06 【问题描述】:

我正在将我的 grails 2 应用程序升级到 grails 4。我已经能够更正所有编译时错误,现在应用程序可以运行。它会在点击控制器操作时引发此错误。

No enum constant com.company.compositeEvent.ResultsStatus.2

在控制器的这一行

if (idList)
            result = RaceGroup.createCriteria().list([sort: 'startDateTime', order: 'asc', offset: offset, max: max])
                inList('id', idList)
                join 'address'
            
        

RaceGroup 有 resultsstatus 属性

ResultsStatus resultsStatus

ResultStatus 是一个枚举,定义为

enum ResultsStatus 

    NO_RESULTS(1),
    RACE_RESULTS(2),
    EXTERNAL_RESULTS(3)

    int id

    private ResultsStatus(int id)
        this.id = id
    


它在 grails 2 中运行良好。我怀疑 grails 4 中发生了一些变化,也许定义枚举的方式是错误的。我感谢任何指导。

更新:

RaceGroup 域定义为

class RaceGroup extends CompositeEvent implements Serializable

    List<Race> races

    static hasMany = [races: Race]
    static mappedBy = [races: 'raceGroup']

    static mapping = 
        discriminator RaceGroup.getSimpleName()
        races cascade: 'all-delete-orphan'
    

    
    static constraints = 
        
    
    
    
    
    
    List<SubEvent> getSubEvents()
        this.races
    

CompositeEvent 定义为

abstract class CompositeEvent extends BaseEntity implements Serializable, Named, Addressable


    EventGroup eventGroup


    /**
     * Currency to use for this Event. Defaults to 'USD'
     */
    final Currency currency = Currency.getInstance('USD')
    
    /**
     * User that created this event.
     */
    User user
    /**
     * Name of this overall event.
     * <p>
     * 'compositeEventName' is used instead of just 'name' because when sorting
     * by name, billingPerson.name is used by grails.
     */
    String compositeEventName
    /**
     * General Information that is entered by the director and displayed on 
     * the registration page. 
     */
    String displayMessage
    /**
     * Location name of the address of this event
     */
    String locationName
    /**
     * Address of this event.
     * <p>
     * Address is stored as one of its sub-classes: USAddress, CanadaAddress,
     * etc.
     */
    Address address

    /**
     * Start date and time of this event.
     */ 
    Date startDateTime
    
    /**
     * Time zone to display the formatted date in.
     */
    TimeZone timeZone
    
    /**
     * End date of this event.
     */
    SqlDate endDate
    
    /**
     * The total number of possible participants, number reserved spots,
     * and the number of allocated spots.
     */
    Capacity capacity = new Capacity(reference: this)


    String token = UUID.randomUUID().toString().replaceAll('-', '').take(12)

    Boolean autoTransferToV6Active


    Boolean showMaxParticipantsLimitInRegistrationPage = false
    Integer showMaxParticipantsLimitBelowThreshold



    /**
     * Director on the registration page listed as being in charge of
     * this event.
     */
    Director director

    /**
     * Person or organization responsible for handling billing and payment
     * in association with this event.
     */
    BillingPerson billingPerson



    String displayLiveRegistrationsPassword


    Boolean displayLiveRegistrations
    /**
     * Whether the list of individuals registered for this event or any of
     * its sub-events will be displayed on the registration page.
     */
    Boolean displayParticipants
    /**
     * Whether the number of individuals registered for this event or any 
     * sub-events will be displayed on the registration page.
     */
    Boolean displayEventRegNum
    /**
     * Whether the teams registered for this event or any sub-events will
     * be displayed on the registration page
     */
    Boolean displayTeams
    /**
     * Whether the number of people in each team will displayed on the
     * registration page.
     */
    Boolean displayTeamRegNum
    /**
     * Whether seed marks will be displayed in the list of participants
     */
    Boolean displaySeedMarks

    /**
     * Whether to display the product photos in the public event page
     */
    Boolean displayProductImages = true



    /**
     * Whether this event is listed among active events and can the
     * registration page can be accessed.
     */
    Boolean published = false // whether this composite event can be viewed
    Boolean unlisted = false // whether this composite event is listed on the website
    Boolean emailReceipts = true // email a receipt each time someone registers


    /**
     * The date from which age will be calculated for participants.
     * 
     * The date must be:
     * <p><i>
     * this.startDateTime - 1 year <= this.ageAsOf <= this.startDateTime
     * </i>
     */
    SqlDate ageAsOf
    /**
     * External web-site with information regarding this event
     */
    String homePage
    /**
     * Required fields of each participant that are set by the director.
     */
    RequiredParticipantFields requiredFields
    /**
     * Logo for this event
     */
    Image logo
    /**
     * Taxes applied to this event
     */
    Tax tax
    /**
     * Access code to be access registration for all subEvents. An access code
     * set in an order template would be used instead of this if both are set.
     */
    String accessCode
    /**
     * Disclaimer that must be accepted by all participants before registering.
     */
    Disclaimer disclaimer
    /**
     * TimingDetails contains data in regards to requesting and providing
     * timing services from RunnerCard
     */
    TimingDetails timingDetails
    

    //Status of Referral. Whether or not to show the referral or share on facebook button
    ReferralStatus referralStatus
    
    
    String bibsRange
    
    Boolean assignBibNumbers

    //in registration form whether to allow user to select more than 1 shirt
    Boolean allowMultiProductSelectionInRegistration


    //in event registration page show products only purchase
    Boolean enableProductsOnlyPurchase = true


    Boolean enableVirtualRace


    /**
     * Ids of past events all separated by a delimiter comma (,)
     * eg 51243, 51234, 64345, 43454
     */
    String eventHistory 
    
    
    Set<Product> products



    String resultsLink
    ResultsStatus resultsStatus


    // automatically updated by GORM
    Date dateCreated
    Date lastUpdated
    
    abstract List<SubEvent> getSubEvents()

    static transients = ['name', 'nameIdAndParticipants']

    static hasMany = [products: Product]

    //static belongsTo = [eventGroup: EventGroup]

    static mapping = 
        address cascade: 'all'
        director cascade: 'save-update,merge,refresh,evict,lock'
        displayMessage type: 'text'

        requiredFields unique: true
        capacity cascade: 'refresh,delete'

        bibsRange type: 'text'
    

    static namedQueries = 
        withAddress
            join 'address'
        
        withBilling
            join 'billingPerson'
        
        withRequiredFields
            join 'requiredFields'
        
    

    static constraints = 
        compositeEventName blank: false

        showMaxParticipantsLimitInRegistrationPage nullable: true
        showMaxParticipantsLimitBelowThreshold nullable: true

        autoTransferToV6Active nullable: true

        enableVirtualRace nullable: true
        eventGroup nullable: true

        eventHistory blank:true, nullable: true
        displayMessage blank: false, nullable: true
        locationName blank: false
        referralStatus nullable: true
        bibsRange nullable:true
        assignBibNumbers nullable: true
        allowMultiProductSelectionInRegistration nullable: true

        enableProductsOnlyPurchase nullable: true
        address()
    
        
        timeZone bindable: true, inList: TimeService.TIME_ZONES
        endDate validator:  SqlDate endDate, CompositeEvent obj ->
            if (obj.startDateTime == null) return
            Calendar start = Calendar.getInstance()
            start.setTime(obj.startDateTime)
            start.set(Calendar.HOUR_OF_DAY, 0)
            start.set(Calendar.MINUTE, 0)
            start.set(Calendar.SECOND, 0)
            start.set(Calendar.MILLISECOND, 0)
            Date startDay = start.getTime()
            DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, LCH.getLocale())
            if (startDay.compareTo(endDate) > 0)
                return ["default.invalid.min.message", formatter.format(startDay)]
            
        
        director validator:  Director person, CompositeEvent compositeEvent, Errors errors ->
            UtilityService.cascadeValidation(person, 'director', errors)
        
        billingPerson validator:  BillingPerson person, CompositeEvent compositeEvent, Errors errors ->
            UtilityService.cascadeValidation(person, 'billingPerson', errors)
        
        displayParticipants()
        displayEventRegNum()
        displayTeams()
        displayTeamRegNum validator: Boolean val, CompositeEvent obj, Errors errors ->
            if (obj.displayTeams != null && val && !obj.displayTeams)
                errors.rejectValue("displayTeamRegNum", "compositeEvent.invalid.displayTeamRegNum")
            
        
        displaySeedMarks()
        displayProductImages()
        published()

    
        
        homePage blank: false, nullable: true, validator:  String homePage, CompositeEvent compositeEvent ->
            // If it is a url that isn't http:// or https://
            if (compositeEvent.homePage != null
                    && !compositeEvent.homePage.matches('^http(s)?://.*')
                    && compositeEvent.errors.getFieldErrors('homePage').size() == 0)
                return "default.invalid.url.message"
            
        
        
        ageAsOf nullable: true // if null my.calculateAge() will calculate age based on the current Date
        requiredFields nullable: true
        logo nullable: true
        tax nullable: true, validator:  Tax tax, obj, Errors errors ->
            UtilityService.cascadeValidation(tax, 'tax', errors)
        
        accessCode blank: false, nullable: true
        displayLiveRegistrationsPassword nullable: true
        displayLiveRegistrations nullable: true
        resultsLink nullable: true
        resultsStatus nullable: true
        disclaimer()
        timingDetails nullable: true
    
    
    /**
     * Saves capacity of this event at initial save
     */
    void beforeInsert()
        this.capacity.save()
    
    
    void afterInsert()
        CompositeEvent.withNewSession


            def productOwnerSettingService = this.getBean("productOwnerSettingService")
            productOwnerSettingService.createSetting(this)

        
    

    /**
     * Checks that the logged in user has delete or admin privileges on 
     * this object and then deletes all AutoUpdateJob instances and acl
     * objects that reference this object.
     */
    void beforeDelete()
        CompositeEvent.withNewSession
            


            def posc = ProductOwnerSettingCompositeEvent.createCriteria().get()
                eq('event', this)
            

            def setting = posc?.productOwnerSetting

            if(posc)
                posc.delete(flush: true)
            

            if(setting) 
                setting.delete(flush: true)
            


        
        super.beforeDelete()
    
    

    
    
    private Object getBean(String beanName)
        try
            return this.domainClass.grailsApplication.mainContext.getBean(beanName)
        
        catch(NoSuchBeanDefinitionException e)
            return null
        
        catch(MissingPropertyException e)
            return null
        
    
    
    
    
    
    
    
    
    /* (non-Javadoc)
     * @see com.runnercard.Named#getName()
     */
    String getName() this.compositeEventName 
    
    void setName(String name) this.compositeEventName = name 
    

    
    

地址域定义为

abstract class Address extends BaseEntity implements Serializable
    
    String address1
    String address2
    String city
    String area
    String postalCode

    // automatically updated by GORM
    Date dateCreated
    Date lastUpdated
    
    static belongsTo = [User, BillingPerson, CompositeEvent, RaceParticipant,
        EmbeddedRaceParticipant]

    static mapping = 
        discriminator value: Address.getSimpleName(), column: 'country'
    
    
    static constraints = 
        address1 nullable: true
        address2 nullable: true
        city nullable: true
        area nullable: true
        postalCode nullable: true
    

    static List getCountries()
        return ['usa', 'can', 'other']
    
    
    boolean equals(Object obj)
        if (!Address.isInstance(obj)) return false
        
        Address other = (Address) obj
        if (this.address1 == other.address1
                && this.address2 == other.address2
                && this.city == other.city
                && this.area == other.area
                && this.postalCode == other.postalCode)
            return true
        
        else
            return false
        
    

    int hashCode()
        HashCodeBuilder builder = new HashCodeBuilder(1333, 1353)
        if (this.address1) builder.append(this.address1)
        if (this.address2) builder.append(this.address2)
        if (this.city) builder.append(this.city)
        if (this.area) builder.append(this.area)
        if (this.postalCode) builder.append(this.postalCode)
        builder.toHashCode()
    

【问题讨论】:

我无法重现该问题。您能否展示RaceGroup 的完整源代码以及address 指向的内容? 杰夫,我添加了缺少的域类。 racegroup 实际上是抽象 CompositeEvent 类的子类,地址是 CompositeEvent 的属性。感谢您的帮助。 感谢 jeff 找到了解决方案,但现在遇到了另一个问题。由于某种原因 RaceRegistration.createCriteria().list() eq('compositeEvent', raceGroup) 抛出数组越界异常。 "RaceRegistration.createCriteria().list() eq('compositeEvent', raceGroup) 抛出数组越界异常" - 你能展示RaceRegistration 类中的内容吗? compositeEvent 指向? 如果您可以分享一个简单的小示例项目来演示该问题,那就更好了。通常只是创建它就会发现问题所在。 【参考方案1】:

问题是我必须把它放在映射中

    resultsStatus enumType: 'ordinal'

【讨论】:

以上是关于grails 4没有枚举常量?的主要内容,如果未能解决你的问题,请参考以下文章

Grails:将枚举类型的mysql字段映射到域类

如何在 grails 上按枚举排序?

Grails 4:独立端口

Grails 4、Ubuntu 20、嵌入式 Tomcat - 请求中没有多部分文件

IDEA 13 新建grails工程之后并没有配置grails相关配置怎么弄?

Grails 2.3.4 池为空。无法在 30 秒内获取连接