Grails REST-обновление свойства коллекции на аннотированном ресурсе домен не работает - PullRequest
1 голос
/ 08 октября 2019

У меня очень странная проблема с @Resource аннотированными классами Домена и автоматически сгенерированным RestfulController для указанных классов. В частности, моя сущность Domain Product имеет свойство Collection hasMany parts в типе Part, и я пытаюсь использовать PUT для обновления parts в экземпляре Product, и обновление не работает.

Моя содержащаяся в домене сущность Product, которая определяется следующим образом:

package com.test

import grails.rest.Resource

@Resource(uri='/rest/product', formats=['json', 'xml'])
class Product
{
  Integer completed  // Completed quantity
  Set<Part> parts    // Each requested product has a list of requested parts

  static hasMany = [parts: Part]

  static constraints = {
    parts minSize: 1
  }
}

, а определение моей части следующее:

package com.test

import grails.rest.Resource

@Resource(uri='/rest/part', formats=['json', 'xml'])
class Part
{
  String identifier // Each part must have an identifier
  Double weight     // How much does each unit of this product part weigh
  Product product   // The product request that this part request belongs to

  static belongsTo = [product: Product]

  static constraints = {
  }
}

В моем BootStrap.groovy Я уже создал две части, каждая для двух продуктов (всего 4 части).

package broken.put.array.property

import com.test.Product
import com.test.Part

class BootStrap {

    def init = { servletContext ->
      Product product = Product.findOrSaveWhere(completed: 4)
      product.addToParts(new Part(product: product, weight: 1237, identifier: "part1").save(failOnError: true, flush: true))
      product.addToParts(new Part(product: product, weight: 1236, identifier: "part2").save(failOnError: true, flush: true))
      product.save(failOnError: true, flush: true)
      Product product2 = Product.findOrSaveWhere(completed: 3)
      product2.addToParts(new Part(product: product2, weight: 1235, identifier: "part3").save(failOnError: true, flush: true))
      product2.addToParts(new Part(product: product2, weight: 1234, identifier: "part4").save(failOnError: true, flush: true))
      product2.save(failOnError: true, flush: true)
    }
    def destroy = {
    }
}

Итак, после запуска приложения я делаю следующее:

$ curl -X PUT "http://localhost:8080/product/1" -H "Content-Type:application/json" -d '{"parts" : [{ "id": 1 }], "completed": 3}'

, чтобы обновить свойство parts Collection Product с идентификатором 1 из 2 частей в1 частьПо какой-то причине обновление всегда заканчивается тем, что на самом деле не изменяет свойство parts вообще, как видно из ответа JSON:

{"id":1,"parts":[{"id":2},{"id":1}],"completed":3}

Поэтому я решил отладить это, добавив в мою @Resource аннотацию *Атрибут 1030 *, который указывает на мой собственный контроллер, где я могу сделать println. Я скопировал тело метода update() из стандартного RestfulController и добавил в него операторы println, чтобы выяснить, где может быть проблема. После некоторых экспериментов я узнал, что после установки instance.properties в getObjectToBind() коллекция parts внутри по-прежнему имеет старые значения (объекты Part с ID 1 и 2) вместо того, что я отправила в теле JSONPUT (один объект Part с идентификатором 1).

Но я обнаружил еще кое-что очень удивительное, если бы поместил оператор println, выводящий instance.properties ДО строки, где он установлен на getObjectToBind(), обновление PUT неожиданно работает с моим предполагаемым поведением. Ничего кроме этого места не подойдет. И это должно быть печать содержимого instance.properties.

Поскольку я понимаю, что это граничит с voodoo, я создал проект изолированного тестового примера в виде zip-файла, который я загрузил в TinyUpload . Моя версия Grails 3.3.6. Хотелось бы услышать от любого, кто когда-либо видел это, или кто может помочь мне понять, почему это происходит. Все, что вам нужно сделать, это разархивировать zip-файл в папку и запустить его с помощью grails dev run-app. В текущем состоянии кода строка println (строка 42) закомментирована в src/main/groovy/com/test/ReactAdminRestfulController.groovy, поэтому вы можете видеть то, что я описал выше. Но раскомментирование этой строки и перезапуск приложения приведут к правильному поведению.

...