Проблема создания JSON с JsonGroovyBuilder в Groovy - PullRequest
0 голосов
/ 18 февраля 2010

Я новичок в JSON и Groovy. Я могу сделать AJAX-вызов Groovlet и заставить его создавать некоторые HTML-коды с помощью MarkupBuilder. Наряду с возвращаемой строкой 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 и начать все сначала. Что может быть решением этой проблемы? Большое спасибо заранее!

Ответы [ 2 ]

2 голосов
/ 18 февраля 2010

Я никогда не пробовал использовать JsonGroovyBuilder, поэтому не могу вам в этом помочь.Я был также разочарован JSON Builder, предоставленным Grails 1.1 (который был заменен лучшей версией в 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.

Единственная библиотека, необходимая для этого компоновщика, - это библиотека Java JSON, предоставляемая json.org .

В случае, если комментарии в коде выше не объясняют, какиспользуйте его достаточно хорошо, вот несколько тестов:

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, "{}"                
    }    
}
0 голосов
/ 28 июня 2010

Это небольшая ошибка в JsonGroovyBuilder.Если вы используете его из скрипта, то неизвестные свойства разрешаются с помощью связывания скрипта.Я опубликовал патч для JsonBuilder, поэтому надеюсь, что ошибка будет исправлена ​​в ближайшее время.Подробнее см. https://sourceforge.net/tracker/?func=detail&aid=3022114&group_id=171425&atid=857928.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...