All Downloads are FREE. Search and download functionalities are using the official Maven repository.

groovy.json.JsonSlurperClassic Maven / Gradle / Ivy

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package groovy.json;

import groovy.io.LineColumnReader;
import org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport;
import org.codehaus.groovy.runtime.ResourceGroovyMethods;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static groovy.json.JsonTokenType.CLOSE_BRACKET;
import static groovy.json.JsonTokenType.CLOSE_CURLY;
import static groovy.json.JsonTokenType.COLON;
import static groovy.json.JsonTokenType.COMMA;
import static groovy.json.JsonTokenType.NULL;
import static groovy.json.JsonTokenType.OPEN_BRACKET;
import static groovy.json.JsonTokenType.OPEN_CURLY;
import static groovy.json.JsonTokenType.STRING;

/**
 * This is the original slurper included in case someone relies on its exact behavior.
 *
 * JSON slurper which parses text or reader content into a data structure of lists and maps.
 * 

* Example usage: *

 * def slurper = new groovy.json.JsonSlurperClassic()
 * def result = slurper.parseText('{"person":{"name":"Guillaume","age":33,"pets":["dog","cat"]}}')
 *
 * assert result.person.name == "Guillaume"
 * assert result.person.age == 33
 * assert result.person.pets.size() == 2
 * assert result.person.pets[0] == "dog"
 * assert result.person.pets[1] == "cat"
 * 
* * @since 1.8.0 */ public class JsonSlurperClassic { /** * Parse a text representation of a JSON data structure * * @param text JSON text to parse * @return a data structure of lists and maps */ public Object parseText(String text) { if (text == null || text.length() == 0) { throw new IllegalArgumentException("The JSON input text should neither be null nor empty."); } return parse(new LineColumnReader(new StringReader(text))); } /** * Parse a JSON data structure from content from a reader * * @param reader reader over a JSON content * @return a data structure of lists and maps */ public Object parse(Reader reader) { Object content; JsonLexer lexer = new JsonLexer(reader); JsonToken token = lexer.nextToken(); if (token.getType() == OPEN_CURLY) { content = parseObject(lexer); } else if (token.getType() == OPEN_BRACKET) { content = parseArray(lexer); } else { throw new JsonException( "A JSON payload should start with " + OPEN_CURLY.getLabel() + " or " + OPEN_BRACKET.getLabel() + ".\n" + "Instead, '" + token.getText() + "' was found " + "on line: " + token.getStartLine() + ", " + "column: " + token.getStartColumn() ); } return content; } /** * Parse a JSON data structure from content within a given File. * * @param file File containing JSON content * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(File file) { return parseFile(file, null); } /** * Parse a JSON data structure from content within a given File. * * @param file File containing JSON content * @param charset the charset for this File * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(File file, String charset) { return parseFile(file, charset); } private Object parseFile(File file, String charset) { Reader reader = null; try { if (charset == null || charset.length() == 0) { reader = ResourceGroovyMethods.newReader(file); } else { reader = ResourceGroovyMethods.newReader(file, charset); } return parse(reader); } catch (IOException ioe) { throw new JsonException("Unable to process file: " + file.getPath(), ioe); } finally { if (reader != null) { DefaultGroovyMethodsSupport.closeWithWarning(reader); } } } /** * Parse a JSON data structure from content at a given URL. * * @param url URL containing JSON content * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(URL url) { return parseURL(url, null); } /** * Parse a JSON data structure from content at a given URL. * * @param url URL containing JSON content * @param params connection parameters * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(URL url, Map params) { return parseURL(url, params); } /** * Parse a JSON data structure from content at a given URL. Convenience variant when using Groovy named parameters for the connection params. * * @param params connection parameters * @param url URL containing JSON content * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(Map params, URL url) { return parseURL(url, params); } private Object parseURL(URL url, Map params) { Reader reader = null; try { if (params == null || params.isEmpty()) { reader = ResourceGroovyMethods.newReader(url); } else { reader = ResourceGroovyMethods.newReader(url, params); } return parse(reader); } catch (IOException ioe) { throw new JsonException("Unable to process url: " + url.toString(), ioe); } finally { if (reader != null) { DefaultGroovyMethodsSupport.closeWithWarning(reader); } } } /** * Parse a JSON data structure from content at a given URL. * * @param url URL containing JSON content * @param charset the charset for this File * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(URL url, String charset) { return parseURL(url, null, charset); } /** * Parse a JSON data structure from content at a given URL. * * @param url URL containing JSON content * @param params connection parameters * @param charset the charset for this File * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(URL url, Map params, String charset) { return parseURL(url, params, charset); } /** * Parse a JSON data structure from content at a given URL. Convenience variant when using Groovy named parameters for the connection params. * * @param params connection parameters * @param url URL containing JSON content * @param charset the charset for this File * @return a data structure of lists and maps * @since 2.2.0 */ public Object parse(Map params, URL url, String charset) { return parseURL(url, params, charset); } private Object parseURL(URL url, Map params, String charset) { Reader reader = null; try { if (params == null || params.isEmpty()) { reader = ResourceGroovyMethods.newReader(url, charset); } else { reader = ResourceGroovyMethods.newReader(url, params, charset); } return parse(reader); } catch (IOException ioe) { throw new JsonException("Unable to process url: " + url.toString(), ioe); } finally { if (reader != null) { DefaultGroovyMethodsSupport.closeWithWarning(reader); } } } /** * Parse an array from the lexer * * @param lexer the lexer * @return a list of JSON values */ private List parseArray(JsonLexer lexer) { List content = new ArrayList(); JsonToken currentToken; for(;;) { currentToken = lexer.nextToken(); if (currentToken == null) { throw new JsonException( "Expected a value on line: " + lexer.getReader().getLine() + ", " + "column: " + lexer.getReader().getColumn() + ".\n" + "But got an unterminated array." ); } if (currentToken.getType() == OPEN_CURLY) { content.add(parseObject(lexer)); } else if (currentToken.getType() == OPEN_BRACKET) { content.add(parseArray(lexer)); } else if (currentToken.getType().ordinal() >= NULL.ordinal()) { content.add(currentToken.getValue()); } else if (currentToken.getType() == CLOSE_BRACKET) { return content; } else { throw new JsonException( "Expected a value, an array, or an object " + "on line: " + currentToken.getStartLine() + ", " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } currentToken = lexer.nextToken(); if (currentToken == null) { throw new JsonException( "Expected " + CLOSE_BRACKET.getLabel() + " " + "or " + COMMA.getLabel() + " " + "on line: " + lexer.getReader().getLine() + ", " + "column: " + lexer.getReader().getColumn() + ".\n" + "But got an unterminated array." ); } // Expect a comma for an upcoming value // or a closing bracket for the end of the array if (currentToken.getType() == CLOSE_BRACKET) { break; } else if (currentToken.getType() != COMMA) { throw new JsonException( "Expected a value or " + CLOSE_BRACKET.getLabel() + " " + "on line: " + currentToken.getStartLine() + " " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } } return content; } /** * Parses an object from the lexer * * @param lexer the lexer * @return a Map representing a JSON object */ private Map parseObject(JsonLexer lexer) { Map content = new HashMap(); JsonToken previousToken = null; JsonToken currentToken = null; for(;;) { currentToken = lexer.nextToken(); if (currentToken == null) { throw new JsonException( "Expected a String key on line: " + lexer.getReader().getLine() + ", " + "column: " + lexer.getReader().getColumn() + ".\n" + "But got an unterminated object." ); } // expect a string key, or already a closing curly brace if (currentToken.getType() == CLOSE_CURLY) { return content; } else if (currentToken.getType() != STRING) { throw new JsonException( "Expected " + STRING.getLabel() + " key " + "on line: " + currentToken.getStartLine() + ", " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } String mapKey = (String) currentToken.getValue(); currentToken = lexer.nextToken(); if (currentToken == null) { throw new JsonException( "Expected a " + COLON.getLabel() + " " + "on line: " + lexer.getReader().getLine() + ", " + "column: " + lexer.getReader().getColumn() + ".\n" + "But got an unterminated object." ); } // expect a colon between the key and value pair if (currentToken.getType() != COLON) { throw new JsonException( "Expected " + COLON.getLabel() + " " + "on line: " + currentToken.getStartLine() + ", " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } currentToken = lexer.nextToken(); if (currentToken == null) { throw new JsonException( "Expected a value " + "on line: " + lexer.getReader().getLine() + ", " + "column: " + lexer.getReader().getColumn() + ".\n" + "But got an unterminated object." ); } // value can be an object, an array, a number, string, boolean or null values if (currentToken.getType() == OPEN_CURLY) { content.put(mapKey, parseObject(lexer)); } else if (currentToken.getType() == OPEN_BRACKET) { content.put(mapKey, parseArray(lexer)); } else if (currentToken.getType().ordinal() >= NULL.ordinal()) { content.put(mapKey, currentToken.getValue()); } else { throw new JsonException( "Expected a value, an array, or an object " + "on line: " + currentToken.getStartLine() + ", " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } previousToken = currentToken; currentToken = lexer.nextToken(); // premature end of the object if (currentToken == null) { throw new JsonException( "Expected " + CLOSE_CURLY.getLabel() + " or " + COMMA.getLabel() + " " + "on line: " + previousToken.getEndLine() + ", " + "column: " + previousToken.getEndColumn() + ".\n" + "But got an unterminated object." ); } // Expect a comma for an upcoming key/value pair // or a closing curly brace for the end of the object if (currentToken.getType() == CLOSE_CURLY) { break; } else if (currentToken.getType() != COMMA) { throw new JsonException( "Expected a value or " + CLOSE_CURLY.getLabel() + " " + "on line: " + currentToken.getStartLine() + ", " + "column: " + currentToken.getStartColumn() + ".\n" + "But got '" + currentToken.getText() + "' instead." ); } } return content; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy