Grails Webflow — удержание вещей *вне* области потока

Я что-то упускаю....

У меня есть веб-поток Grails, который выглядит так:

def childFlow = {
        start {
            action {
                def targets = []
                Target.list().each {target ->
                    targets.add(new TargetCommand(name: target.name, id: target.id))
                }
                log.debug "targets are $targets"
                [children: targets]
            }
            on('success').to('selectChild')
        }
        ...

TargetCommand является сериализуемым. но я получаю эту ошибку: -

Caused by: java.io.NotSerializableException: com.nerderg.groupie.donate.Target

По какой-то причине «целевой» объект, который находится внутри замыкания Target.list().each {}, помещается в область потока, и я не могу понять, как пометить его как переходный.

У меня есть некоторый код в службе, в которой есть объекты, помещенные в область потока, когда я тоже этого не хочу.

Как остановить локальные переходные переменные в замыканиях, помещаемых в область потока?


person pmc    schedule 07.11.2009    source источник
comment
на самом деле Target.list() - это то, что помещает целевые объекты в сеанс и, следовательно, в поток.   -  person pmc    schedule 07.11.2009


Ответы (4)


Уточняя приведенный выше ответ, вместо очистки persistenceContext мы просто удаляем экземпляры по мере их завершения, например:

    Target.list().each {
        targets.add(new TargetCommand(name: it.name, id: it.id))
        flow.persistenceContext.evict(it)
    }

Это все еще обходной путь для невозможности пометить переменные закрытия как переходные.

person pmc    schedule 07.11.2009

Ответ на мой вопрос:

объект потока представляет собой карту, которая содержит ссылку на «persistenceContext», который является org.hibernate.impl.SessionImpl, поэтому поток пытается сохранить весь сеанс, даже если объекты не изменены (я полагаю, для контекста)

этот неправильный пример из документа Grails 1.1.x дает нам подсказку, что делать:

processPurchaseOrder  {
     action {
         def a =  flow.address
         def p = flow.person
         def pd = flow.paymentDetails
         def cartItems = flow.cartItems
         flow.clear()

    def o = new Order(person:p, shippingAddress:a, paymentDetails:pd) 
    o.invoiceNumber = new Random().nextInt(9999999) cartItems.each { o.addToItems(it) }
    o.save() 
    [order:o] } 
    on("error").to "confirmPurchase" 
    on(Exception).to "confirmPurchase" 
    on("success").to "displayInvoice" 
}

Функция flow.clear() очищает всю карту потока, включая persistenceContext или сеанс, что затем приводит к сбою всего потока из-за отсутствия сеанса.

поэтому промежуточное «решение» состоит в том, чтобы использовать persistenceContext и в этом случае очистить его. Итак, это работает: -

def childFlow = {
        start {
            action {
                sponsorService.updateTargetsFromTaggedContent()
                def targets = []

                Target.list().each {
                    targets.add(new TargetCommand(name: it.name, id: it.id))
                }

                flow.persistenceContext.clear()
                [children: targets]
            }
            on('success').to('selectChild')
            on(Exception).to 'finish'
        }

Очевидная проблема заключается в том, что сеанс очищается полностью, вместо того, чтобы просто оставлять в потоке то, что мне не нужно.

person pmc    schedule 07.11.2009
comment
Спасибо. Я потратил впустую день, ошеломленный этим, пока не увидел ваш ответ. Очень странное поведение... не уверен, почему поток должен сохранять весь сеанс гибернации по умолчанию, но его очистка работает для меня. - person Martin Dow; 25.10.2010
comment
Очень поздно днем, но это, по-видимому, сделано для того, чтобы разговоры работали. Альтернативное решение — сделать любые классы предметной области, к которым можно получить доступ из потока, сериализуемыми. - person Peter Ledbrook; 29.11.2010
comment
Кстати, я поднял вопрос по этому поводу: jira.codehaus.org/browse/GRAILS -6984 - person Martin Dow; 30.11.2010

за неимением лучшего способа, вот обобщенное решение, которое удаляет любые несериализуемые объекты из persistenceContext потока. Это может быть метод обслуживания с учетом потока: -

def remove = []
flow.persistenceContext.getPersistenceContext().getEntitiesByKey().values().each { entity ->
    if(!entity instanceof Serializable){
        remove.add(entity)
    }
}
remove.each {flow.persistenceContext.evict(it)}
person pmc    schedule 07.11.2009
comment
Что все хорошо, пока вы не используете тег в представлении, которое выбирает объект домена. Я думаю, что либо веб-поток не создан для этого, либо это тупиковый импл. - person pmc; 07.11.2009
comment
исправлена ​​проблема с тегом путем реализации нового тега, который вызывает flowService.cleanUpSession(flow) — например, ‹nerderg:cleanupflow поток=${this}/› - person pmc; 07.11.2009
comment
Обратите внимание, что это работает только в первом действии состояния. Другие вещи, которые, похоже, работают, - это отсоединение рассматриваемого объекта домена. Если все остальное не удается реализовать сериализуемое: -/ - person pmc; 16.11.2009

Если, как и я, вам нужно выселить всех, может быть, вам нравится это делать.

flow.persistenceContext.flush()
flow.persistenceContext.persistenceContext.clear()
person Fabiano Taioli    schedule 18.10.2012