在Groovy中使用JsonGroovyBuilder创建JSON时出现问题 [英] Problem creating JSON with JsonGroovyBuilder in Groovy

查看:1136
本文介绍了在Groovy中使用JsonGroovyBuilder创建JSON时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对JSON和Groovy是新手。我可以对groovlet进行AJAX调用,并使用MarkupBuilder构建一些HTML代码。随着HTML字符串被返回,我想要在输入文本框中填充一个JSON字符串。问题是使用JsonGroovyBuilder()。我甚至无法获得Json-lib中显示的最简单示例以正确运行。这是我的代码:

I am new to JSON and Groovy. I can make an AJAX call to a groovlet and make it build some HTML codes with MarkupBuilder. Along with the HTML string being returned, I want a JSON string to be filled in one of a input text box. The problem is the use of JsonGroovyBuilder(). I can't even get the simplest example shown in Json-lib to run correctly. Here is my code:

import net.sf.json.groovy.*;
import net.sf.json.groovy.JsonGroovyBuilder;

def builder = new JsonGroovyBuilder()  
def books = builder.books {  
    book = [title: "Groovy in Action", author: "Dierk Konig"]  
    book = [title: "Groovy in Action", author: "Dierk Konig"]  
}  

我在GroovyConsole上运行这段简单的代码,我得到了这个回报:

I run this simple piece of code on GroovyConsole and I get this in return:

Result: {"books":null}

很奇怪。但是,当我在Eclipse中运行它时,甚至是怪怪的事情,我得到了这个结果:

Very odd. But the even "odder" thing is when I run it in Eclipse, I get this:

Caught: groovy.lang.MissingMethodException: No signature of method: net.sf.json.groovy.JsonGroovyBuilder.books() is applicable for argument types: (JSONSandbox$_run_closure1) values: [JSONSandbox$_run_closure1@164debb]
Possible solutions: is(java.lang.Object)
 at JSONSandbox.run(JSONSandbox.groovy:6)

我认为我有我需要的所有jar文件:

I think that I have all the jar files I needed:

    json-lib-2.3-jdk15.jar
commons-collections-2.1.jar
commons-lang-2.3.jar
httpclient-4.0.1.jar

我现在已经陷入了这个问题几天了。也许我做错了什么,或者误解了这个函数的使用。我在任何地方搜索JSON,Groovy都指向Grails。我对Groovy还是个新手,我不认识Grails。我不想扔掉我的Groovy代码并重新开始。有什么可以解决这个问题?很多人提前感谢!

I have been stuck in this problem for a couple of days now. Perhaps I have done something wrong, or misunderstanding the use of this function. Everywhere I search on JSON and Groovy points back to Grails. I am still new to Groovy and I don't know Grails. I don't want to throw away my Groovy codes and start over. What could be the fix of this problem? Many many thanks in advance!

推荐答案

我从来没有尝试过使用 JsonGroovyBuilder ,所以不能真正帮助你。我对Grails 1.1提供的JSON Builder(在Grails 1.2中用更好的版本取代)感到沮丧。我通过编写自己的Groovy JSON构建器克服了这个沮丧,我们欢迎您使用它。我粘贴了下面的源代码。

I've never tried using JsonGroovyBuilder, so can't really help you with that. I was similar frustrated by the JSON Builder provided by Grails 1.1 (which was replaced with a better version in Grails 1.2). I overcame this frustration by writing my own Groovy JSON builder, which you're welcome to use. I've pasted the source code below.

import org.json.JSONStringer

/**
 * An alternative JSON builder, because <code>grails.util.JSonBuilder</code> sucks!
 * The reasons why it sucks are described here: http://www.anyware.co.uk/2005/2008/06/19/a-grails-json-builder-that-doesnt-suck/
 * Although this page provides an alternative JSON builder, the author didn't provide any usage examples, and I couldn't
 * figure out how to use it, so I wrote my own instead.
 *
 * The underlying JSON functionality is provided by <code>json.org.JSONStringer</code>. An example usage is:
 *
 * <code>
 * builder.array(['feck', 'arse', 'girls']) {
 *     foo(bar:'1', baz: '2') {
 *         hobbies(sport: 'snooker', drink: 'guinness')
 *         emptyObj([:])
 *         emptyArray([])
 *     }
 * }
 * builder.json
 * </code>
 *
 * This will print:
 * <code>
 * ["feck","arse","girls", {"bar":"1", "baz":"2", "hobbies": {"sport":"snooker", "drink":"guinness"}, "emptyObj": {},"emptyArray":[]}]
 * </code>
 *
 * Verifiable usage examples are provided by the unit tests. A few points worth noting (the term 'element' is used below
 * to mean 'either a JSON object or JSON array'):
 *
 * <ul>
 *   <li>The nesting of elements is indicated by the nesting of closures in the usual Groovy builder fashion</li>
 *   <li>The name of the method is used as the name of the key when nesting an element within an object</li>
 *   <li>The name of the method is irrelevant when nesting an element within an array, but it is recommended
 *   to use either the method name 'object' or 'array' for the sake of code readability</li>
 *   <li>The decision to create an array or object is determined by the type of the method parameter. A map will cause
 *   an object to be created, any other type will cause an array to be created</li>
 *   <li>To create an empty array or an array whose contents are determined only by nested closures, either call
 *   <code>builder.array()</code> or <code>builder.keyName([])</code>. The latter should be used when nesting the empty
 *   array within an object and control over the key name is required.</li>
 *   <li>To create an empty object or an object whose contents are determined only by nested closures, either call
 *   <code>builder.object()</code> or <code>builder.keyName([:])</code>. The latter should be used when nesting the empty
 *   object within another object and control over the key name is required.</li>
 * </ul>
 */
class SimpleJSONBuilder extends BuilderSupport {

    private jsonText = new JSONStringer()

    /**
     * Returns the JSON text created by this builder
     */
    String getJson() {
        jsonText.toString()
    }

    String toString() {
        getJson()
    }

    protected void setParent(Object parent, Object child) {
        // Method is abstract in parent class, but an empty implementation is all we need
    }

    /**
     * Creates an array or object which is either empty, or whose contents are determined exclusively by nested closures.
     */
    protected Object createNode(Object name) {

        if (current == ElementType.OBJECT) {
            throw new IllegalStateException("""Error processing method $name() Empty argument methods should not be invoked
when nesting an element within an object because the key name cannot be determined. Replace this call with either
$name([]) or $name([:])""")
        }

        if (name == 'array') {
            jsonText.array()
            return ElementType.ARRAY

        } else if (name == 'object') {
            jsonText.object()
            return ElementType.OBJECT

        } else {
            throw new IllegalArgumentException("""When calling a method with no arguments, the method must be named either
'$array' or '$object' to indicate which you wish to create""")
        }

    }

    protected Object createNode(Object name, Map attributes, Object value) {
        throw new UnsupportedOperationException("Error invoking method $name. Method calls must supply either a single object (to create an array) or a Map (to create an object)")
    }

    /**
     * Ensures that an array/object is correctly nested within an object
     * @name Name of the key to use for the nested element
     * @return The type of element
     */
    private void nestElement(name) {
        if (current == ElementType.OBJECT) {
            jsonText.key(name)
        }
    }

    /**
     * Creates an array
     * @name Name of the method. This will be used as the key if the array is nested within an object
     * @value The contents of the array. This should be either a single value or a collection or array
     * @return The type of element
     */
    protected Object createNode(Object name, Object value) {
        nestElement(name)
        jsonText.array()

        if (value instanceof Collection || value instanceof Object[]) {
            value.each {jsonText.value(it)}

        } else {
            jsonText.value(value)
        }
        return ElementType.ARRAY
    }

    /**
     * Creates an object
     * @name Name of the method. This will be used as the key if the object is nested within an object
     * @value The name-value pairs contained by this object
     * @return The type of element
     */
    protected Object createNode(Object name, Map attributes) {
        nestElement(name)
        jsonText.object()
        attributes.each {key, value ->
            jsonText.key(key).value(value)
        }
        return ElementType.OBJECT
    }

    protected void nodeCompleted(Object parent, Object node) {
        node == ElementType.OBJECT ? jsonText.endObject() : jsonText.endArray()
    }
}

private enum ElementType {
    ARRAY, OBJECT
}

上面的源代码定义了类 SimpleJSONBuilder 和枚举 SimpleJSONBuilder ,但您可以将这两个文件存储在一个文件中 SimpleJSONBuilder.groovy

The source code above defines the class SimpleJSONBuilder and the enum SimpleJSONBuilder, but you can store both of these in a single file SimpleJSONBuilder.groovy.

此构建器所需的唯一库是Java JSON库,由 json.org 提供。

The only library required by this builder is the Java JSON library provided by json.org.

如果上面代码中的注释没有解释如何充分使用它,那么下面是一些测试用例:

In case the comments in the code above don't explain how to use it sufficiently well, here are some test cases:

public class SimpleJSONBuilderTests extends GroovyTestCase {

    void testRootArrayElement() {
        def builder = new SimpleJSONBuilder()
        builder.array(['feck', 'arse', 'girls']) {
            foo(bar: '1', baz: '2') {
                hobbies(sport: 'snooker', drink: 'guinness')
                emptyObj([:])
                emptyArray([])
            }
        }

        assertEquals builder.json, '["feck","arse","girls",{"bar":"1","baz":"2","hobbies":{"sport":"snooker","drink":"guinness"},"emptyObj":{},"emptyArray":[]}]'
    }

    void testRootObjElement() {
       def builder = new SimpleJSONBuilder()
        builder.object(feck:'arse') {
            foo(bar: '1', baz: '2') {
                hobbies(sport: 'snooker', drink: 'guinness')
                emptyObj([:])
                emptyArray([])
            }
        }

        assertEquals builder.json, '{"feck":"arse","foo":{"bar":"1","baz":"2","hobbies":{"sport":"snooker","drink":"guinness"},"emptyObj":{},"emptyArray":[]}}'
    }        

    /**
     * Test that both mechanisms for creating empty arrays are equivalent
     */
    void testEmptyArrays() {
        def builder = new SimpleJSONBuilder()
        builder.array([])

        def builder2 = new SimpleJSONBuilder()
        builder2.array()

        assertEquals builder.json, builder2.json
        assertEquals builder.json, "[]"
    }

    /**
     * Test that both mechanisms for creating empty objects are equivalent
     */
    void testEmptyObjects() {
        def builder = new SimpleJSONBuilder()
        builder.object([:])

        def builder2 = new SimpleJSONBuilder()
        builder2.object()

        assertEquals builder.json, builder2.json
        assertEquals builder.json, "{}"                
    }    
}

这篇关于在Groovy中使用JsonGroovyBuilder创建JSON时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆