Подтвердить что ты не робот

Связывание JSON с вложенными объектами домена Grails

Я разрабатываю интерфейс RESTful, который используется для предоставления данных JSON для приложения JavaScript.

На стороне сервера я использую Grails 1.3.7 и использую объекты домена GORM для сохранения. Я реализовал пользовательский JSON Marshaller для поддержки сортировки объектов вложенных доменов.

Вот примеры объектов домена:

class SampleDomain {
    static mapping = { nest2 cascade: 'all' }
    String someString
    SampleDomainNested nest2
}

и

class SampleDomainNested {
    String someField
}

Ресурс SampleDomain публикуется под URL/rs/sample/so/rs/sample/1 указывает на объект SampleDomain с идентификатором 1

Когда я создаю ресурс с помощью моего настраиваемого json marshaller (GET on/rs/sample/1), я получаю следующие данные:

{
    "someString" : "somevalue1",
    "nest2" : {
        "someField" : "someothervalue"
    }
}

что именно то, что я хочу.

Теперь возникает проблема: я пытаюсь отправить те же данные в ресурс /rs/sample/ 1 через PUT.

Чтобы связать json-данные с объектом Domain, контроллер, обрабатывающий запрос, вызывает def domain = SampleDomain.get(id) и domain.properties = data, где данные являются немаршаллированным объектом.

Связывание для поля "someString" работает нормально, но вложенный объект не заполняется с помощью вложенных данных, поэтому я получаю сообщение об ошибке, что свойство "nest2" имеет значение null, что не разрешено.

Я уже пробовал реализовать пользовательский PropertyEditorSupport, а также StructuredPropertyEditor и зарегистрировать редактор для этого класса.

Странно, редактор вызывается только при поставке не-вложенных значений. Поэтому, когда я посылаю следующее на сервер через PUT (что не имеет никакого смысла;))

{
    "someString" : "somevalue1",
    "nest2" : "test"
}

по крайней мере вызывается редактор свойств.

Я посмотрел код GrailsDataBinder. Я выяснил, что параметры настройки ассоциации, похоже, работают, указывая путь ассоциации вместо предоставления карты, поэтому также работает следующее:

{
    "someString" : "somevalue1",
    "nest2.somefield" : "someothervalue"
}

но это не помогает мне, так как я не хочу реализовывать собственный JavaScript для JSON-сериализатора объектов.

Можно ли использовать привязку данных Grails с помощью вложенных карт? Или действительно ли я реализую это вручную для каждого класса домена?

Большое спасибо,

Martin

4b9b3361

Ответ 1

Поскольку этот вопрос поднялся несколько раз, я хотел бы поделиться тем, что я сделал в конце:

Поскольку у меня было еще несколько требований к реализации, таких как безопасность и т.д., я реализовал уровень сервиса, который скрывает объекты домена от контроллеров. Я ввел "динамический слой DTO", который переводит объекты домена на Groovy Карты, которые можно легко сериализовать с помощью стандартных сериализаторов и который вручную обновляет. Все решения полуавтоматического/метапрограммного/командного шаблона /..., которые я попытался реализовать в какой-то момент, в большинстве случаев приводят к появлению странных ошибок GORM или большого количества кода конфигурации (и большого разочарования). Методы обновления и сериализации для DTO довольно просты и могут быть реализованы очень быстро. Он также не вводит много дублирующего кода, так как вам нужно указать, как ваши объекты домена сериализуются в любом случае, если вы не хотите публиковать структуру своего внутреннего домена. Возможно, это не самое элегантное решение, но это единственное решение, которое действительно сработало для меня. Это также позволяет мне реализовывать пакетные обновления, поскольку логика обновления больше не связана с http-запросами.

Однако я должен сказать, что я не думаю, что grails - это соответствующий технический стек, наиболее подходящий для такого приложения, поскольку он делает ваше приложение очень тяжелым и неустойчивым. Мой опыт в том, что, как только вы начинаете делать вещи, которые по умолчанию не поддерживаются каркасом, он начинает запутываться. Кроме того, мне не нравится тот факт, что слой "репозиторий" в grails по существу существует только как часть объектов домена, который ввел множество проблем и привел к нескольким "прокси-сервисам", имитирующим уровень репозитория. Если вы начнете создавать приложение, используя интерфейс json rest, я бы предложил либо пойти на очень легкую технологию, например node.js, либо, если вы хотите/должны придерживаться стека на основе java, используйте стандартный spring framework + spring mvc + spring с хорошим и чистым dto-слоем (это то, к чему я перешел, и он работает как шарм). Вам не нужно писать много кода шаблона, и вы полностью контролируете то, что на самом деле происходит. Кроме того, вы получаете сильную типизацию, которая повышает производительность разработчиков, а также ремонтопригодность и которая легитимирует дополнительные LOC. И, конечно, сильный ввод текста означает сильное оснащение!

Я начал писать запись в блоге, описывающую архитектуру, в которой я придумал (с образцом проекта, конечно), однако у меня нет много времени, чтобы закончить его. Когда это будет сделано, я свяжусь с ним здесь для справки.

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

Ура!

Ответ 2

Требуется указать имя класса:

{ class:"SampleDomain", someString: "abc", 
nest2: { class: "SampleDomainNested", someField:"def" }
} 

Я знаю, для этого требуется другой ввод, который он производит.

Как я уже упоминал в комментарии ранее, вам может быть лучше использовать библиотеку gson.

Ответ 3

Не уверен, почему вы написали свой собственный json marshaller с xstream вокруг.

См. http://x-stream.github.io/json-tutorial.html

Мы очень довольны xstream для наших сервисов back-end (на основе Grails) и таким образом вы можете отображать marshall в xml или json или переопределять сортировку по умолчанию для определенного объекта, если хотите.

Кажется, что Jettison создает более компактный, менее читаемый JSON, и вы можете столкнуться с некоторыми материалами столкновения с библиотекой, но встроенный рендеринг потока json по умолчанию является достойным.

Если вы собираетесь опубликовать эту услугу для общественности, вам нужно будет потратить время на возврат соответствующих ответов HTTP-протокола на ошибки и т.д. ($.02)