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

org.apache.juneau.parser.Parser Maven / Gradle / Ivy

There is a newer version: 9.0.1
Show newest version
// ***************************************************************************************************************************
// * 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 org.apache.juneau.parser;

import java.io.*;
import java.lang.reflect.*;
import java.util.*;

import org.apache.juneau.*;
import org.apache.juneau.http.*;
import org.apache.juneau.json.*;
import org.apache.juneau.transform.*;
import org.apache.juneau.transforms.*;
import org.apache.juneau.utils.*;

/**
 * Parent class for all Juneau parsers.
 *
 * 
Valid data conversions
* * Parsers can parse any parsable POJO types, as specified in the POJO Categories. * *

* Some examples of conversions are shown below... *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Data typeClass typeJSON exampleXML exampleClass examples
objectMaps, Java beans{name:'John Smith',age:21}<object> * <name type='string'>John Smith</name> * <age type='number'>21</age> * </object>HashMap, TreeMap<String,Integer>
arrayCollections, Java arrays[1,2,3]<array> * <number>1</number> * <number>2</number> * <number>3</number> * </array>List<Integer>, int[], Float[], Set<Person>
numberNumbers123<number>123</number>Integer, Long, Float, int
booleanBooleanstrue<boolean>true</boolean>Boolean
stringCharSequences'foobar'<string>foobar</string>String, StringBuilder
* *

* In addition, any class types with {@link PojoSwap PojoSwaps} associated with them on the registered * {@link #getBeanContext() beanContext} can also be passed in. * *

* For example, if the {@link CalendarSwap} transform is used to generalize {@code Calendar} objects to {@code String} * objects. * When registered with this parser, you can construct {@code Calendar} objects from {@code Strings} using the * following syntax... *

* Calendar c = parser.parse("'Sun Mar 03 04:05:06 EST 2001'", GregorianCalendar.class); * *

* If Object.class is specified as the target type, then the parser automatically determines the * data types and generates the following object types... *

* * * * * * *
JSON typeClass type
object{@link ObjectMap}
array{@link ObjectList}
number{@link Number}
(depending on length and format, could be {@link Integer}, * {@link Double}, {@link Float}, etc...)
boolean{@link Boolean}
string{@link String}
* * *
Supported types
* * Several of the methods below take {@link Type} parameters to identify the type of object to create. * Any of the following types can be passed in to these methods... *
    *
  • {@link ClassMeta} *
  • {@link Class} *
  • {@link ParameterizedType} *
  • {@link GenericArrayType} *
* *

* However, {@code ParameterizedTypes} and {@code GenericArrayTypes} should not contain * {@link WildcardType WildcardTypes} or {@link TypeVariable TypeVariables}. * *

* Passing in null or Object.class typically signifies that it's up to the parser * to determine what object type is being parsed parsed based on the rules above. */ public abstract class Parser extends CoreObject { //------------------------------------------------------------------------------------------------------------------- // Configurable properties //------------------------------------------------------------------------------------------------------------------- private static final String PREFIX = "Parser."; /** * Configuration property: Trim parsed strings. * *

    *
  • Name: "Parser.trimStrings" *
  • Data type: Boolean *
  • Default: false *
  • Session-overridable: true *
* *

* If true, string values will be trimmed of whitespace using {@link String#trim()} before being added to * the POJO. */ public static final String PARSER_trimStrings = PREFIX + "trimStrings"; /** * Configuration property: Strict mode. * *

    *
  • Name: "Parser.strict" *
  • Data type: Boolean *
  • Default: false *
  • Session-overridable: true *
*

* If true, strict mode for the parser is enabled. * *

* Strict mode can mean different things for different parsers. * *

* * * * * * * * * *
Parser classStrict behavior
All reader-based parsers * When enabled, throws {@link ParseException ParseExceptions} on malformed charset input. * Otherwise, malformed input is ignored. *
{@link JsonParser} * When enabled, throws exceptions on the following invalid JSON syntax: *
    *
  • Unquoted attributes. *
  • Missing attribute values. *
  • Concatenated strings. *
  • Javascript comments. *
  • Numbers and booleans when Strings are expected. *
  • Numbers valid in Java but not JSON (e.g. octal notation, etc...) *
*
*/ public static final String PARSER_strict = PREFIX + "strict"; /** * Configuration property: Input stream charset. * *
    *
  • Name: "Parser.inputStreamCharset" *
  • Data type: String *
  • Default: "UTF-8" *
  • Session-overridable: true *
* *

* The character set to use for converting InputStreams and byte arrays to readers. * *

* Used when passing in input streams and byte arrays to {@link Parser#parse(Object, Class)}. */ public static final String PARSER_inputStreamCharset = PREFIX + "inputStreamCharset"; /** * Configuration property: File charset. * *

    *
  • Name: "Parser.fileCharset" *
  • Data type: String *
  • Default: "default" *
  • Session-overridable: true *
* *

* The character set to use for reading Files from the file system. * *

* Used when passing in files to {@link Parser#parse(Object, Class)}. * *

* "default" can be used to indicate the JVM default file system charset. */ public static final String PARSER_fileCharset = PREFIX + "fileCharset"; /** * Configuration property: Parser listener. * *

    *
  • Name: "Parser.listener" *
  • Data type: Class<? extends ParserListener> *
  • Default: null *
  • Session-overridable: true *
* *

* Class used to listen for errors and warnings that occur during parsing. */ public static final String PARSER_listener = PREFIX + "listener"; //------------------------------------------------------------------------------------------------------------------- // Instance //------------------------------------------------------------------------------------------------------------------- /** General parser properties currently set on this parser. */ private final MediaType[] consumes; // Hidden constructor to force subclass from InputStreamParser or ReaderParser. Parser(PropertyStore propertyStore, String...consumes) { super(propertyStore); this.consumes = new MediaType[consumes.length]; for (int i = 0; i < consumes.length; i++) { this.consumes[i] = MediaType.forString(consumes[i]); } } @Override /* CoreObject */ public ParserBuilder builder() { return new ParserBuilder(propertyStore); } //-------------------------------------------------------------------------------- // Abstract methods //-------------------------------------------------------------------------------- /** * Returns true if this parser subclasses from {@link ReaderParser}. * * @return true if this parser subclasses from {@link ReaderParser}. */ public abstract boolean isReaderParser(); /** * Create the session object that will be passed in to the parse method. * *

* It's up to implementers to decide what the session object looks like, although typically it's going to be a * subclass of {@link ParserSession}. * * @param args * Runtime arguments. * @return The new session. */ public abstract ParserSession createSession(ParserSessionArgs args); //-------------------------------------------------------------------------------- // Other methods //-------------------------------------------------------------------------------- /** * Parses input into the specified object type. * *

* The type can be a simple type (e.g. beans, strings, numbers) or parameterized type (collections/maps). * *

Examples:
*

* ReaderParser p = JsonParser.DEFAULT; * * // Parse into a linked-list of strings. * List l = p.parse(json, LinkedList.class, String.class); * * // Parse into a linked-list of beans. * List l = p.parse(json, LinkedList.class, MyBean.class); * * // Parse into a linked-list of linked-lists of strings. * List l = p.parse(json, LinkedList.class, LinkedList.class, String.class); * * // Parse into a map of string keys/values. * Map m = p.parse(json, TreeMap.class, String.class, String.class); * * // Parse into a map containing string keys and values of lists containing beans. * Map m = p.parse(json, TreeMap.class, String.class, List.class, MyBean.class); *

* *

* Collection classes are assumed to be followed by zero or one objects indicating the element type. * *

* Map classes are assumed to be followed by zero or two meta objects indicating the key and value types. * *

* The array can be arbitrarily long to indicate arbitrarily complex data structures. * *

Notes:
*
    *
  • Use the {@link #parse(Object, Class)} method instead if you don't need a parameterized map/collection. *
* * @param The class type of the object to create. * @param input * The input. *
Character-based parsers can handle the following input class types: *
    *
  • null *
  • {@link Reader} *
  • {@link CharSequence} *
  • {@link InputStream} containing UTF-8 encoded text (or charset defined by * {@link #PARSER_inputStreamCharset} property value). *
  • byte[] containing UTF-8 encoded text (or charset defined by * {@link #PARSER_inputStreamCharset} property value). *
  • {@link File} containing system encoded text (or charset defined by * {@link #PARSER_fileCharset} property value). *
*
Stream-based parsers can handle the following input class types: *
    *
  • null *
  • {@link InputStream} *
  • byte[] *
  • {@link File} *
* @param type * The object type to create. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} * @param args * The type arguments of the class if it's a collection or map. *
Can be any of the following: {@link ClassMeta}, {@link Class}, {@link ParameterizedType}, * {@link GenericArrayType} *
Ignored if the main type is not a map or collection. * @return The parsed object. * @throws ParseException * If the input contains a syntax error or is malformed, or is not valid for the specified type. * @see BeanSession#getClassMeta(Type,Type...) for argument syntax for maps and collections. */ public final T parse(Object input, Type type, Type...args) throws ParseException { ParserSession session = createSession(); try { return session.parse(input, type, args); } finally { session.close(); } } /** * Same as {@link #parse(Object, Type, Type...)} except optimized for a non-parameterized class. * *

* This is the preferred parse method for simple types since you don't need to cast the results. * *

Examples:
*

* ReaderParser p = JsonParser.DEFAULT; * * // Parse into a string. * String s = p.parse(json, String.class); * * // Parse into a bean. * MyBean b = p.parse(json, MyBean.class); * * // Parse into a bean array. * MyBean[] ba = p.parse(json, MyBean[].class); * * // Parse into a linked-list of objects. * List l = p.parse(json, LinkedList.class); * * // Parse into a map of object keys/values. * Map m = p.parse(json, TreeMap.class); *

* * @param The class type of the object being created. * @param input * The input. * See {@link #parse(Object, Type, Type...)} for details. * @param type The object type to create. * @return The parsed object. * @throws ParseException * If the input contains a syntax error or is malformed, or is not valid for the specified type. */ public final T parse(Object input, Class type) throws ParseException { ParserSession session = createSession(); try { return session.parse(input, type); } finally { session.close(); } } /** * Same as {@link #parse(Object, Type, Type...)} except the type has already been converted into a {@link ClassMeta} * object. * *

* This is mostly an internal method used by the framework. * * @param The class type of the object being created. * @param input * The input. * See {@link #parse(Object, Type, Type...)} for details. * @param type The object type to create. * @return The parsed object. * @throws ParseException * If the input contains a syntax error or is malformed, or is not valid for the specified type. */ public final T parse(Object input, ClassMeta type) throws ParseException { ParserSession session = createSession(); try { return session.parse(input, type); } finally { session.close(); } } /** * Create a basic session object without overriding properties or specifying javaMethod. * *

* Equivalent to calling createSession(null, null). * * @return The new context. */ public final ParserSession createSession() { return createSession(createDefaultSessionArgs()); } /** * Creates the session arguments object that gets passed to the {@link #createSession(ParserSessionArgs)} method. * * @return * A new default session arguments object. *

The arguments can be modified before passing to the {@link #createSession(ParserSessionArgs)}. */ protected final ParserSessionArgs createDefaultSessionArgs() { return new ParserSessionArgs(ObjectMap.EMPTY_MAP, null, null, null, getPrimaryMediaType(), null); } //-------------------------------------------------------------------------------- // Optional methods //-------------------------------------------------------------------------------- /** * Parses the contents of the specified reader and loads the results into the specified map. * *

* Reader must contain something that serializes to a map (such as text containing a JSON object). * *

* Used in the following locations: *

    *
  • * The various character-based constructors in {@link ObjectMap} (e.g. * {@link ObjectMap#ObjectMap(CharSequence,Parser)}). *
* * @param The key class type. * @param The value class type. * @param input The input. See {@link #parse(Object, ClassMeta)} for supported input types. * @param m The map being loaded. * @param keyType The class type of the keys, or null to default to String.class. * @param valueType The class type of the values, or null to default to whatever is being parsed. * @return The same map that was passed in to allow this method to be chained. * @throws ParseException If the input contains a syntax error or is malformed, or is not valid for the specified type. * @throws UnsupportedOperationException If not implemented. */ public final Map parseIntoMap(Object input, Map m, Type keyType, Type valueType) throws ParseException { ParserSession session = createSession(); try { return session.parseIntoMap(input, m, keyType, valueType); } finally { session.close(); } } /** * Parses the contents of the specified reader and loads the results into the specified collection. * *

* Used in the following locations: *

    *
  • * The various character-based constructors in {@link ObjectList} (e.g. * {@link ObjectList#ObjectList(CharSequence,Parser)}. *
* * @param The element class type. * @param input The input. See {@link #parse(Object, ClassMeta)} for supported input types. * @param c The collection being loaded. * @param elementType The class type of the elements, or null to default to whatever is being parsed. * @return The same collection that was passed in to allow this method to be chained. * @throws ParseException * If the input contains a syntax error or is malformed, or is not valid for the specified type. * @throws UnsupportedOperationException If not implemented. */ public final Collection parseIntoCollection(Object input, Collection c, Type elementType) throws ParseException { ParserSession session = createSession(); try { return session.parseIntoCollection(input, c, elementType); } finally { session.close(); } } /** * Parses the specified array input with each entry in the object defined by the {@code argTypes} * argument. * *

* Used for converting arrays (e.g. "[arg1,arg2,...]") into an {@code Object[]} that can be passed * to the {@code Method.invoke(target, args)} method. * *

* Used in the following locations: *

    *
  • * Used to parse argument strings in the {@link PojoIntrospector#invokeMethod(Method, Reader)} method. *
* * @param input The input. Subclasses can support different input types. * @param argTypes Specifies the type of objects to create for each entry in the array. * @return An array of parsed objects. * @throws ParseException * If the input contains a syntax error or is malformed, or is not valid for the specified type. */ public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException { if (argTypes == null || argTypes.length == 0) return new Object[0]; ParserSession session = createSession(); try { return session.parseArgs(input, argTypes); } finally { session.close(); } } //-------------------------------------------------------------------------------- // Other methods //-------------------------------------------------------------------------------- /** * Returns the media types handled based on the values passed to the consumes constructor parameter. * * @return The list of media types. Never null. */ public final MediaType[] getMediaTypes() { return consumes; } /** * Returns the first media type handled based on the values passed to the consumes constructor parameter. * * @return The media type. */ public final MediaType getPrimaryMediaType() { return consumes == null || consumes.length == 0 ? null : consumes[0]; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy