From 7a023eae58a9ba5438f3d4cdfe2294787dc693bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Hron?= Date: Fri, 16 Dec 2022 14:53:10 +0100 Subject: [PATCH 1/2] Added support for multi-template inheritance. --- .../views/_child2MultipleParents.gson | 9 +++++ .../views/_child3MultipleParents.gson | 9 +++++ .../views/_child4MultipleParents.gson | 11 ++++++ json/grails-app/views/_parent4.gson | 7 ++++ .../json/view/JsonViewWritableScript.groovy | 34 ++++++++++++++----- .../plugin/json/view/api/JsonView.groovy | 19 ++++------- .../json/view/api/internal/ParentInfo.groovy | 17 ++++++++++ .../json/view/TemplateInheritanceSpec.groovy | 27 +++++++++++++++ 8 files changed, 112 insertions(+), 21 deletions(-) create mode 100644 json/grails-app/views/_child2MultipleParents.gson create mode 100644 json/grails-app/views/_child3MultipleParents.gson create mode 100644 json/grails-app/views/_child4MultipleParents.gson create mode 100644 json/grails-app/views/_parent4.gson create mode 100644 json/src/main/groovy/grails/plugin/json/view/api/internal/ParentInfo.groovy diff --git a/json/grails-app/views/_child2MultipleParents.gson b/json/grails-app/views/_child2MultipleParents.gson new file mode 100644 index 000000000..90b4610ef --- /dev/null +++ b/json/grails-app/views/_child2MultipleParents.gson @@ -0,0 +1,9 @@ +import grails.plugin.json.view.Player +import groovy.transform.Field + +inherits(template: 'parent2') +inherits(template: 'parent4') + +@Field Player player + +json g.render(player) diff --git a/json/grails-app/views/_child3MultipleParents.gson b/json/grails-app/views/_child3MultipleParents.gson new file mode 100644 index 000000000..a6a377cb1 --- /dev/null +++ b/json/grails-app/views/_child3MultipleParents.gson @@ -0,0 +1,9 @@ +import grails.plugin.json.view.Player +import groovy.transform.Field + +inherits(template: 'parent3') +inherits(template: 'parent4') + +@Field Player player + +json g.render(player, [includes:'name']) diff --git a/json/grails-app/views/_child4MultipleParents.gson b/json/grails-app/views/_child4MultipleParents.gson new file mode 100644 index 000000000..f188161e4 --- /dev/null +++ b/json/grails-app/views/_child4MultipleParents.gson @@ -0,0 +1,11 @@ +import grails.plugin.json.view.Player +import groovy.transform.Field + +inherits(template: 'parent2') +inherits(template: 'parent4') + +@Field Player player + +json { + name player.name +} diff --git a/json/grails-app/views/_parent4.gson b/json/grails-app/views/_parent4.gson new file mode 100644 index 000000000..5af6f3039 --- /dev/null +++ b/json/grails-app/views/_parent4.gson @@ -0,0 +1,7 @@ +import groovy.transform.Field + +@Field Object object + +json { + bar "foo" +} diff --git a/json/src/main/groovy/grails/plugin/json/view/JsonViewWritableScript.groovy b/json/src/main/groovy/grails/plugin/json/view/JsonViewWritableScript.groovy index a3f43d626..bbed80730 100644 --- a/json/src/main/groovy/grails/plugin/json/view/JsonViewWritableScript.groovy +++ b/json/src/main/groovy/grails/plugin/json/view/JsonViewWritableScript.groovy @@ -4,8 +4,10 @@ import grails.plugin.json.builder.JsonOutput import grails.plugin.json.builder.StreamingJsonBuilder import grails.plugin.json.view.api.JsonView import grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper +import grails.plugin.json.view.api.internal.ParentInfo import grails.util.GrailsNameUtils import grails.views.AbstractWritableScript +import grails.views.GrailsViewTemplate import grails.views.api.GrailsView import groovy.transform.CompileStatic import org.grails.buffer.FastStringWriter @@ -46,13 +48,20 @@ abstract class JsonViewWritableScript extends AbstractWritableScript implements * @return */ StreamingJsonBuilder json(@DelegatesTo(value = StreamingJsonBuilder.StreamingJsonDelegate, strategy = Closure.DELEGATE_FIRST) Closure callable) { - if(parentTemplate != null) { + if(parentData.size() > 0) { if (!inline) { out.write(JsonOutput.OPEN_BRACE) } - def parentWritable = prepareParentWritable() - parentWritable.writeTo(out) - resetProcessedObjects() + Iterator parentInfoIt = parentData.iterator() + while ( parentInfoIt.hasNext() ) { + ParentInfo parentInfo = parentInfoIt.next() + def parentWritable = prepareParentWritable(parentInfo.parentTemplate, parentInfo.parentModel) + parentWritable.writeTo(out) + resetProcessedObjects() + if ( parentInfoIt.hasNext() ) { + out.write(JsonOutput.COMMA) + } + } def jsonDelegate = new StreamingJsonBuilder.StreamingJsonDelegate(out, false, generator) callable.setDelegate(jsonDelegate) callable.call() @@ -107,13 +116,20 @@ abstract class JsonViewWritableScript extends AbstractWritableScript implements * @return The json builder */ StreamingJsonBuilder json(JsonOutput.JsonWritable writable) { - if(parentTemplate != null) { + if(parentData.size() > 0) { if (!inline) { out.write(JsonOutput.OPEN_BRACE) } - def parentWritable = prepareParentWritable() - parentWritable.writeTo(out) - resetProcessedObjects() + Iterator parentInfoIt = parentData.iterator() + while ( parentInfoIt.hasNext() ) { + ParentInfo parentInfo = parentInfoIt.next() + def parentWritable = prepareParentWritable(parentInfo.parentTemplate, parentInfo.parentModel) + parentWritable.writeTo(out) + resetProcessedObjects() + if ( parentInfoIt.hasNext() ) { + out.write(JsonOutput.COMMA) + } + } writable.setInline(true) writable.setFirst(false) writable.writeTo(out) @@ -158,7 +174,7 @@ abstract class JsonViewWritableScript extends AbstractWritableScript implements return json } - private GrailsView prepareParentWritable() { + private GrailsView prepareParentWritable(GrailsViewTemplate parentTemplate, Map parentModel) { parentModel.putAll(binding.variables) for(o in binding.variables.values()) { if (o != null) { diff --git a/json/src/main/groovy/grails/plugin/json/view/api/JsonView.groovy b/json/src/main/groovy/grails/plugin/json/view/api/JsonView.groovy index 1f9210152..0cef22a42 100644 --- a/json/src/main/groovy/grails/plugin/json/view/api/JsonView.groovy +++ b/json/src/main/groovy/grails/plugin/json/view/api/JsonView.groovy @@ -5,6 +5,7 @@ import grails.plugin.json.builder.StreamingJsonBuilder import grails.plugin.json.view.api.internal.DefaultGrailsJsonViewHelper import grails.plugin.json.view.api.internal.DefaultHalViewHelper import grails.plugin.json.view.api.internal.DefaultJsonApiViewHelper +import grails.plugin.json.view.api.internal.ParentInfo import grails.plugin.json.view.api.internal.TemplateRenderer import grails.plugin.json.view.api.jsonapi.JsonApiIdRenderStrategy import grails.views.GrailsViewTemplate @@ -21,7 +22,6 @@ import groovy.transform.CompileStatic */ @CompileStatic trait JsonView extends GrailsView { - /** * The default generator */ @@ -37,15 +37,7 @@ trait JsonView extends GrailsView { */ StreamingJsonBuilder json - /** - * The parent template if any - */ - GrailsViewTemplate parentTemplate - - /** - * The parent model, if any - */ - Map parentModel + Collection parentData = [] /** * Overrides the default helper with new methods specific to JSON building */ @@ -91,8 +83,11 @@ trait JsonView extends GrailsView { .resolveTemplateUri(getControllerNamespace(), getControllerName(), template.toString()) GrailsViewTemplate parentTemplate = (GrailsViewTemplate)templateEngine.resolveTemplate(templateUri, locale) if(parentTemplate != null) { - this.parentTemplate = parentTemplate - this.parentModel = model + ParentInfo parentInfo = new ParentInfo( + parentTemplate: parentTemplate, + parentModel: model + ) + parentData.add(parentInfo) } else { throw new ViewException("Template not found for name $template") diff --git a/json/src/main/groovy/grails/plugin/json/view/api/internal/ParentInfo.groovy b/json/src/main/groovy/grails/plugin/json/view/api/internal/ParentInfo.groovy new file mode 100644 index 000000000..e0d84fdaa --- /dev/null +++ b/json/src/main/groovy/grails/plugin/json/view/api/internal/ParentInfo.groovy @@ -0,0 +1,17 @@ +package grails.plugin.json.view.api.internal + +import grails.views.GrailsViewTemplate +import groovy.transform.CompileStatic + +@CompileStatic +class ParentInfo { + /** + * The parent template if any + */ + GrailsViewTemplate parentTemplate + + /** + * The parent model, if any + */ + Map parentModel +} diff --git a/json/src/test/groovy/grails/plugin/json/view/TemplateInheritanceSpec.groovy b/json/src/test/groovy/grails/plugin/json/view/TemplateInheritanceSpec.groovy index 8555ea840..64732c1ba 100644 --- a/json/src/test/groovy/grails/plugin/json/view/TemplateInheritanceSpec.groovy +++ b/json/src/test/groovy/grails/plugin/json/view/TemplateInheritanceSpec.groovy @@ -44,4 +44,31 @@ class TemplateInheritanceSpec extends Specification implements JsonViewTest { result.jsonText == '{"name":"Cantona"}' } + void "test extending multiple templates"() { + when: + + def result = render(template:'child2MultipleParents', model:[player: new Player(name: "Cantona")]) + then: + result.jsonText == '{"_links":{"self":{"href":"http://localhost:8080/player","hreflang":"en","type":"application/hal+json"}},"foo":"bar","bar":"foo","name":"Cantona"}' + } + + void "test extending multiple templates that uses g.render(..)"() { + + when: + def player = new Player(name: "Cantona") + player.id = 1L + def result = render(template:'child3MultipleParents', model:[player: player]) + then: + result.jsonText == '{"id":1,"bar":"foo","name":"Cantona"}' + } + + void "test extending multiple templates and rendering a JSON block"() { + when: + + def result = render(template:'child4MultipleParents', model:[player: new Player(name: "Cantona")]) + then: + result.jsonText == '{"_links":{"self":{"href":"http://localhost:8080/player","hreflang":"en","type":"application/hal+json"}},"foo":"bar","bar":"foo","name":"Cantona"}' + } + + } From 305222a7591acf7fc2df8ac023a0f5d15be663ad Mon Sep 17 00:00:00 2001 From: Mattias Reichel Date: Thu, 11 May 2023 08:12:39 +0200 Subject: [PATCH 2/2] Update version history in documentation. (#418) * Update version history in documentation. * Added a note in the version history section to check Github release page for later releases. --- docs/src/docs/asciidoc/json/history.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/docs/asciidoc/json/history.adoc b/docs/src/docs/asciidoc/json/history.adoc index 55cae0d7b..754c34745 100644 --- a/docs/src/docs/asciidoc/json/history.adoc +++ b/docs/src/docs/asciidoc/json/history.adoc @@ -2,6 +2,8 @@ The current release is {version}. Below is a version history. +For later releases check the release notes at: https://github.com/grails/grails-views/releases + *2.0.2* * Fix bug where incorrect JSON was generated when all values are null in the nested object.