Подключение делегирования Groovy MOP к представлению - StackruError

Я новичок в Groovy и Grails, и пытался работать над делегированием, просматривая эту статью: http://groovy.codehaus.org/Replace+Inheritance+with+Delegation.

Используя сгенерированные по умолчанию представления в Netbeans, он создал соответствующие поля формы, когда я следую примерам наследования и делегирования, но в примере MOP он создал только поле локальной переменной. Если я использую формы, сгенерированные в предыдущих примерах, я получаю StackruError.

2014-03-20 08:39:32,569 [http-bio-8080-exec-7] ERROR errors.GrailsExceptionResolver  - StackruError occurred when processing request: [GET] /Delegation/attendee/create
Stacktrace follows:
Message: Error processing GroovyPageView: Error executing tag <g:form>: Error executing tag <g:render>: null
    Line | Method
->>  530 | doFilter  in C:\development\sandbox\Delegation\grails-app\views\attendee\create.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Caused by GrailsTagException: Error executing tag <g:form>: Error executing tag <g:render>: null
->>   36 | doCall    in C:/development/sandbox/Delegation/grails-app/views/attendee/create.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Caused by GrailsTagException: Error executing tag <g:render>: null
->>   31 | doCall    in C:/development/sandbox/Delegation/grails-app/views/attendee/create.gsp
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
Caused by StackruError: null
->> 2037 | get       in java.util.Collections$SynchronizedMap
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
|     11 | doCall    in delegation.Attendee$_hasLocalProperty_closure2
|     29 | getProperty in delegation.Attendee
|     30 | getProperty in     ''
....
|Compiling 1 source files

Как мне связать вид с примером MOP?

Обновление: добавление классов View, Domain и Controller.

Домен:

class Attendee {

  enum AttendeeRole {
    VENDOR, PRESENTER, STUDENT
  }

  private person = new Person()
  private hasLocalProperty(name) {
    metaClass.properties.collect{ it.name }.contains(name)
  }

  AttendeeRole role

  Attendee (Map map) {
    map.each{ k, v -> setProperty(k, v) }
  }

  void setProperty(String name, value) {
    if (hasLocalProperty(name)) this.@"$name" = value 
    else delegate.setProperty(name, value)
  }

  def getProperty(String name) {
    if (hasLocalProperty(name)) return this.@"$name"
    else return delegate.getProperty(name)
  }

}

Человек:

class Person {
  String firstName
  String lastName
  Integer age

  static constraints = {
    lastName blank: false
    firstName blank: false
    age min: 18
  }

  def describe() {"$firstName $lastName is $age"}
}

Вид (генерируется при наследовании):

<%@ page import="delegation.Attendee" %>

<div class="fieldcontain ${hasErrors(bean: attendeeInstance, field: 'lastName', 'has-error')} required form-group">
  <label for="lastName" class="control-label col-sm-2">
    <g:message code="attendee.lastName.label" default="Last Name" />
    <span class="required-indicator">*</span>
  </label>
  <div class="col-sm-3">
    <g:textField class="form-control" name="lastName" required="" value="${attendeeInstance?.lastName}"/>

  </div>
</div>

<div class="fieldcontain ${hasErrors(bean: attendeeInstance, field: 'firstName', 'has-error')} required form-group">
  <label for="firstName" class="control-label col-sm-2">
    <g:message code="attendee.firstName.label" default="First Name" />
    <span class="required-indicator">*</span>
  </label>
  <div class="col-sm-3">
    <g:textField class="form-control" name="firstName" required="" value="${attendeeInstance?.firstName}"/>

  </div>
</div>

<div class="fieldcontain ${hasErrors(bean: attendeeInstance, field: 'age', 'has-error')} required form-group">
  <label for="age" class="control-label col-sm-2">
    <g:message code="attendee.age.label" default="Age" />
    <span class="required-indicator">*</span>
  </label>
  <div class="col-sm-3">
    <g:field class="form-control" name="age" type="number" min="18" value="${attendeeInstance.age}" required=""/>

  </div>
</div>


<div class="fieldcontain ${hasErrors(bean: attendeeInstance, field: 'role', 'has-error')} required form-group">
  <label for="role" class="control-label col-sm-2">
    <g:message code="attendee.role.label" default="Role" />
    <span class="required-indicator">*</span>
  </label>
  <div class="col-sm-3">
    <g:select class="form-control" name="role" from="${delegation.Attendee$AttendeeRole?.values()}" keys="${delegation.Attendee$AttendeeRole.values()*.name()}" required="" value="${attendeeInstance?.role?.name()}" />

  </div>
</div>

Вид, созданный с помощью MOP:

<%@ page import="delegation.Attendee" %>

<div class="fieldcontain ${hasErrors(bean: attendeeInstance, field: 'role', 'has-error')} required form-group">
  <label for="role" class="control-label col-sm-2">
    <g:message code="attendee.role.label" default="Role" />
    <span class="required-indicator">*</span>
  </label>
  <div class="col-sm-3">
    <g:select class="form-control" name="role" from="${delegation.Attendee$AttendeeRole?.values()}" keys="${delegation.Attendee$AttendeeRole.values()*.name()}" required="" value="${attendeeInstance?.role?.name()}" />

  </div>
</div>

Класс контроллера:

import static org.springframework.http.HttpStatus.*
import grails.transaction.Transactional

@Transactional(readOnly = true)
class AttendeeController {

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond Attendee.list(params), model:[attendeeInstanceCount: Attendee.count()]
    }

    def show(Attendee attendeeInstance) {
        respond attendeeInstance
    }

    def create() {
        respond new Attendee(params)
    }

    @Transactional
    def save(Attendee attendeeInstance) {
        if (attendeeInstance == null) {
            notFound()
            return
        }

        if (attendeeInstance.hasErrors()) {
            respond attendeeInstance.errors, view:'create'
            return
        }

        attendeeInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'attendeeInstance.label', default: 'Attendee'), attendeeInstance.id])
                redirect attendeeInstance
            }
            '*' { respond attendeeInstance, [status: CREATED] }
        }
    }

    def edit(Attendee attendeeInstance) {
        respond attendeeInstance
    }

    @Transactional
    def update(Attendee attendeeInstance) {
        if (attendeeInstance == null) {
            notFound()
            return
        }

        if (attendeeInstance.hasErrors()) {
            respond attendeeInstance.errors, view:'edit'
            return
        }

        attendeeInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'Attendee.label', default: 'Attendee'), attendeeInstance.id])
                redirect attendeeInstance
            }
            '*'{ respond attendeeInstance, [status: OK] }
        }
    }

    @Transactional
    def delete(Attendee attendeeInstance) {

        if (attendeeInstance == null) {
            notFound()
            return
        }

        attendeeInstance.delete flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'Attendee.label', default: 'Attendee'), attendeeInstance.id])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'attendeeInstance.label', default: 'Attendee'), params.id])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }
}

0 ответов

Другие вопросы по тегам