You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@juneau.apache.org by ja...@apache.org on 2017/07/28 18:22:22 UTC
[07/12] incubator-juneau git commit: Allow serializer and parser
sessions to be reused.
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
index f632c84..4a8177d 100644
--- a/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
+++ b/juneau-core/src/main/java/org/apache/juneau/msgpack/MsgPackSerializerSession.java
@@ -14,20 +14,20 @@ package org.apache.juneau.msgpack;
import static org.apache.juneau.msgpack.MsgPackSerializerContext.*;
-import java.lang.reflect.*;
import java.util.*;
import org.apache.juneau.*;
-import org.apache.juneau.http.*;
import org.apache.juneau.serializer.*;
+import org.apache.juneau.transform.*;
/**
* Session object that lives for the duration of a single use of {@link MsgPackSerializer}.
*
* <p>
- * This class is NOT thread safe. It is meant to be discarded after one-time use.
+ * This class is NOT thread safe.
+ * It is typically discarded after one-time use although it can be reused within the same thread.
*/
-public final class MsgPackSerializerSession extends SerializerSession {
+public final class MsgPackSerializerSession extends OutputStreamSerializerSession {
private final boolean
addBeanTypeProperties;
@@ -38,28 +38,20 @@ public final class MsgPackSerializerSession extends SerializerSession {
* @param ctx
* The context creating this session object.
* The context contains all the configuration settings for this object.
- * @param op
- * The override properties.
- * These override any context properties defined in the context.
- * @param javaMethod The java method that called this serializer, usually the method in a REST servlet.
- * @param locale
- * The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
- * @param timeZone
- * The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
- * @param mediaType The session media type (e.g. <js>"application/json"</js>).
- * @param uriContext
- * The URI context.
- * Identifies the current request URI used for resolution of URIs to absolute or root-relative form.
+ * @param args
+ * Runtime arguments.
+ * These specify session-level information such as locale and URI context.
+ * It also include session-level properties that override the properties defined on the bean and
+ * serializer contexts.
+ * <br>If <jk>null</jk>, defaults to {@link SerializerSessionArgs#DEFAULT}.
*/
- protected MsgPackSerializerSession(MsgPackSerializerContext ctx, ObjectMap op, Method javaMethod,
- Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) {
- super(ctx, op, javaMethod, locale, timeZone, mediaType, uriContext);
- if (op == null || op.isEmpty()) {
+ protected MsgPackSerializerSession(MsgPackSerializerContext ctx, SerializerSessionArgs args) {
+ super(ctx, args);
+ ObjectMap p = getProperties();
+ if (p.isEmpty()) {
addBeanTypeProperties = ctx.addBeanTypeProperties;
} else {
- addBeanTypeProperties = op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
+ addBeanTypeProperties = p.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties);
}
}
@@ -69,22 +61,167 @@ public final class MsgPackSerializerSession extends SerializerSession {
* @return The {@link MsgPackSerializerContext#MSGPACK_addBeanTypeProperties} setting value for this session.
*/
@Override /* SerializerSession */
- public final boolean isAddBeanTypeProperties() {
+ protected final boolean isAddBeanTypeProperties() {
return addBeanTypeProperties;
}
- /**
+ @Override /* SerializerSession */
+ protected void doSerialize(SerializerPipe out, Object o) throws Exception {
+ serializeAnything(getMsgPackOutputStream(out), o, getExpectedRootType(o), "root", null);
+ }
+
+ /*
* Converts the specified output target object to an {@link MsgPackOutputStream}.
- *
- * @param out The output target object.
- * @return The output target object wrapped in an {@link MsgPackOutputStream}.
- * @throws Exception
*/
- @SuppressWarnings("static-method")
- public MsgPackOutputStream getMsgPackOutputStream(SerializerOutput out) throws Exception {
+ private static final MsgPackOutputStream getMsgPackOutputStream(SerializerPipe out) throws Exception {
Object output = out.getRawOutput();
if (output instanceof MsgPackOutputStream)
return (MsgPackOutputStream)output;
- return new MsgPackOutputStream(out.getOutputStream());
+ MsgPackOutputStream os = new MsgPackOutputStream(out.getOutputStream());
+ out.setOutputStream(os);
+ return os;
+ }
+
+ /*
+ * Workhorse method.
+ * Determines the type of object, and then calls the appropriate type-specific serialization method.
+ */
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private MsgPackOutputStream serializeAnything(MsgPackOutputStream out, Object o, ClassMeta<?> eType, String attrName, BeanPropertyMeta pMeta) throws Exception {
+
+ if (o == null)
+ return out.appendNull();
+
+ if (eType == null)
+ eType = object();
+
+ ClassMeta<?> aType; // The actual type
+ ClassMeta<?> sType; // The serialized type
+
+ aType = push(attrName, o, eType);
+ boolean isRecursion = aType == null;
+
+ // Handle recursion
+ if (aType == null) {
+ o = null;
+ aType = object();
+ }
+
+ sType = aType.getSerializedClassMeta();
+ String typeName = getBeanTypeName(eType, aType, pMeta);
+
+ // Swap if necessary
+ PojoSwap swap = aType.getPojoSwap();
+ if (swap != null) {
+ o = swap.swap(this, o);
+
+ // If the getSwapClass() method returns Object, we need to figure out
+ // the actual type now.
+ if (sType.isObject())
+ sType = getClassMetaForObject(o);
+ }
+
+ // '\0' characters are considered null.
+ if (o == null || (sType.isChar() && ((Character)o).charValue() == 0))
+ out.appendNull();
+ else if (sType.isBoolean())
+ out.appendBoolean((Boolean)o);
+ else if (sType.isNumber())
+ out.appendNumber((Number)o);
+ else if (sType.isBean())
+ serializeBeanMap(out, toBeanMap(o), typeName);
+ else if (sType.isUri() || (pMeta != null && pMeta.isUri()))
+ out.appendString(resolveUri(o.toString()));
+ else if (sType.isMap()) {
+ if (o instanceof BeanMap)
+ serializeBeanMap(out, (BeanMap)o, typeName);
+ else
+ serializeMap(out, (Map)o, eType);
+ }
+ else if (sType.isCollection()) {
+ serializeCollection(out, (Collection) o, eType);
+ }
+ else if (sType.isArray()) {
+ serializeCollection(out, toList(sType.getInnerClass(), o), eType);
+ } else
+ out.appendString(toString(o));
+
+ if (! isRecursion)
+ pop();
+ return out;
+ }
+
+ @SuppressWarnings({ "rawtypes", "unchecked" })
+ private void serializeMap(MsgPackOutputStream out, Map m, ClassMeta<?> type) throws Exception {
+
+ ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType();
+
+ m = sort(m);
+
+ // The map size may change as we're iterating over it, so
+ // grab a snapshot of the entries in a separate list.
+ List<SimpleMapEntry> entries = new ArrayList<SimpleMapEntry>(m.size());
+ for (Map.Entry e : (Set<Map.Entry>)m.entrySet())
+ entries.add(new SimpleMapEntry(e.getKey(), e.getValue()));
+
+ out.startMap(entries.size());
+
+ for (SimpleMapEntry e : entries) {
+ Object value = e.value;
+ Object key = generalize(e.key, keyType);
+
+ serializeAnything(out, key, keyType, null, null);
+ serializeAnything(out, value, valueType, null, null);
+ }
+ }
+
+ private void serializeBeanMap(MsgPackOutputStream out, final BeanMap<?> m, String typeName) throws Exception {
+
+ List<BeanPropertyValue> values = m.getValues(isTrimNulls(), typeName != null ? createBeanTypeNameProperty(m, typeName) : null);
+
+ int size = values.size();
+ for (BeanPropertyValue p : values)
+ if (p.getThrown() != null)
+ size--;
+ out.startMap(size);
+
+ for (BeanPropertyValue p : values) {
+ BeanPropertyMeta pMeta = p.getMeta();
+ ClassMeta<?> cMeta = p.getClassMeta();
+ String key = p.getName();
+ Object value = p.getValue();
+ Throwable t = p.getThrown();
+ if (t != null)
+ onBeanGetterException(pMeta, t);
+ else {
+ serializeAnything(out, key, null, null, null);
+ serializeAnything(out, value, cMeta, key, pMeta);
+ }
+ }
+ }
+
+ private static class SimpleMapEntry {
+ final Object key;
+ final Object value;
+
+ private SimpleMapEntry(Object key, Object value) {
+ this.key = key;
+ this.value = value;
+ }
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private void serializeCollection(MsgPackOutputStream out, Collection c, ClassMeta<?> type) throws Exception {
+
+ ClassMeta<?> elementType = type.getElementType();
+ List<Object> l = new ArrayList<Object>(c.size());
+
+ c = sort(c);
+ l.addAll(c);
+
+ out.startArray(l.size());
+
+ for (Object o : l)
+ serializeAnything(out, o, elementType, "<iterator>", null);
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
index 46b1678..9fb15d6 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParser.java
@@ -45,7 +45,7 @@ public abstract class InputStreamParser extends Parser {
}
@Override /* Parser */
- public boolean isReaderParser() {
+ public final boolean isReaderParser() {
return false;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
new file mode 100644
index 0000000..3d061a5
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/InputStreamParserSession.java
@@ -0,0 +1,50 @@
+// ***************************************************************************************************************************
+// * 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;
+
+/**
+ * Subclass of parser session objects for byte-based parsers.
+ *
+ * <p>
+ * This class is NOT thread safe. It is typically discarded after one-time use.
+ */
+public abstract class InputStreamParserSession extends ParserSession {
+
+ /**
+ * Create a new session using properties specified in the context.
+ *
+ * @param ctx
+ * The context creating this session object.
+ * The context contains all the configuration settings for this object.
+ * @param args
+ * Runtime session arguments.
+ */
+ protected InputStreamParserSession(ParserContext ctx, ParserSessionArgs args) {
+ super(ctx, args);
+ }
+
+ /**
+ * Constructor for sessions that don't require context.
+ *
+ * @param args
+ * Runtime session arguments.
+ */
+ protected InputStreamParserSession(ParserSessionArgs args) {
+ this(null, args);
+ }
+
+ @Override /* ParserSession */
+ public final boolean isReaderParser() {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
index f675377..f90d497 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParseException.java
@@ -15,10 +15,8 @@ package org.apache.juneau.parser;
import static org.apache.juneau.internal.StringUtils.*;
import java.text.*;
-import java.util.*;
import org.apache.juneau.*;
-import org.apache.juneau.json.*;
/**
* Exception that indicates invalid syntax encountered during parsing.
@@ -30,12 +28,12 @@ public class ParseException extends FormattedException {
/**
* Constructor.
*
- * @param session The parser session to extract information from.
+ * @param location The location of the parse exception.
* @param message The exception message containing {@link MessageFormat}-style arguments.
* @param args Optional {@link MessageFormat}-style arguments.
*/
- public ParseException(ParserSession session, String message, Object...args) {
- super(getMessage(session, message, args));
+ public ParseException(ObjectMap location, String message, Object...args) {
+ super(getMessage(location, message, args));
}
/**
@@ -51,11 +49,11 @@ public class ParseException extends FormattedException {
/**
* Constructor.
*
- * @param session The parser session to extract information from.
+ * @param location The location of the parse exception.
* @param causedBy The inner exception.
*/
- public ParseException(ParserSession session, Exception causedBy) {
- super(causedBy, getMessage(session, causedBy.getMessage()));
+ public ParseException(ObjectMap location, Exception causedBy) {
+ super(causedBy, getMessage(location, causedBy.getMessage()));
}
/**
@@ -67,13 +65,11 @@ public class ParseException extends FormattedException {
super(causedBy, getMessage(null, causedBy.getMessage()));
}
- private static String getMessage(ParserSession session, String msg, Object... args) {
+ private static String getMessage(ObjectMap location, String msg, Object... args) {
if (args.length != 0)
msg = format(msg, args);
- if (session != null) {
- Map<String,Object> m = session.getLastLocation();
- if (m != null && ! m.isEmpty())
- msg = "Parse exception occurred at " + JsonSerializer.DEFAULT_LAX.toString(m) + ". " + msg;
+ if (location != null && ! location.isEmpty()) {
+ msg = "Parse exception occurred at " + location.toString() + ". " + msg;
}
return msg;
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
index c28dbf9..b077654 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/Parser.java
@@ -145,12 +145,10 @@ public abstract class Parser extends CoreObject {
/** General parser properties currently set on this parser. */
private final MediaType[] mediaTypes;
- private final ParserContext ctx;
// Hidden constructor to force subclass from InputStreamParser or ReaderParser.
Parser(PropertyStore propertyStore) {
super(propertyStore);
- this.ctx = createContext(ParserContext.class);
Consumes c = getAnnotation(Consumes.class, getClass());
if (c == null)
@@ -168,74 +166,35 @@ public abstract class Parser extends CoreObject {
return new ParserBuilder(propertyStore);
}
+
//--------------------------------------------------------------------------------
// Abstract methods
//--------------------------------------------------------------------------------
/**
- * Workhorse method. Subclasses are expected to implement this method.
- *
- * @param session
- * The runtime session object returned by {@link #createSession(Object, ObjectMap, Method, Object,
- * Locale, TimeZone, MediaType)}.
- * If <jk>null</jk>, one will be created using {@link #createSession(Object)}.
- * @param type
- * The class type of the object to create.
- * If <jk>null</jk> or <code>Object.<jk>class</jk></code>, object type is based on what's being parsed.
- * For example, when parsing JSON text, it may return a <code>String</code>, <code>Number</code>,
- * <code>ObjectMap</code>, etc...
- * @param <T> The class type of the object to create.
- * @return The parsed object.
- * @throws Exception If thrown from underlying stream, or if the input contains a syntax error or is malformed.
- */
- protected abstract <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception;
-
- /**
* Returns <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
*
* @return <jk>true</jk> if this parser subclasses from {@link ReaderParser}.
*/
public abstract boolean isReaderParser();
- //--------------------------------------------------------------------------------
- // Other methods
- //--------------------------------------------------------------------------------
-
/**
- * Entry point for all parsing calls.
+ * Create the session object that will be passed in to the parse method.
*
* <p>
- * Calls the {@link #doParse(ParserSession, ClassMeta)} implementation class and catches/re-wraps any exceptions
- * thrown.
+ * 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 session
- * The runtime session returned by {@link #createSession(Object, ObjectMap, Method, Object, Locale,
- * TimeZone, MediaType)}.
- * @param type The class type of the object to create.
- * @param <T> The class type of the object 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.
+ * @param args
+ * Runtime arguments.
+ * @return The new session.
*/
- public final <T> T parseSession(ParserSession session, ClassMeta<T> type) throws ParseException {
- try {
- if (type.isVoid())
- return null;
- return doParse(session, type);
- } catch (ParseException e) {
- throw e;
- } catch (StackOverflowError e) {
- throw new ParseException(session, "Depth too deep. Stack overflow occurred.");
- } catch (IOException e) {
- throw new ParseException(session, "I/O exception occurred. exception={0}, message={1}.",
- e.getClass().getSimpleName(), e.getLocalizedMessage()).initCause(e);
- } catch (Exception e) {
- throw new ParseException(session, "Exception occurred. exception={0}, message={1}.",
- e.getClass().getSimpleName(), e.getLocalizedMessage()).initCause(e);
- } finally {
- session.close();
- }
- }
+ public abstract ParserSession createSession(ParserSessionArgs args);
+
+
+ //--------------------------------------------------------------------------------
+ // Other methods
+ //--------------------------------------------------------------------------------
/**
* Parses input into the specified object type.
@@ -313,10 +272,13 @@ public abstract class Parser extends CoreObject {
* 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.
*/
- @SuppressWarnings("unchecked")
public final <T> T parse(Object input, Type type, Type...args) throws ParseException {
- ParserSession session = createSession(input);
- return (T)parseSession(session, session.getClassMeta(type, args));
+ ParserSession session = createSession();
+ try {
+ return session.parse(input, type, args);
+ } finally {
+ session.close();
+ }
}
/**
@@ -355,8 +317,12 @@ public abstract class Parser extends CoreObject {
* If the input contains a syntax error or is malformed, or is not valid for the specified type.
*/
public final <T> T parse(Object input, Class<T> type) throws ParseException {
- ParserSession session = createSession(input);
- return parseSession(session, session.getClassMeta(type));
+ ParserSession session = createSession();
+ try {
+ return session.parse(input, type);
+ } finally {
+ session.close();
+ }
}
/**
@@ -376,37 +342,12 @@ public abstract class Parser extends CoreObject {
* If the input contains a syntax error or is malformed, or is not valid for the specified type.
*/
public final <T> T parse(Object input, ClassMeta<T> type) throws ParseException {
- return parseSession(createSession(input), type);
- }
-
- /**
- * Create the session object that will be passed in to the parse method.
- *
- * <p>
- * 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 input
- * The input.
- * See {@link #parse(Object, ClassMeta)} for supported input types.
- * @param op Optional additional properties.
- * @param javaMethod
- * Java method that invoked this parser.
- * When using the REST API, this is the Java method invoked by the REST call.
- * Can be used to access annotations defined on the method or class.
- * @param outer The outer object for instantiating top-level non-static inner classes.
- * @param locale
- * The session locale.
- * If <jk>null</jk>, then the locale defined on the context is used.
- * @param timeZone
- * The session timezone.
- * If <jk>null</jk>, then the timezone defined on the context is used.
- * @param mediaType The session media type (e.g. <js>"application/json"</js>).
- * @return The new session.
- */
- public ParserSession createSession(Object input, ObjectMap op, Method javaMethod, Object outer, Locale locale,
- TimeZone timeZone, MediaType mediaType) {
- return new ParserSession(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType);
+ ParserSession session = createSession();
+ try {
+ return session.parse(input, type);
+ } finally {
+ session.close();
+ }
}
/**
@@ -415,11 +356,10 @@ public abstract class Parser extends CoreObject {
* <p>
* Equivalent to calling <code>createSession(<jk>null</jk>, <jk>null</jk>)</code>.
*
- * @param input The input. See {@link #parse(Object, ClassMeta)} for supported input types.
* @return The new context.
*/
- protected final ParserSession createSession(Object input) {
- return createSession(input, null, null, null, null, null, getPrimaryMediaType());
+ public final ParserSession createSession() {
+ return createSession(null);
}
@@ -452,39 +392,15 @@ public abstract class Parser extends CoreObject {
* @throws UnsupportedOperationException If not implemented.
*/
public final <K,V> Map<K,V> parseIntoMap(Object input, Map<K,V> m, Type keyType, Type valueType) throws ParseException {
- ParserSession session = createSession(input);
+ ParserSession session = createSession();
try {
- return doParseIntoMap(session, m, keyType, valueType);
- } catch (ParseException e) {
- throw e;
- } catch (Exception e) {
- throw new ParseException(session, e);
+ return session.parseIntoMap(input, m, keyType, valueType);
} finally {
session.close();
}
}
/**
- * Implementation method.
- *
- * <p>
- * Default implementation throws an {@link UnsupportedOperationException}.
- *
- * @param session
- * The runtime session object returned by
- * {@link #createSession(Object, ObjectMap, Method, Object, Locale, TimeZone, MediaType)}.
- * If <jk>null</jk>, one will be created using {@link #createSession(Object)}.
- * @param m The map being loaded.
- * @param keyType The class type of the keys, or <jk>null</jk> to default to <code>String.<jk>class</jk></code>.
- * @param valueType The class type of the values, or <jk>null</jk> to default to whatever is being parsed.
- * @return The same map that was passed in to allow this method to be chained.
- * @throws Exception If thrown from underlying stream, or if the input contains a syntax error or is malformed.
- */
- protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> m, Type keyType, Type valueType) throws Exception {
- throw new UnsupportedOperationException("Parser '"+getClass().getName()+"' does not support this method.");
- }
-
- /**
* Parses the contents of the specified reader and loads the results into the specified collection.
*
* <p>
@@ -504,40 +420,16 @@ public abstract class Parser extends CoreObject {
* 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 <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType)
- throws ParseException {
- ParserSession session = createSession(input);
+ public final <E> Collection<E> parseIntoCollection(Object input, Collection<E> c, Type elementType) throws ParseException {
+ ParserSession session = createSession();
try {
- return doParseIntoCollection(session, c, elementType);
- } catch (ParseException e) {
- throw e;
- } catch (Exception e) {
- throw new ParseException(session, e);
+ return session.parseIntoCollection(input, c, elementType);
} finally {
session.close();
}
}
/**
- * Implementation method.
- *
- * <p>
- * Default implementation throws an {@link UnsupportedOperationException}.
- *
- * @param session
- * The runtime session object returned by {@link #createSession(Object, ObjectMap, Method, Object,
- * Locale, TimeZone, MediaType)}.
- * If <jk>null</jk>, one will be created using {@link #createSession(Object)}.
- * @param c The collection being loaded.
- * @param elementType The class type of the elements, or <jk>null</jk> to default to whatever is being parsed.
- * @return The same collection that was passed in to allow this method to be chained.
- * @throws Exception If thrown from underlying stream, or if the input contains a syntax error or is malformed.
- */
- protected <E> Collection<E> doParseIntoCollection(ParserSession session, Collection<E> c, Type elementType) throws Exception {
- throw new UnsupportedOperationException("Parser '"+getClass().getName()+"' does not support this method.");
- }
-
- /**
* Parses the specified array input with each entry in the object defined by the {@code argTypes}
* argument.
*
@@ -561,13 +453,9 @@ public abstract class Parser extends CoreObject {
public final Object[] parseArgs(Object input, Type[] argTypes) throws ParseException {
if (argTypes == null || argTypes.length == 0)
return new Object[0];
- ParserSession session = createSession(input);
+ ParserSession session = createSession();
try {
- return doParse(session, session.getArgsClassMeta(argTypes));
- } catch (ParseException e) {
- throw e;
- } catch (Exception e) {
- throw new ParseException(session, e);
+ return session.parseArgs(input, argTypes);
} finally {
session.close();
}
@@ -579,83 +467,6 @@ public abstract class Parser extends CoreObject {
//--------------------------------------------------------------------------------
/**
- * Converts the specified string to the specified type.
- *
- * @param session The session object.
- * @param outer
- * The outer object if we're converting to an inner object that needs to be created within the context
- * of an outer object.
- * @param s The string to convert.
- * @param type The class type to convert the string to.
- * @return The string converted as an object of the specified type.
- * @throws Exception If the input contains a syntax error or is malformed, or is not valid for the specified type.
- * @param <T> The class type to convert the string to.
- */
- @SuppressWarnings({ "unchecked", "rawtypes" })
- protected <T> T convertAttrToType(ParserSession session, Object outer, String s, ClassMeta<T> type) throws Exception {
- if (s == null)
- return null;
-
- if (type == null)
- type = (ClassMeta<T>)object();
- PojoSwap transform = type.getPojoSwap();
- ClassMeta<?> sType = type.getSerializedClassMeta();
-
- Object o = s;
- if (sType.isChar())
- o = s.charAt(0);
- else if (sType.isNumber())
- if (type.canCreateNewInstanceFromNumber(outer))
- o = type.newInstanceFromNumber(session, outer, parseNumber(s, type.getNewInstanceFromNumberClass()));
- else
- o = parseNumber(s, (Class<? extends Number>)sType.getInnerClass());
- else if (sType.isBoolean())
- o = Boolean.parseBoolean(s);
- else if (! (sType.isCharSequence() || sType.isObject())) {
- if (sType.canCreateNewInstanceFromString(outer))
- o = sType.newInstanceFromString(outer, s);
- else
- throw new ParseException(session, "Invalid conversion from string to class ''{0}''", type);
- }
-
- if (transform != null)
- o = transform.unswap(session, o, type);
-
- return (T)o;
- }
-
- /**
- * Convenience method for calling the {@link ParentProperty @ParentProperty} method on the specified object if it
- * exists.
- *
- * @param cm The class type of the object.
- * @param o The object.
- * @param parent The parent to set.
- * @throws Exception
- */
- protected void setParent(ClassMeta<?> cm, Object o, Object parent) throws Exception {
- Setter m = cm.getParentProperty();
- if (m != null)
- m.set(o, parent);
- }
-
- /**
- * Convenience method for calling the {@link NameProperty @NameProperty} method on the specified object if it exists.
- *
- * @param cm The class type of the object.
- * @param o The object.
- * @param name The name to set.
- * @throws Exception
- */
- protected void setName(ClassMeta<?> cm, Object o, Object name) throws Exception {
- if (cm != null) {
- Setter m = cm.getNameProperty();
- if (m != null)
- m.set(o, name);
- }
- }
-
- /**
* Returns the media types handled based on the value of the {@link Consumes} annotation on the parser class.
*
* <p>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
index e8fd4b7..583649f 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserContext.java
@@ -21,6 +21,12 @@ import org.apache.juneau.json.*;
public class ParserContext extends BeanContext {
/**
+ * Default context with all default values.
+ */
+ @SuppressWarnings("hiding")
+ protected static final ParserContext DEFAULT = new ParserContext(PropertyStore.create());
+
+ /**
* <b>Configuration property:</b> Trim parsed strings.
*
* <ul>
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
index 846ebcb..d9ee830 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserGroup.java
@@ -92,7 +92,7 @@ public final class ParserGroup {
* tried to match against media types.
*/
public ParserGroup(PropertyStore propertyStore, Parser[] parsers) {
- this.propertyStore = PropertyStore.create(propertyStore);
+ this.propertyStore = propertyStore.copy();
this.parsers = Collections.unmodifiableList(new ArrayList<Parser>(Arrays.asList(parsers)));
List<MediaType> lmt = new ArrayList<MediaType>();
@@ -187,7 +187,7 @@ public final class ParserGroup {
* @return A new copy of the property store passed in to the constructor.
*/
public PropertyStore createPropertyStore() {
- return PropertyStore.create(propertyStore);
+ return propertyStore.copy();
}
/**
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
deleted file mode 100644
index 773606e..0000000
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserInput.java
+++ /dev/null
@@ -1,230 +0,0 @@
-// ***************************************************************************************************************************
-// * 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 static org.apache.juneau.internal.IOUtils.*;
-import static org.apache.juneau.internal.StringUtils.*;
-
-import java.io.*;
-import java.nio.charset.*;
-
-import org.apache.juneau.*;
-
-/**
- * A wrapper around an object that a parser reads its input from.
- *
- * <p>
- * For character-based parsers, the input object can be any of the following:
- * <ul>
- * <li>{@link Reader}
- * <li>{@link CharSequence}
- * <li>{@link InputStream}
- * <li><code><jk>byte</jk>[]</code>
- * <li>{@link File}
- * <li><code><jk>null</jk></code>
- * </ul>
- *
- * <p>
- * For stream-based parsers, the input object can be any of the following:
- * <ul>
- * <li>{@link InputStream}
- * <li><code><jk>byte</jk>[]</code>
- * <li>{@link File}
- * <li>{@link String} - Hex-encoded bytes. (not BASE-64!)
- * <li><code><jk>null</jk></code>
- * </ul>
- */
-public class ParserInput {
-
- private Object input;
- private String inputString;
- private InputStream inputStream;
- private Reader reader, noCloseReader;
- private boolean debug, strict;
- private String fileCharset, inputStreamCharset;
-
- /**
- * Constructor.
- *
- * @param input
- * @param debug
- * @param strict
- * @param fileCharset
- * @param inputStreamCharset
- */
- public ParserInput(Object input, boolean debug, boolean strict, String fileCharset, String inputStreamCharset) {
- this.input = input;
- this.debug = debug;
- this.strict = strict;
- this.fileCharset = fileCharset;
- this.inputStreamCharset = inputStreamCharset;
- }
-
- /**
- * Wraps the specified input object inside an input stream.
- *
- * <p>
- * Subclasses can override this method to implement their own input streams.
- *
- * @return The input object wrapped in an input stream, or <jk>null</jk> if the object is null.
- * @throws ParseException If object could not be converted to an input stream.
- */
- public InputStream getInputStream() throws ParseException {
- try {
- if (input == null)
- return null;
- if (input instanceof InputStream) {
- if (debug) {
- byte[] b = readBytes((InputStream)input, 1024);
- inputString = toHex(b);
- return new ByteArrayInputStream(b);
- }
- return (InputStream)input;
- }
- if (input instanceof byte[]) {
- if (debug)
- inputString = toHex((byte[])input);
- return new ByteArrayInputStream((byte[])input);
- }
- if (input instanceof String) {
- inputString = (String)input;
- return new ByteArrayInputStream(fromHex((String)input));
- }
- if (input instanceof File) {
- if (debug) {
- byte[] b = readBytes((File)input);
- inputString = toHex(b);
- return new ByteArrayInputStream(b);
- }
- inputStream = new FileInputStream((File)input);
- return inputStream;
- }
- } catch (IOException e) {
- throw new ParseException(e);
- }
- throw new ParseException("Cannot convert object of type {0} to an InputStream.", input.getClass().getName());
- }
-
-
- /**
- * Wraps the specified input object inside a reader.
- *
- * <p>
- * Subclasses can override this method to implement their own readers.
- *
- * @return The input object wrapped in a Reader, or <jk>null</jk> if the object is null.
- * @throws Exception If object could not be converted to a reader.
- */
- public Reader getReader() throws Exception {
- if (input == null)
- return null;
- if (input instanceof Reader) {
- if (debug) {
- inputString = read((Reader)input);
- return new StringReader(inputString);
- }
- return (Reader)input;
- }
- if (input instanceof CharSequence) {
- inputString = input.toString();
- if (reader == null)
- reader = new ParserReader((CharSequence)input);
- return reader;
- }
- if (input instanceof InputStream || input instanceof byte[]) {
- InputStream is = (
- input instanceof InputStream
- ? (InputStream)input
- : new ByteArrayInputStream((byte[])input)
- );
- if (noCloseReader == null) {
- CharsetDecoder cd = (
- "default".equalsIgnoreCase(inputStreamCharset)
- ? Charset.defaultCharset()
- : Charset.forName(inputStreamCharset)
- ).newDecoder();
- if (strict) {
- cd.onMalformedInput(CodingErrorAction.REPORT);
- cd.onUnmappableCharacter(CodingErrorAction.REPORT);
- } else {
- cd.onMalformedInput(CodingErrorAction.REPLACE);
- cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
- noCloseReader = new InputStreamReader(is, cd);
- }
- if (debug) {
- inputString = read(noCloseReader);
- return new StringReader(inputString);
- }
- return noCloseReader;
- }
- if (input instanceof File) {
- if (reader == null) {
- CharsetDecoder cd = (
- "default".equalsIgnoreCase(fileCharset)
- ? Charset.defaultCharset()
- : Charset.forName(fileCharset)
- ).newDecoder();
- if (strict) {
- cd.onMalformedInput(CodingErrorAction.REPORT);
- cd.onUnmappableCharacter(CodingErrorAction.REPORT);
- } else {
- cd.onMalformedInput(CodingErrorAction.REPLACE);
- cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
- }
- reader = new InputStreamReader(new FileInputStream((File)input), cd);
- }
- if (debug) {
- inputString = read(reader);
- return new StringReader(inputString);
- }
- return reader;
- }
- throw new ParseException("Cannot convert object of type {0} to a Reader.", input.getClass().getName());
- }
-
- /**
- * Returns the raw input object passed into this session.
- *
- * @return The raw input object passed into this session.
- */
- protected Object getRawInput() {
- return input;
- }
-
- /**
- * Returns the input to this parser as a plain string.
- *
- * <p>
- * This method only returns a value if {@link BeanContext#BEAN_debug} is enabled.
- *
- * @return The input as a string, or <jk>null</jk> if debug mode not enabled.
- */
- public String getInputAsString() {
- return inputString;
- }
-
- /**
- * Perform cleanup on this context object if necessary.
- */
- public void close() {
- try {
- if (inputStream != null)
- inputStream.close();
- if (reader != null)
- reader.close();
- } catch (IOException e) {
- throw new BeanRuntimeException(e);
- }
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
index 75d39bb..83ac9a7 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserListener.java
@@ -29,10 +29,11 @@ public class ParserListener {
* Otherwise, the parser will throw a {@link ParseException}.
*
* @param <T> The class type of the bean.
- * @param session
- * The parser session.
+ * @param session The parser session.
+ * @param pipe
+ * The parser input.
* Note that if {@link BeanContext#BEAN_debug} is enabled on the parser, you can get the input as a string through
- * {@link ParserSession#getInputAsString()}.
+ * {@link ParserPipe#getInputAsString()}.
* @param propertyName The property name encountered in the document.
* @param beanClass The bean class.
* @param bean The bean.
@@ -41,8 +42,8 @@ public class ParserListener {
* @param col
* The column number where the unknown property was found (-1 if parser doesn't support line/column indicators).
*/
- public <T> void onUnknownBeanProperty(ParserSession session, String propertyName, Class<T> beanClass, T bean, int line, int col) {
- onError(session, null,
+ public <T> void onUnknownBeanProperty(ParserSession session, ParserPipe pipe, String propertyName, Class<T> beanClass, T bean, int line, int col) {
+ onError(session, pipe, null,
format("Unknown property ''{0}'' encountered while trying to parse into class ''{1}'' at line {2} column {3}",
propertyName, beanClass, line, col)
);
@@ -51,13 +52,15 @@ public class ParserListener {
/**
* Called when an error occurs during parsing but is ignored.
*
- * @param session The parsers session.
+ * @param session The parser session.
+ * @param pipe
+ * The parser input.
* Note that if {@link BeanContext#BEAN_debug} is enabled on the parser, you can get the input as a string through
- * {@link ParserSession#getInputAsString()}.
+ * {@link ParserPipe#getInputAsString()}.
* @param t The throwable that was thrown by the getter method.
* @param msg The error message.
*/
- public void onError(ParserSession session, Throwable t, String msg) {
+ public void onError(ParserSession session, ParserPipe pipe, Throwable t, String msg) {
// Do something with this information.
}
}
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
new file mode 100644
index 0000000..4faf988
--- /dev/null
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserPipe.java
@@ -0,0 +1,278 @@
+// ***************************************************************************************************************************
+// * 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 static org.apache.juneau.internal.IOUtils.*;
+import static org.apache.juneau.internal.StringUtils.*;
+
+import java.io.*;
+import java.nio.charset.*;
+
+import org.apache.juneau.*;
+import org.apache.juneau.internal.*;
+
+/**
+ * A wrapper around an object that a parser reads its input from.
+ *
+ * <p>
+ * For character-based parsers, the input object can be any of the following:
+ * <ul>
+ * <li>{@link Reader}
+ * <li>{@link CharSequence}
+ * <li>{@link InputStream}
+ * <li><code><jk>byte</jk>[]</code>
+ * <li>{@link File}
+ * <li><code><jk>null</jk></code>
+ * </ul>
+ *
+ * <p>
+ * For stream-based parsers, the input object can be any of the following:
+ * <ul>
+ * <li>{@link InputStream}
+ * <li><code><jk>byte</jk>[]</code>
+ * <li>{@link File}
+ * <li>{@link String} - Hex-encoded bytes. (not BASE-64!)
+ * <li><code><jk>null</jk></code>
+ * </ul>
+ *
+ * <p>
+ * Note that Readers and InputStreams will NOT be automatically closed when {@link #close()} is called, but
+ * streams and readers created from other types (e.g. Files) WILL be automatically closed.
+ */
+public final class ParserPipe {
+
+ private final Object input;
+ private final boolean debug, strict;
+ private final String fileCharset, inputStreamCharset;
+
+ private String inputString;
+ private InputStream inputStream;
+ private Reader reader;
+
+ /**
+ * Constructor.
+ *
+ * @param input The parser input object.
+ * @param debug
+ * If <jk>true</jk>, the input contents will be copied locally and accessible via the {@link #getInputAsString()}
+ * method.
+ * This allows the contents of the pipe to be accessed when a problem occurs.
+ * @param strict
+ * If <jk>true</jk>, sets {@link CodingErrorAction#REPORT} on {@link CharsetDecoder#onMalformedInput(CodingErrorAction)}
+ * and {@link CharsetDecoder#onUnmappableCharacter(CodingErrorAction)}.
+ * Otherwise, sets them to {@link CodingErrorAction#REPLACE}.
+ * @param fileCharset
+ * The charset to expect when reading from {@link File Files}.
+ * Use <js>"default"</js> to specify {@link Charset#defaultCharset()}.
+ * @param inputStreamCharset
+ * The charset to expect when reading from {@link InputStream InputStreams}.
+ * Use <js>"default"</js> to specify {@link Charset#defaultCharset()}.
+ */
+ public ParserPipe(Object input, boolean debug, boolean strict, String fileCharset, String inputStreamCharset) {
+ this.input = input;
+ this.debug = debug;
+ this.strict = strict;
+ this.fileCharset = fileCharset;
+ this.inputStreamCharset = inputStreamCharset;
+ if (input instanceof CharSequence)
+ this.inputString = input.toString();
+ }
+
+ /**
+ * Shortcut constructor, typically for straight string input.
+ *
+ * <p>
+ * Equivalent to calling <code><jk>new</jk> ParserPipe(input, <jk>false</jk>, <jk>false</jk>, <jk>null</jk>, <jk>null</jk>);</code>
+ *
+ * @param input The input object.
+ */
+ public ParserPipe(Object input) {
+ this(input, false, false, null, null);
+ }
+
+ /**
+ * Wraps the specified input object inside an input stream.
+ *
+ * <p>
+ * Subclasses can override this method to implement their own input streams.
+ *
+ * @return The input object wrapped in an input stream, or <jk>null</jk> if the object is null.
+ * @throws IOException If object could not be converted to an input stream.
+ */
+ public InputStream getInputStream() throws IOException {
+ if (input == null)
+ return null;
+
+ if (input instanceof InputStream) {
+ if (debug) {
+ byte[] b = readBytes((InputStream)input, 1024);
+ inputString = toHex(b);
+ inputStream = new ByteArrayInputStream(b);
+ } else {
+ inputStream = (InputStream)input;
+ }
+ } else if (input instanceof byte[]) {
+ if (debug)
+ inputString = toHex((byte[])input);
+ inputStream = new ByteArrayInputStream((byte[])input);
+ } else if (input instanceof String) {
+ inputString = (String)input;
+ inputStream = new ByteArrayInputStream(fromHex((String)input));
+ } else if (input instanceof File) {
+ if (debug) {
+ byte[] b = readBytes((File)input);
+ inputString = toHex(b);
+ inputStream = new ByteArrayInputStream(b);
+ } else {
+ inputStream = new FileInputStream((File)input);
+ }
+ } else {
+ throw new IOException("Cannot convert object of type "+input.getClass().getName()+" to an InputStream.");
+ }
+
+ return inputStream;
+ }
+
+
+ /**
+ * Wraps the specified input object inside a reader.
+ *
+ * <p>
+ * Subclasses can override this method to implement their own readers.
+ *
+ * @return The input object wrapped in a Reader, or <jk>null</jk> if the object is null.
+ * @throws IOException If object could not be converted to a reader.
+ */
+ public Reader getReader() throws IOException {
+ if (input == null)
+ return null;
+
+ if (input instanceof Reader) {
+ if (debug) {
+ inputString = read((Reader)input);
+ reader = new StringReader(inputString);
+ } else {
+ reader = (Reader)input;
+ }
+ } else if (input instanceof CharSequence) {
+ inputString = input.toString();
+ reader = new ParserReader(this);
+ } else if (input instanceof InputStream || input instanceof byte[]) {
+ InputStream is = (
+ input instanceof InputStream
+ ? (InputStream)input
+ : new ByteArrayInputStream((byte[])input)
+ );
+ CharsetDecoder cd = (
+ "default".equalsIgnoreCase(inputStreamCharset)
+ ? Charset.defaultCharset()
+ : Charset.forName(inputStreamCharset)
+ ).newDecoder();
+ if (strict) {
+ cd.onMalformedInput(CodingErrorAction.REPORT);
+ cd.onUnmappableCharacter(CodingErrorAction.REPORT);
+ } else {
+ cd.onMalformedInput(CodingErrorAction.REPLACE);
+ cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ reader = new InputStreamReader(is, cd);
+ if (debug) {
+ inputString = read(reader);
+ reader = new StringReader(inputString);
+ }
+ } else if (input instanceof File) {
+ CharsetDecoder cd = (
+ "default".equalsIgnoreCase(fileCharset)
+ ? Charset.defaultCharset()
+ : Charset.forName(fileCharset)
+ ).newDecoder();
+ if (strict) {
+ cd.onMalformedInput(CodingErrorAction.REPORT);
+ cd.onUnmappableCharacter(CodingErrorAction.REPORT);
+ } else {
+ cd.onMalformedInput(CodingErrorAction.REPLACE);
+ cd.onUnmappableCharacter(CodingErrorAction.REPLACE);
+ }
+ reader = new InputStreamReader(new FileInputStream((File)input), cd);
+ if (debug) {
+ inputString = read(reader);
+ reader = new StringReader(inputString);
+ }
+ } else {
+ throw new IOException("Cannot convert object of type "+input.getClass().getName()+" to a Reader.");
+ }
+
+ return reader;
+ }
+
+ /**
+ * Returns the contents of this pipe as a buffered reader.
+ *
+ * <p>
+ * If the reader passed into this pipe is already a buffered reader, that reader will be returned.
+ *
+ * @return The contents of this pipe as a buffered reader.
+ * @throws Exception
+ */
+ public Reader getBufferedReader() throws Exception {
+ return IOUtils.getBufferedReader(getReader());
+ }
+
+ /**
+ * Returns the input to this parser as a plain string.
+ *
+ * <p>
+ * This method only returns a value if {@link BeanContext#BEAN_debug} is enabled.
+ *
+ * @return The input as a string, or <jk>null</jk> if debug mode not enabled.
+ */
+ public String getInputAsString() {
+ return inputString;
+ }
+
+ /**
+ * Converts this pipe into a {@link ParserReader}.
+ *
+ * @return The converted pipe.
+ * @throws Exception
+ */
+ public ParserReader getParserReader() throws Exception {
+ if (input == null)
+ return null;
+ if (input instanceof ParserReader)
+ reader = (ParserReader)input;
+ else
+ reader = new ParserReader(this);
+ return (ParserReader)reader;
+ }
+
+ /**
+ * Returns <jk>true</jk> if the contents passed into this pipe was a {@link CharSequence}.
+ *
+ * @return <jk>true</jk> if the contents passed into this pipe was a {@link CharSequence}.
+ */
+ public boolean isString() {
+ return inputString != null;
+ }
+
+ /**
+ * Perform cleanup on this context object if necessary.
+ */
+ public void close() {
+ try {
+ IOUtils.close(reader, inputStream);
+ } catch (IOException e) {
+ throw new BeanRuntimeException(e);
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
----------------------------------------------------------------------
diff --git a/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java b/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
index daa1593..3c75e36 100644
--- a/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
+++ b/juneau-core/src/main/java/org/apache/juneau/parser/ParserReader.java
@@ -14,6 +14,7 @@ package org.apache.juneau.parser;
import java.io.*;
+import org.apache.juneau.*;
import org.apache.juneau.internal.*;
/**
@@ -32,7 +33,8 @@ import org.apache.juneau.internal.*;
public class ParserReader extends Reader {
/** Wrapped reader */
- protected Reader r;
+ protected final Reader r;
+ private final ParserPipe pipe;
private char[] buff; // Internal character buffer
private int line = 1; // Current line number
@@ -42,33 +44,28 @@ public class ParserReader extends Reader {
private int iEnd = 0; // The last good character position in the buffer
private boolean endReached, holesExist;
- ParserReader() {}
-
/**
- * Constructor for input from a {@link CharSequence}.
+ * Constructor.
*
- * @param in The character sequence being read from.
+ * @param pipe The parser input.
+ * @throws IOException
*/
- public ParserReader(CharSequence in) {
- this.r = new CharSequenceReader(in);
- if (in == null)
- this.buff = new char[0];
- else
+ public ParserReader(ParserPipe pipe) throws IOException {
+ this.pipe = pipe;
+ if (pipe.isString()) {
+ String in = pipe.getInputAsString();
+ this.r = new CharSequenceReader(in);
this.buff = new char[in.length() < 1024 ? in.length() : 1024];
+ } else {
+ Reader _r = pipe.getReader();
+ if (_r instanceof ParserReader)
+ this.r = ((ParserReader)_r).r;
+ else
+ this.r = _r;
+ this.buff = new char[1024];
+ }
}
- /**
- * Constructor for input from a {@link Reader}).
- *
- * @param r The Reader being wrapped.
- */
- public ParserReader(Reader r) {
- if (r instanceof ParserReader)
- this.r = ((ParserReader)r).r;
- else
- this.r = r;
- this.buff = new char[1024];
- }
/**
* Returns the current line number position in this reader.
@@ -278,7 +275,7 @@ public class ParserReader extends Reader {
* @return This object (for method chaining).
* @throws IOException If a problem occurred trying to read from the reader.
*/
- public final ParserReader unread() throws IOException {
+ public ParserReader unread() throws IOException {
if (iCurrent <= 0)
throw new IOException("Buffer underflow.");
iCurrent--;
@@ -293,7 +290,8 @@ public class ParserReader extends Reader {
*/
@Override /* Reader */
public void close() throws IOException {
- r.close();
+ if (r != null)
+ r.close();
}
/**
@@ -417,4 +415,23 @@ public class ParserReader extends Reader {
public int read(char[] cbuf, int off, int len) throws IOException {
return r.read(cbuf, off, len);
}
+
+ /**
+ * Returns the combined location information on both this reader and the session.
+ *
+ * @param session The session object to read the last location on.
+ * @return A new map describing the current parse location.
+ */
+ public ObjectMap getLocation(ParserSession session) {
+ return session.getLastLocation().append("line", getLine()).append("column", getColumn());
+ }
+
+ /**
+ * Returns the pipe that was passed into the constructor.
+ *
+ * @return The pipe that was passed into the constructor.
+ */
+ public final ParserPipe getPipe() {
+ return pipe;
+ }
}