我是JSON和Groovy的新手。我可以对groovlet进行AJAX调用,并使用MarkupBuilder构建一些HTML代码。连同返回的HTML字符串,我希望在输入文本框之一中填充JSON字符串。问题是使用JsonGroovyBuilder()。我甚至无法让Json-lib中显示的最简单的示例正确运行。这是我的代码:
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上运行这段简单的代码,我得到了回报:
Result: {"books":null}
很奇怪。但是甚至“奇怪”的事情是当我在Eclipse中运行它时,我得到了这个:
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文件:
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代码并重新开始。有什么可以解决这个问题?很多人都提前感谢!
答案 0 :(得分:2)
我从未尝试使用JsonGroovyBuilder
,因此无法真正帮助您。 Grails 1.1提供的JSON Builder(在Grails 1.2中被更好的版本取代)让我感到非常沮丧。我通过编写自己的Groovy JSON构建器克服了这种挫败感,欢迎您使用它。我已粘贴下面的源代码。
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
中。
此构建器所需的唯一库是json.org提供的Java JSON库。
如果上面代码中的注释没有解释如何充分利用它,这里有一些测试用例:
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, "{}"
}
}
答案 1 :(得分:0)
这是JsonGroovyBuilder中的一个小错误。如果从脚本中使用它,则使用脚本绑定解析未知属性。 我已经发布了JsonBuilder的补丁,所以我希望很快就能解决这个问题。 有关详细信息,请参阅https://sourceforge.net/tracker/?func=detail&aid=3022114&group_id=171425&atid=857928。