http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java index 6ceb906..9f872c0 100644 --- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java +++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java @@ -14,19 +14,15 @@ package org.apache.juneau.urlencoding; import static org.apache.juneau.serializer.SerializerContext.*; import static org.apache.juneau.uon.UonSerializerContext.*; -import static org.apache.juneau.internal.ArrayUtils.*; +import static org.apache.juneau.urlencoding.UrlEncodingContext.*; import static org.apache.juneau.internal.StringUtils.*; import java.io.*; -import java.lang.reflect.*; import java.net.*; -import java.util.*; import org.apache.juneau.*; import org.apache.juneau.annotation.*; -import org.apache.juneau.http.*; import org.apache.juneau.serializer.*; -import org.apache.juneau.transform.*; import org.apache.juneau.uon.*; /** @@ -158,12 +154,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ * @param propertyStore The property store containing all the settings for this object. */ public Expanded(PropertyStore propertyStore) { - super(propertyStore); - } - - @Override /* CoreObject */ - protected ObjectMap getOverrideProperties() { - return super.getOverrideProperties().append(UrlEncodingContext.URLENC_expandedParams, true); + super(propertyStore.copy().append(URLENC_expandedParams, true)); } } @@ -178,12 +169,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ * @param propertyStore The property store containing all the settings for this object. */ public Readable(PropertyStore propertyStore) { - super(propertyStore); - } - - @Override /* CoreObject */ - protected ObjectMap getOverrideProperties() { - return super.getOverrideProperties().append(SERIALIZER_useWhitespace, true); + super(propertyStore.copy().append(SERIALIZER_useWhitespace, true)); } } @@ -198,12 +184,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ * @param propertyStore The property store containing all the settings for this object. */ public PlainText(PropertyStore propertyStore) { - super(propertyStore); - } - - @Override /* CoreObject */ - protected ObjectMap getOverrideProperties() { - return super.getOverrideProperties().append(UonSerializerContext.UON_paramFormat, "PLAINTEXT"); + super(propertyStore.copy().append(UON_paramFormat, "PLAINTEXT")); } } @@ -215,7 +196,7 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ * @param propertyStore The property store containing all the settings for this object. */ public UrlEncodingSerializer(PropertyStore propertyStore) { - super(propertyStore); + super(propertyStore.copy().append(UON_encodeChars, true)); this.ctx = createContext(UrlEncodingSerializerContext.class); } @@ -224,183 +205,6 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ return new UrlEncodingSerializerBuilder(propertyStore); } - @Override /* CoreObject */ - protected ObjectMap getOverrideProperties() { - return super.getOverrideProperties().append(UON_encodeChars, true); - } - - /** - * Workhorse method. Determines the type of object, and then calls the appropriate type-specific serialization method. - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - private SerializerWriter serializeAnything(UrlEncodingSerializerSession session, UonWriter out, Object o) throws Exception { - - ClassMeta<?> aType; // The actual type - ClassMeta<?> sType; // The serialized type - - aType = session.push("root", o, object()); - session.indent--; - if (aType == null) - aType = object(); - - sType = aType.getSerializedClassMeta(); - String typeName = session.getBeanTypeName(session.object(), aType, null); - - // Swap if necessary - PojoSwap swap = aType.getPojoSwap(); - if (swap != null) { - o = swap.swap(session, o); - - // If the getSwapClass() method returns Object, we need to figure out - // the actual type now. - if (sType.isObject()) - sType = session.getClassMetaForObject(o); - } - - if (sType.isMap()) { - if (o instanceof BeanMap) - serializeBeanMap(session, out, (BeanMap)o, typeName); - else - serializeMap(session, out, (Map)o, sType); - } else if (sType.isBean()) { - serializeBeanMap(session, out, session.toBeanMap(o), typeName); - } else if (sType.isCollection() || sType.isArray()) { - Map m = sType.isCollection() ? getCollectionMap((Collection)o) : getCollectionMap(o); - serializeCollectionMap(session, out, m, session.getClassMeta(Map.class, Integer.class, Object.class)); - } else { - // All other types can't be serialized as key/value pairs, so we create a - // mock key/value pair with a "_value" key. - out.append("_value="); - super.serializeAnything(session, out, o, null, null, null); - } - - session.pop(); - return out; - } - - /** - * Converts a Collection into an integer-indexed map. - */ - private static Map<Integer,Object> getCollectionMap(Collection<?> c) { - Map<Integer,Object> m = new TreeMap<Integer,Object>(); - int i = 0; - for (Object o : c) - m.put(i++, o); - return m; - } - - /** - * Converts an array into an integer-indexed map. - */ - private static Map<Integer,Object> getCollectionMap(Object array) { - Map<Integer,Object> m = new TreeMap<Integer,Object>(); - for (int i = 0; i < Array.getLength(array); i++) - m.put(i, Array.get(array, i)); - return m; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private SerializerWriter serializeMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception { - - m = session.sort(m); - - ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType(); - - int depth = session.getIndent(); - boolean addAmp = false; - - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) { - Object key = session.generalize(e.getKey(), keyType); - Object value = e.getValue(); - - if (session.shouldUseExpandedParams(value)) { - Iterator i = value instanceof Collection ? ((Collection)value).iterator() : iterator(value); - while (i.hasNext()) { - if (addAmp) - out.cr(depth).append('&'); - out.appendObject(key, true).append('='); - super.serializeAnything(session, out, i.next(), null, (key == null ? null : key.toString()), null); - addAmp = true; - } - } else { - if (addAmp) - out.cr(depth).append('&'); - out.appendObject(key, true).append('='); - super.serializeAnything(session, out, value, valueType, (key == null ? null : key.toString()), null); - addAmp = true; - } - } - - return out; - } - - @SuppressWarnings({ "rawtypes", "unchecked" }) - private SerializerWriter serializeCollectionMap(UrlEncodingSerializerSession session, UonWriter out, Map m, ClassMeta<?> type) throws Exception { - - ClassMeta<?> valueType = type.getValueType(); - - int depth = session.getIndent(); - boolean addAmp = false; - - for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) { - if (addAmp) - out.cr(depth).append('&'); - out.append(e.getKey()).append('='); - super.serializeAnything(session, out, e.getValue(), valueType, null, null); - addAmp = true; - } - - return out; - } - - @SuppressWarnings({ "rawtypes" }) - private SerializerWriter serializeBeanMap(UrlEncodingSerializerSession session, UonWriter out, BeanMap<?> m, String typeName) throws Exception { - int depth = session.getIndent(); - - boolean addAmp = false; - - for (BeanPropertyValue p : m.getValues(session.isTrimNulls(), typeName != null ? session.createBeanTypeNameProperty(m, typeName) : null)) { - BeanPropertyMeta pMeta = p.getMeta(); - ClassMeta<?> cMeta = p.getClassMeta(); - - String key = p.getName(); - Object value = p.getValue(); - Throwable t = p.getThrown(); - if (t != null) - session.onBeanGetterException(pMeta, t); - - if (session.canIgnoreValue(cMeta, key, value)) - continue; - - if (value != null && session.shouldUseExpandedParams(pMeta)) { - // Transformed object array bean properties may be transformed resulting in ArrayLists, - // so we need to check type if we think it's an array. - Iterator i = (cMeta.isCollection() || value instanceof Collection) ? ((Collection)value).iterator() : iterator(value); - while (i.hasNext()) { - if (addAmp) - out.cr(depth).append('&'); - - out.appendObject(key, true).append('='); - - super.serializeAnything(session, out, i.next(), cMeta.getElementType(), key, pMeta); - - addAmp = true; - } - } else { - if (addAmp) - out.cr(depth).append('&'); - - out.appendObject(key, true).append('='); - - super.serializeAnything(session, out, value, cMeta, key, pMeta); - - addAmp = true; - } - - } - return out; - } - //-------------------------------------------------------------------------------- // Methods for constructing individual parameter values. @@ -438,9 +242,8 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ } StringWriter w = new StringWriter(); - SerializerOutput out = new SerializerOutput(w); - UonSerializerSession s = new UrlEncodingSerializerSession(ctx, urlEncode, null, null, null, null, MediaType.UON, null); - super.doSerialize(s, out, o); + UonSerializerSession s = new UonSerializerSession(ctx, urlEncode, SerializerSessionArgs.DEFAULT); + s.serialize(w, o); return w.toString(); } catch (Exception e) { throw new RuntimeException(e); @@ -453,15 +256,8 @@ public class UrlEncodingSerializer extends UonSerializer implements PartSerializ //-------------------------------------------------------------------------------- @Override /* Serializer */ - public UrlEncodingSerializerSession createSession(ObjectMap op, Method javaMethod, Locale locale, - TimeZone timeZone, MediaType mediaType, UriContext uriContext) { - return new UrlEncodingSerializerSession(ctx, null, op, javaMethod, locale, timeZone, mediaType, uriContext); - } - - @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - UrlEncodingSerializerSession s = (UrlEncodingSerializerSession)session; - serializeAnything(s, s.getUonWriter(out), o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new UrlEncodingSerializerSession(ctx, null, args); } @Override /* PartSerializer */
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java index 6a0fb21..46e36d2 100644 --- a/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java +++ b/juneau-core/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java @@ -12,62 +12,56 @@ // *************************************************************************************************************************** package org.apache.juneau.urlencoding; +import static org.apache.juneau.internal.ArrayUtils.*; + 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.*; import org.apache.juneau.uon.*; /** * Session object that lives for the duration of a single use of {@link UrlEncodingSerializer}. * * <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. */ +@SuppressWarnings({ "rawtypes", "unchecked" }) public class UrlEncodingSerializerSession extends UonSerializerSession { private final boolean expandedParams; /** - * Create a new session using properties specified in the context. + * Constructor. * * @param ctx * The context creating this session object. * The context contains all the configuration settings for this object. - * @param encode Overrides the {@link UonSerializerContext#UON_encodeChars} setting. - * @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 encode Override the {@link UonSerializerContext#UON_encodeChars} setting. + * @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}. */ - public UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, Boolean encode, ObjectMap op, - Method javaMethod, Locale locale, TimeZone timeZone, MediaType mediaType, UriContext uriContext) { - super(ctx, encode, op, javaMethod, locale, timeZone, mediaType, uriContext); - if (op == null || op.isEmpty()) { + protected UrlEncodingSerializerSession(UrlEncodingSerializerContext ctx, Boolean encode, SerializerSessionArgs args) { + super(ctx, encode, args); + ObjectMap p = getProperties(); + if (p.isEmpty()) { expandedParams = ctx.expandedParams; } else { - expandedParams = op.getBoolean(UrlEncodingContext.URLENC_expandedParams, false); + expandedParams = p.getBoolean(UrlEncodingContext.URLENC_expandedParams, false); } } - /** + /* * Returns <jk>true</jk> if the specified bean property should be expanded as multiple key-value pairs. - * - * @param pMeta The metadata on the bean property. - * @return <jk>true</jk> if the specified bean property should be expanded as multiple key-value pairs. */ - public final boolean shouldUseExpandedParams(BeanPropertyMeta pMeta) { + private boolean shouldUseExpandedParams(BeanPropertyMeta pMeta) { ClassMeta<?> cm = pMeta.getClassMeta(); if (cm.isCollectionOrArray()) { if (expandedParams) @@ -78,13 +72,10 @@ public class UrlEncodingSerializerSession extends UonSerializerSession { return false; } - /** + /* * Returns <jk>true</jk> if the specified value should be represented as an expanded parameter list. - * - * @param value The value to check. - * @return <jk>true</jk> if the specified value should be represented as an expanded parameter list. */ - public final boolean shouldUseExpandedParams(Object value) { + private boolean shouldUseExpandedParams(Object value) { if (value == null || ! expandedParams) return false; ClassMeta<?> cm = getClassMetaForObject(value).getSerializedClassMeta(); @@ -94,4 +85,173 @@ public class UrlEncodingSerializerSession extends UonSerializerSession { } return false; } + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + serializeAnything(getUonWriter(out), o); + } + + /* + * Workhorse method. Determines the type of object, and then calls the appropriate type-specific serialization method. + */ + private SerializerWriter serializeAnything(UonWriter out, Object o) throws Exception { + + ClassMeta<?> aType; // The actual type + ClassMeta<?> sType; // The serialized type + + aType = push("root", o, object()); + indent--; + if (aType == null) + aType = object(); + + sType = aType.getSerializedClassMeta(); + String typeName = getBeanTypeName(object(), aType, null); + + // 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); + } + + if (sType.isMap()) { + if (o instanceof BeanMap) + serializeBeanMap(out, (BeanMap)o, typeName); + else + serializeMap(out, (Map)o, sType); + } else if (sType.isBean()) { + serializeBeanMap(out, toBeanMap(o), typeName); + } else if (sType.isCollection() || sType.isArray()) { + Map m = sType.isCollection() ? getCollectionMap((Collection)o) : getCollectionMap(o); + serializeCollectionMap(out, m, getClassMeta(Map.class, Integer.class, Object.class)); + } else { + // All other types can't be serialized as key/value pairs, so we create a + // mock key/value pair with a "_value" key. + out.append("_value="); + super.serializeAnything(out, o, null, null, null); + } + + pop(); + return out; + } + + /* + * Converts a Collection into an integer-indexed map. + */ + private static Map<Integer,Object> getCollectionMap(Collection<?> c) { + Map<Integer,Object> m = new TreeMap<Integer,Object>(); + int i = 0; + for (Object o : c) + m.put(i++, o); + return m; + } + + /* + * Converts an array into an integer-indexed map. + */ + private static Map<Integer,Object> getCollectionMap(Object array) { + Map<Integer,Object> m = new TreeMap<Integer,Object>(); + for (int i = 0; i < Array.getLength(array); i++) + m.put(i, Array.get(array, i)); + return m; + } + + private SerializerWriter serializeMap(UonWriter out, Map m, ClassMeta<?> type) throws Exception { + + m = sort(m); + + ClassMeta<?> keyType = type.getKeyType(), valueType = type.getValueType(); + + boolean addAmp = false; + + for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) { + Object key = generalize(e.getKey(), keyType); + Object value = e.getValue(); + + if (shouldUseExpandedParams(value)) { + Iterator i = value instanceof Collection ? ((Collection)value).iterator() : iterator(value); + while (i.hasNext()) { + if (addAmp) + out.cr(indent).append('&'); + out.appendObject(key, true).append('='); + super.serializeAnything(out, i.next(), null, (key == null ? null : key.toString()), null); + addAmp = true; + } + } else { + if (addAmp) + out.cr(indent).append('&'); + out.appendObject(key, true).append('='); + super.serializeAnything(out, value, valueType, (key == null ? null : key.toString()), null); + addAmp = true; + } + } + + return out; + } + + private SerializerWriter serializeCollectionMap(UonWriter out, Map m, ClassMeta<?> type) throws Exception { + + ClassMeta<?> valueType = type.getValueType(); + + boolean addAmp = false; + + for (Map.Entry e : (Set<Map.Entry>)m.entrySet()) { + if (addAmp) + out.cr(indent).append('&'); + out.append(e.getKey()).append('='); + super.serializeAnything(out, e.getValue(), valueType, null, null); + addAmp = true; + } + + return out; + } + + private SerializerWriter serializeBeanMap(UonWriter out, BeanMap<?> m, String typeName) throws Exception { + boolean addAmp = false; + + for (BeanPropertyValue p : m.getValues(isTrimNulls(), typeName != null ? createBeanTypeNameProperty(m, typeName) : null)) { + 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); + + if (canIgnoreValue(cMeta, key, value)) + continue; + + if (value != null && shouldUseExpandedParams(pMeta)) { + // Transformed object array bean properties may be transformed resulting in ArrayLists, + // so we need to check type if we think it's an array. + Iterator i = (cMeta.isCollection() || value instanceof Collection) ? ((Collection)value).iterator() : iterator(value); + while (i.hasNext()) { + if (addAmp) + out.cr(indent).append('&'); + + out.appendObject(key, true).append('='); + + super.serializeAnything(out, i.next(), cMeta.getElementType(), key, pMeta); + + addAmp = true; + } + } else { + if (addAmp) + out.cr(indent).append('&'); + + out.appendObject(key, true).append('='); + + super.serializeAnything(out, value, cMeta, key, pMeta); + + addAmp = true; + } + + } + return out; + } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java index e7e4548..6e70c35 100644 --- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializer.java @@ -46,12 +46,7 @@ public class XmlDocSerializer extends XmlSerializer { * @param propertyStore The property store containing all the settings for this object. */ public Ns(PropertyStore propertyStore) { - super(propertyStore); - } - - @Override /* CoreObject */ - protected ObjectMap getOverrideProperties() { - return super.getOverrideProperties().append(XML_enableNamespaces, true); + super(propertyStore.copy().append(XML_enableNamespaces, true)); } } @@ -64,19 +59,8 @@ public class XmlDocSerializer extends XmlSerializer { super(propertyStore); } - //-------------------------------------------------------------------------------- - // Entry point methods - //-------------------------------------------------------------------------------- - @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - XmlSerializerSession s = (XmlSerializerSession)session; - XmlWriter w = s.getXmlWriter(out); - w.append("<?xml") - .attr("version", "1.0") - .attr("encoding", "UTF-8") - .appendln("?>"); - w.flush(); - super.doSerialize(s, out, o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new XmlDocSerializerSession(ctx, args); } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java new file mode 100644 index 0000000..b889889 --- /dev/null +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlDocSerializerSession.java @@ -0,0 +1,53 @@ +// *************************************************************************************************************************** +// * 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.xml; + +import org.apache.juneau.serializer.*; + +/** + * Session object that lives for the duration of a single use of {@link XmlDocSerializer}. + * + * <p> + * This class is NOT thread safe. + * It is typically discarded after one-time use although it can be reused within the same thread. + */ +public class XmlDocSerializerSession extends XmlSerializerSession { + + /** + * 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 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 XmlDocSerializerSession(XmlSerializerContext ctx, SerializerSessionArgs args) { + super(ctx, args); + } + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + XmlWriter w = getXmlWriter(out); + w.append("<?xml") + .attr("version", "1.0") + .attr("encoding", "UTF-8") + .appendln("?>"); + w.flush(); + super.doSerialize(out, o); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java index aed0b63..cd81507 100644 --- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParser.java @@ -12,22 +12,9 @@ // *************************************************************************************************************************** package org.apache.juneau.xml; -import static javax.xml.stream.XMLStreamConstants.*; -import static org.apache.juneau.internal.StringUtils.*; -import static org.apache.juneau.xml.annotation.XmlFormat.*; - -import java.lang.reflect.*; -import java.util.*; - -import javax.xml.stream.*; -import javax.xml.stream.Location; - import org.apache.juneau.*; import org.apache.juneau.annotation.*; -import org.apache.juneau.http.*; import org.apache.juneau.parser.*; -import org.apache.juneau.transform.*; -import org.apache.juneau.xml.annotation.*; /** * Parses text generated by the {@link XmlSerializer} class back into a POJO model. @@ -48,15 +35,12 @@ import org.apache.juneau.xml.annotation.*; * <li>{@link BeanContext} * </ul> */ -@SuppressWarnings({ "rawtypes", "unchecked" }) @Consumes("text/xml,application/xml") public class XmlParser extends ReaderParser { /** Default parser, all default settings.*/ public static final XmlParser DEFAULT = new XmlParser(PropertyStore.create()); - private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, NUMBER=4, BOOLEAN=5, NULL=6; - private final XmlParserContext ctx; @@ -75,456 +59,8 @@ public class XmlParser extends ReaderParser { return new XmlParserBuilder(propertyStore); } - /** - * Workhorse method. - * - * @param session The current parser session. - * @param eType The expected type of object. - * @param currAttr The current bean property name. - * @param r The reader. - * @param outer The outer object. - * @param isRoot If <jk>true</jk>, then we're serializing a root element in the document. - * @param pMeta The bean property metadata. - * @return The parsed object. - * @throws Exception - */ - protected <T> T parseAnything(XmlParserSession session, ClassMeta<T> eType, String currAttr, XMLStreamReader r, - Object outer, boolean isRoot, BeanPropertyMeta pMeta) throws Exception { - - if (eType == null) - eType = (ClassMeta<T>)object(); - PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap(); - ClassMeta<?> sType = eType.getSerializedClassMeta(); - session.setCurrentClass(sType); - - String wrapperAttr = (isRoot && session.isPreserveRootElement()) ? r.getName().getLocalPart() : null; - String typeAttr = r.getAttributeValue(null, session.getBeanTypePropertyName(eType)); - int jsonType = getJsonType(typeAttr); - String elementName = session.getElementName(r); - if (jsonType == 0) { - if (elementName == null || elementName.equals(currAttr)) - jsonType = UNKNOWN; - else { - typeAttr = elementName; - jsonType = getJsonType(elementName); - } - } - - ClassMeta tcm = session.getClassMeta(typeAttr, pMeta, eType); - if (tcm == null && elementName != null && ! elementName.equals(currAttr)) - tcm = session.getClassMeta(elementName, pMeta, eType); - if (tcm != null) - sType = eType = tcm; - - Object o = null; - - if (jsonType == NULL) { - r.nextTag(); // Discard end tag - return null; - } - - if (sType.isObject()) { - if (jsonType == OBJECT) { - ObjectMap m = new ObjectMap(session); - parseIntoMap(session, r, m, string(), object(), pMeta); - if (wrapperAttr != null) - m = new ObjectMap(session).append(wrapperAttr, m); - o = session.cast(m, pMeta, eType); - } else if (jsonType == ARRAY) - o = parseIntoCollection(session, r, new ObjectList(session), null, pMeta); - else if (jsonType == STRING) { - o = session.getElementText(r); - if (sType.isChar()) - o = o.toString().charAt(0); - } - else if (jsonType == NUMBER) - o = parseNumber(session.getElementText(r), null); - else if (jsonType == BOOLEAN) - o = Boolean.parseBoolean(session.getElementText(r)); - else if (jsonType == UNKNOWN) - o = getUnknown(session, r); - } else if (sType.isBoolean()) { - o = Boolean.parseBoolean(session.getElementText(r)); - } else if (sType.isCharSequence()) { - o = session.getElementText(r); - } else if (sType.isChar()) { - String s = session.getElementText(r); - o = s.length() == 0 ? 0 : s.charAt(0); - } else if (sType.isMap()) { - Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(session)); - o = parseIntoMap(session, r, m, sType.getKeyType(), sType.getValueType(), pMeta); - if (wrapperAttr != null) - o = new ObjectMap(session).append(wrapperAttr, m); - } else if (sType.isCollection()) { - Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance(outer) : new ObjectList(session)); - o = parseIntoCollection(session, r, l, sType, pMeta); - } else if (sType.isNumber()) { - o = parseNumber(session.getElementText(r), (Class<? extends Number>)sType.getInnerClass()); - } else if (sType.canCreateNewBean(outer)) { - if (sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED) { - String fieldName = r.getLocalName(); - BeanMap<?> m = session.newBeanMap(outer, sType.getInnerClass()); - BeanPropertyMeta bpm = m.getMeta().getExtendedMeta(XmlBeanMeta.class).getPropertyMeta(fieldName); - ClassMeta<?> cm = m.getMeta().getClassMeta(); - Object value = parseAnything(session, cm, currAttr, r, m.getBean(false), false, null); - setName(cm, value, currAttr); - bpm.set(m, currAttr, value); - o = m.getBean(); - } else { - BeanMap m = session.newBeanMap(outer, sType.getInnerClass()); - o = parseIntoBean(session, r, m).getBean(); - } - } else if (sType.isArray() || sType.isArgs()) { - ArrayList l = (ArrayList)parseIntoCollection(session, r, new ArrayList(), sType, pMeta); - o = session.toArray(sType, l); - } else if (sType.canCreateNewInstanceFromString(outer)) { - o = sType.newInstanceFromString(outer, session.getElementText(r)); - } else if (sType.canCreateNewInstanceFromNumber(outer)) { - o = sType.newInstanceFromNumber(session, outer, parseNumber(session.getElementText(r), sType.getNewInstanceFromNumberClass())); - } else { - throw new ParseException(session, - "Class ''{0}'' could not be instantiated. Reason: ''{1}'', property: ''{2}''", - sType.getInnerClass().getName(), sType.getNotABeanReason(), pMeta == null ? null : pMeta.getName()); - } - - if (transform != null && o != null) - o = transform.unswap(session, o, eType); - - if (outer != null) - setParent(eType, o, outer); - - return (T)o; - } - - private <K,V> Map<K,V> parseIntoMap(XmlParserSession session, XMLStreamReader r, Map<K,V> m, ClassMeta<K> keyType, - ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception { - int depth = 0; - for (int i = 0; i < r.getAttributeCount(); i++) { - String a = r.getAttributeLocalName(i); - // TODO - Need better handling of namespaces here. - if (! (a.equals(session.getBeanTypePropertyName(null)))) { - K key = session.trim(convertAttrToType(session, m, a, keyType)); - V value = session.trim(convertAttrToType(session, m, r.getAttributeValue(i), valueType)); - setName(valueType, value, key); - m.put(key, value); - } - } - do { - int event = r.nextTag(); - String currAttr; - if (event == START_ELEMENT) { - depth++; - currAttr = session.getElementName(r); - K key = convertAttrToType(session, m, currAttr, keyType); - V value = parseAnything(session, valueType, currAttr, r, m, false, pMeta); - setName(valueType, value, currAttr); - if (valueType.isObject() && m.containsKey(key)) { - Object o = m.get(key); - if (o instanceof List) - ((List)o).add(value); - else - m.put(key, (V)new ObjectList(o, value).setBeanSession(session)); - } else { - m.put(key, value); - } - } else if (event == END_ELEMENT) { - depth--; - return m; - } - } while (depth > 0); - return m; - } - - private <E> Collection<E> parseIntoCollection(XmlParserSession session, XMLStreamReader r, Collection<E> l, - ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception { - int depth = 0; - int argIndex = 0; - do { - int event = r.nextTag(); - if (event == START_ELEMENT) { - depth++; - ClassMeta<?> elementType = type == null ? object() : type.isArgs() ? type.getArg(argIndex++) : type.getElementType(); - E value = (E)parseAnything(session, elementType, null, r, l, false, pMeta); - l.add(value); - } else if (event == END_ELEMENT) { - depth--; - return l; - } - } while (depth > 0); - return l; - } - - private static int getJsonType(String s) { - if (s == null) - return UNKNOWN; - char c = s.charAt(0); - switch(c) { - case 'o': return (s.equals("object") ? OBJECT : UNKNOWN); - case 'a': return (s.equals("array") ? ARRAY : UNKNOWN); - case 's': return (s.equals("string") ? STRING : UNKNOWN); - case 'b': return (s.equals("boolean") ? BOOLEAN : UNKNOWN); - case 'n': { - c = s.charAt(2); - switch(c) { - case 'm': return (s.equals("number") ? NUMBER : UNKNOWN); - case 'l': return (s.equals("null") ? NULL : UNKNOWN); - } - //return NUMBER; - } - } - return UNKNOWN; - } - - private <T> BeanMap<T> parseIntoBean(XmlParserSession session, XMLStreamReader r, BeanMap<T> m) throws Exception { - BeanMeta<?> bMeta = m.getMeta(); - XmlBeanMeta xmlMeta = bMeta.getExtendedMeta(XmlBeanMeta.class); - - for (int i = 0; i < r.getAttributeCount(); i++) { - String key = session.getAttributeName(r, i); - String val = r.getAttributeValue(i); - BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key); - if (bpm == null) { - if (xmlMeta.getAttrsProperty() != null) { - xmlMeta.getAttrsProperty().add(m, key, key, val); - } else { - Location l = r.getLocation(); - session.onUnknownProperty(key, m, l.getLineNumber(), l.getColumnNumber()); - } - } else { - bpm.set(m, key, val); - } - } - - BeanPropertyMeta cp = xmlMeta.getContentProperty(); - XmlFormat cpf = xmlMeta.getContentFormat(); - boolean trim = cp == null || ! cpf.isOneOf(MIXED_PWS, TEXT_PWS); - ClassMeta<?> cpcm = (cp == null ? session.object() : cp.getClassMeta()); - StringBuilder sb = null; - BeanRegistry breg = cp == null ? null : cp.getBeanRegistry(); - LinkedList<Object> l = null; - - int depth = 0; - do { - int event = r.next(); - String currAttr; - // We only care about text in MIXED mode. - // Ignore if in ELEMENTS mode. - if (event == CHARACTERS) { - if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) { - if (cpcm.isCollectionOrArray()) { - if (l == null) - l = new LinkedList<Object>(); - l.add(session.getText(r, false)); - } else { - cp.set(m, null, session.getText(r, trim)); - } - } else if (cpf != ELEMENTS) { - String s = session.getText(r, trim); - if (s != null) { - if (sb == null) - sb = session.getStringBuilder(); - sb.append(s); - } - } else { - // Do nothing...we're in ELEMENTS mode. - } - } else if (event == START_ELEMENT) { - if (cp != null && cpf.isOneOf(TEXT, TEXT_PWS)) { - String s = session.parseText(r); - if (s != null) { - if (sb == null) - sb = session.getStringBuilder(); - sb.append(s); - } - depth--; - } else if (cpf == XMLTEXT) { - if (sb == null) - sb = session.getStringBuilder(); - sb.append(session.getElementAsString(r)); - depth++; - } else if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) { - if (session.isWhitespaceElement(r) && (breg == null || ! breg.hasName(r.getLocalName()))) { - if (cpcm.isCollectionOrArray()) { - if (l == null) - l = new LinkedList<Object>(); - l.add(session.parseWhitespaceElement(r)); - } else { - cp.set(m, null, session.parseWhitespaceElement(r)); - } - } else { - if (cpcm.isCollectionOrArray()) { - if (l == null) - l = new LinkedList<Object>(); - l.add(parseAnything(session, cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp)); - } else { - cp.set(m, null, parseAnything(session, cpcm, cp.getName(), r, m.getBean(false), false, cp)); - } - } - } else if (cp != null && cpf == ELEMENTS) { - cp.add(m, null, parseAnything(session, cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp)); - } else { - currAttr = session.getElementName(r); - BeanPropertyMeta pMeta = xmlMeta.getPropertyMeta(currAttr); - if (pMeta == null) { - Location loc = r.getLocation(); - session.onUnknownProperty(currAttr, m, loc.getLineNumber(), loc.getColumnNumber()); - skipCurrentTag(r); - } else { - session.setCurrentProperty(pMeta); - XmlFormat xf = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat(); - if (xf == COLLAPSED) { - ClassMeta<?> et = pMeta.getClassMeta().getElementType(); - Object value = parseAnything(session, et, currAttr, r, m.getBean(false), false, pMeta); - setName(et, value, currAttr); - pMeta.add(m, currAttr, value); - } else if (xf == ATTR) { - pMeta.set(m, currAttr, session.getAttributeValue(r, 0)); - r.nextTag(); - } else { - ClassMeta<?> cm = pMeta.getClassMeta(); - Object value = parseAnything(session, cm, currAttr, r, m.getBean(false), false, pMeta); - setName(cm, value, currAttr); - pMeta.set(m, currAttr, value); - } - session.setCurrentProperty(null); - } - } - } else if (event == END_ELEMENT) { - if (depth > 0) { - if (cpf == XMLTEXT) { - if (sb == null) - sb = session.getStringBuilder(); - sb.append(session.getElementAsString(r)); - } - else - throw new ParseException("End element found where one was not expected. {0}", XmlUtils.toReadableEvent(r)); - } - depth--; - } else { - throw new ParseException("Unexpected event type: {0}", XmlUtils.toReadableEvent(r)); - } - } while (depth >= 0); - - if (sb != null && cp != null) - cp.set(m, null, sb.toString()); - else if (l != null && cp != null) - cp.set(m, null, XmlUtils.collapseTextNodes(l)); - - session.returnStringBuilder(sb); - return m; - } - - private static void skipCurrentTag(XMLStreamReader r) throws XMLStreamException { - int depth = 1; - do { - int event = r.next(); - if (event == START_ELEMENT) - depth++; - else if (event == END_ELEMENT) - depth--; - } while (depth > 0); - } - - private Object getUnknown(XmlParserSession session, XMLStreamReader r) throws Exception { - if (r.getEventType() != XMLStreamConstants.START_ELEMENT) { - throw new XmlParseException(r.getLocation(), "Parser must be on START_ELEMENT to read next text."); - } - ObjectMap m = null; - - // If this element has attributes, then it's always an ObjectMap. - if (r.getAttributeCount() > 0) { - m = new ObjectMap(session); - for (int i = 0; i < r.getAttributeCount(); i++) { - String key = session.getAttributeName(r, i); - String val = r.getAttributeValue(i); - if (! key.equals(session.getBeanTypePropertyName(null))) - m.put(key, val); - } - } - int eventType = r.next(); - StringBuilder sb = session.getStringBuilder(); - while (eventType != XMLStreamConstants.END_ELEMENT) { - if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) { - sb.append(r.getText()); - } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) { - // skipping - } else if (eventType == XMLStreamConstants.END_DOCUMENT) { - throw new XmlParseException(r.getLocation(), "Unexpected end of document when reading element text content"); - } else if (eventType == XMLStreamConstants.START_ELEMENT) { - // Oops...this has an element in it. - // Parse it as a map. - if (m == null) - m = new ObjectMap(session); - int depth = 0; - do { - int event = (eventType == -1 ? r.nextTag() : eventType); - String currAttr; - if (event == START_ELEMENT) { - depth++; - currAttr = session.getElementName(r); - String key = convertAttrToType(session, null, currAttr, string()); - Object value = parseAnything(session, object(), currAttr, r, null, false, null); - if (m.containsKey(key)) { - Object o = m.get(key); - if (o instanceof ObjectList) - ((ObjectList)o).add(value); - else - m.put(key, new ObjectList(o, value).setBeanSession(session)); - } else { - m.put(key, value); - } - - } else if (event == END_ELEMENT) { - depth--; - break; - } - eventType = -1; - } while (depth > 0); - break; - } else { - throw new XmlParseException(r.getLocation(), "Unexpected event type ''{0}''", eventType); - } - eventType = r.next(); - } - String s = sb.toString(); - session.returnStringBuilder(sb); - s = session.decodeString(s); - if (m != null) { - if (! s.isEmpty()) - m.put("contents", s); - return m; - } - return s; - } - - - //-------------------------------------------------------------------------------- - // Entry point methods - //-------------------------------------------------------------------------------- - @Override /* Parser */ - public XmlParserSession createSession(Object input, ObjectMap op, Method javaMethod, Object outer, Locale locale, - TimeZone timeZone, MediaType mediaType) { - return new XmlParserSession(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType); - } - - @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - XmlParserSession s = (XmlParserSession)session; - return parseAnything(s, type, null, s.getXmlStreamReader(), s.getOuter(), true, null); - } - - @Override /* ReaderParser */ - protected <K,V> Map<K,V> doParseIntoMap(ParserSession session, Map<K,V> m, Type keyType, Type valueType) throws Exception { - XmlParserSession s = (XmlParserSession)session; - ClassMeta cm = session.getClassMeta(m.getClass(), keyType, valueType); - return parseIntoMap(s, m, cm.getKeyType(), cm.getValueType()); - } - - @Override /* ReaderParser */ - protected <E> Collection<E> doParseIntoCollection(ParserSession session, Collection<E> c, Type elementType) throws Exception { - XmlParserSession s = (XmlParserSession)session; - ClassMeta cm = session.getClassMeta(c.getClass(), elementType); - return parseIntoCollection(s,c, cm.getElementType()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new XmlParserSession(ctx, args); } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java index 3dd0d13..1f41d56 100644 --- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlParserSession.java @@ -14,9 +14,9 @@ package org.apache.juneau.xml; import static javax.xml.stream.XMLStreamConstants.*; import static org.apache.juneau.xml.XmlParserContext.*; -import static org.apache.juneau.internal.IOUtils.*; +import static org.apache.juneau.xml.annotation.XmlFormat.*; +import static org.apache.juneau.internal.StringUtils.*; -import java.io.*; import java.lang.reflect.*; import java.util.*; @@ -24,17 +24,22 @@ import javax.xml.stream.*; import javax.xml.stream.util.*; import org.apache.juneau.*; -import org.apache.juneau.http.*; import org.apache.juneau.parser.*; +import org.apache.juneau.transform.*; import org.apache.juneau.xml.annotation.*; /** * Session object that lives for the duration of a single use of {@link XmlParser}. * * <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 against multiple inputs. */ -public class XmlParserSession extends ParserSession { +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class XmlParserSession extends ReaderParserSession { + + private static final int UNKNOWN=0, OBJECT=1, ARRAY=2, STRING=3, NUMBER=4, BOOLEAN=5, NULL=6; + private final boolean validating, @@ -42,8 +47,7 @@ public class XmlParserSession extends ParserSession { private final XMLReporter reporter; private final XMLResolver resolver; private final XMLEventAllocator eventAllocator; - private XMLStreamReader xmlStreamReader; - private final StringBuilder sb = new StringBuilder(); // Reusable string builder used in this class. + private final StringBuilder rsb = new StringBuilder(); // Reusable string builder used in this class. /** * Create a new session using properties specified in the context. @@ -51,89 +55,36 @@ public class XmlParserSession extends ParserSession { * @param ctx * The context creating this session object. * The context contains all the configuration settings for this object. - * @param input - * The input. - * Can be any of the following types: - * <ul> - * <li><jk>null</jk> - * <li>{@link Reader} - * <li>{@link CharSequence} - * <li>{@link InputStream} containing UTF-8 encoded text. - * <li>{@link File} containing system encoded text. - * </ul> - * @param op - * The override properties. - * These override any context properties defined in the context. - * @param javaMethod The java method that called this parser, usually the method in a REST servlet. - * @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>). + * @param args + * Runtime session arguments. */ - public XmlParserSession(XmlParserContext ctx, ObjectMap op, Object input, Method javaMethod, Object outer, - Locale locale, TimeZone timeZone, MediaType mediaType) { - super(ctx, op, input, javaMethod, outer, locale, timeZone, mediaType); - if (op == null || op.isEmpty()) { + protected XmlParserSession(XmlParserContext ctx, ParserSessionArgs args) { + super(ctx, args); + ObjectMap p = getProperties(); + if (p.isEmpty()) { validating = ctx.validating; reporter = ctx.reporter; resolver = ctx.resolver; eventAllocator = ctx.eventAllocator; preserveRootElement = ctx.preserveRootElement; } else { - validating = op.getBoolean(XML_validating, ctx.validating); - reporter = (XMLReporter)op.get(XML_reporter, ctx.reporter); - resolver = (XMLResolver)op.get(XML_resolver, ctx.resolver); - eventAllocator = (XMLEventAllocator)op.get(XML_eventAllocator, ctx.eventAllocator); - preserveRootElement = op.getBoolean(XML_preserveRootElement, ctx.preserveRootElement); + validating = p.getBoolean(XML_validating, ctx.validating); + reporter = (XMLReporter)p.get(XML_reporter, ctx.reporter); + resolver = (XMLResolver)p.get(XML_resolver, ctx.resolver); + eventAllocator = (XMLEventAllocator)p.get(XML_eventAllocator, ctx.eventAllocator); + preserveRootElement = p.getBoolean(XML_preserveRootElement, ctx.preserveRootElement); } } /** - * Returns the {@link XmlParserContext#XML_preserveRootElement} setting value for this session. - * - * @return The {@link XmlParserContext#XML_preserveRootElement} setting value for this session. - */ - public final boolean isPreserveRootElement() { - return preserveRootElement; - } - - /** * Wrap the specified reader in a STAX reader based on settings in this context. * + * @param pipe The parser input. * @return The new STAX reader. * @throws Exception If problem occurred trying to create reader. */ - public final XMLStreamReader getXmlStreamReader() throws Exception { - if (xmlStreamReader != null) - return xmlStreamReader; - - try { - Reader r = getBufferedReader(getReader()); - XMLInputFactory factory = XMLInputFactory.newInstance(); - factory.setProperty(XMLInputFactory.IS_VALIDATING, validating); - factory.setProperty(XMLInputFactory.IS_COALESCING, true); - factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true); // This usually has no effect anyway. - if (factory.isPropertySupported(XMLInputFactory.REPORTER) && reporter != null) - factory.setProperty(XMLInputFactory.REPORTER, reporter); - if (factory.isPropertySupported(XMLInputFactory.RESOLVER) && resolver != null) - factory.setProperty(XMLInputFactory.RESOLVER, resolver); - if (factory.isPropertySupported(XMLInputFactory.ALLOCATOR) && eventAllocator != null) - factory.setProperty(XMLInputFactory.ALLOCATOR, eventAllocator); - xmlStreamReader = factory.createXMLStreamReader(r); - xmlStreamReader.nextTag(); - } catch (Error e) { - close(); - throw new ParseException(e.getLocalizedMessage()); - } catch (XMLStreamException e) { - close(); - throw new ParseException(e); - } - - return xmlStreamReader; + protected final XmlReader getXmlReader(ParserPipe pipe) throws Exception { + return new XmlReader(pipe, validating, reporter, resolver, eventAllocator); } /** @@ -145,57 +96,37 @@ public class XmlParserSession extends ParserSession { * @param s The string to be decoded. * @return The decoded string. */ - public final String decodeString(String s) { + protected final String decodeString(String s) { if (s == null) return null; - sb.setLength(0); - s = XmlUtils.decode(s, sb); + rsb.setLength(0); + s = XmlUtils.decode(s, rsb); if (isTrimStrings()) s = s.trim(); return s; } - /** + /* * Returns the name of the current XML element. - * - * <p> * Any <js>'_x####_'</js> sequences in the string will be decoded. - * - * @param r The reader to read from. - * @return The decoded element name. - * @throws XMLStreamException */ - public final String getElementName(XMLStreamReader r) throws XMLStreamException { + private String getElementName(XmlReader r) { return decodeString(r.getLocalName()); } - /** + /* * Returns the name of the specified attribute on the current XML element. - * - * <p> * Any <js>'_x####_'</js> sequences in the string will be decoded. - * - * @param r The reader to read from. - * @param i The attribute index. - * @return The decoded attribute name. - * @throws XMLStreamException */ - public final String getAttributeName(XMLStreamReader r, int i) throws XMLStreamException { + private String getAttributeName(XmlReader r, int i) { return decodeString(r.getAttributeLocalName(i)); } - /** + /* * Returns the value of the specified attribute on the current XML element. - * - * <p> * Any <js>'_x####_'</js> sequences in the string will be decoded. - * - * @param r The reader to read from. - * @param i The attribute index. - * @return The decoded attribute value. - * @throws XMLStreamException */ - public final String getAttributeValue(XMLStreamReader r, int i) throws XMLStreamException { + private String getAttributeValue(XmlReader r, int i) { return decodeString(r.getAttributeValue(i)); } @@ -212,28 +143,16 @@ public class XmlParserSession extends ParserSession { * @return The decoded text. <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>. * @throws Exception */ - public String getElementText(XMLStreamReader r) throws Exception { - String s = r.getElementText().trim(); - return decodeString(s); + protected String getElementText(XmlReader r) throws Exception { + return decodeString(r.getElementText().trim()); } - /** + /* * Returns the content of the current CHARACTERS node. - * - * <p> * Any <js>'_x####_'</js> sequences in the string will be decoded. - * - * <p> * Leading and trailing whitespace (unencoded) will be trimmed from the result. - * - * @param r The reader to read the element text from. - * @param trim - * If <jk>true</jk>, trim the contents of the text node BEFORE decoding escape sequences. - * Typically <jk>true</jk> for {@link XmlFormat#MIXED_PWS} and {@link XmlFormat#TEXT_PWS}. - * @return The decoded text. <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>. - * @throws XMLStreamException */ - public String getText(XMLStreamReader r, boolean trim) throws XMLStreamException { + private String getText(XmlReader r, boolean trim) { String s = r.getText(); if (trim) s = s.trim(); @@ -242,52 +161,41 @@ public class XmlParserSession extends ParserSession { return decodeString(s); } - /** + /* * Shortcut for calling <code>getText(r, <jk>true</jk>);</code>. - * - * @param r The reader to read the element text from. - * @return The decoded text. <jk>null</jk> if the text consists of the sequence <js>'_x0000_'</js>. - * @throws XMLStreamException */ - public String getText(XMLStreamReader r) throws XMLStreamException { + private String getText(XmlReader r) { return getText(r, true); } - /** + /* * Takes the element being read from the XML stream reader and reconstructs it as XML. - * - * <p> * Used when reconstructing bean properties of type {@link XmlFormat#XMLTEXT}. - * - * @param r The XML stream reader to read the current event from. - * @return The event as XML. - * @throws RuntimeException if the event is not a start or end tag. */ - public final String getElementAsString(XMLStreamReader r) { + private String getElementAsString(XmlReader r) { int t = r.getEventType(); if (t > 2) throw new FormattedRuntimeException("Invalid event type on stream reader for elementToString() method: ''{0}''", XmlUtils.toReadableEvent(r)); - sb.setLength(0); - sb.append("<").append(t == 1 ? "" : "/").append(r.getLocalName()); + rsb.setLength(0); + rsb.append("<").append(t == 1 ? "" : "/").append(r.getLocalName()); if (t == 1) for (int i = 0; i < r.getAttributeCount(); i++) - sb.append(' ').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\''); - sb.append('>'); - return sb.toString(); + rsb.append(' ').append(r.getAttributeName(i)).append('=').append('\'').append(r.getAttributeValue(i)).append('\''); + rsb.append('>'); + return rsb.toString(); } /** * Parses the current element as text. * - * <p> - * Note that this is different than {@link #getText(XMLStreamReader)} since it assumes that we're pointing to a - * whitespace element. - * * @param r * @return The parsed text. * @throws Exception */ - public String parseText(XMLStreamReader r) throws Exception { + protected String parseText(XmlReader r) throws Exception { + // Note that this is different than {@link #getText(XmlReader)} since it assumes that we're pointing to a + // whitespace element. + StringBuilder sb2 = getStringBuilder(); int depth = 0; @@ -321,7 +229,7 @@ public class XmlParserSession extends ParserSession { * @param r The XML stream reader to read the current event from. * @return <jk>true</jk> if the current element is a whitespace element. */ - public boolean isWhitespaceElement(XMLStreamReader r) { + protected boolean isWhitespaceElement(XmlReader r) { return false; } @@ -337,24 +245,449 @@ public class XmlParserSession extends ParserSession { * @throws XMLStreamException * @throws Exception */ - public String parseWhitespaceElement(XMLStreamReader r) throws Exception { + protected String parseWhitespaceElement(XmlReader r) throws Exception { return null; } + @Override /* ParserSession */ + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return parseAnything(type, null, getXmlReader(pipe), getOuter(), true, null); + } + + @Override /* ReaderParserSession */ + protected <K,V> Map<K,V> doParseIntoMap(ParserPipe pipe, Map<K,V> m, Type keyType, Type valueType) throws Exception { + ClassMeta cm = getClassMeta(m.getClass(), keyType, valueType); + return parseIntoMap(pipe, m, cm.getKeyType(), cm.getValueType()); + } + + @Override /* ReaderParserSession */ + protected <E> Collection<E> doParseIntoCollection(ParserPipe pipe, Collection<E> c, Type elementType) throws Exception { + ClassMeta cm = getClassMeta(c.getClass(), elementType); + return parseIntoCollection(pipe, c, cm.getElementType()); + } + /** - * Silently closes the XML stream. + * Workhorse method. + * + * @param eType The expected type of object. + * @param currAttr The current bean property name. + * @param r The reader. + * @param outer The outer object. + * @param isRoot If <jk>true</jk>, then we're serializing a root element in the document. + * @param pMeta The bean property metadata. + * @return The parsed object. + * @throws Exception */ - @Override /* ParserContext */ - public boolean close() { - if (super.close()) { - try { - if (xmlStreamReader != null) - xmlStreamReader.close(); - } catch (XMLStreamException e) { - // Ignore. + protected <T> T parseAnything(ClassMeta<T> eType, String currAttr, XmlReader r, + Object outer, boolean isRoot, BeanPropertyMeta pMeta) throws Exception { + + if (eType == null) + eType = (ClassMeta<T>)object(); + PojoSwap<T,Object> transform = (PojoSwap<T,Object>)eType.getPojoSwap(); + ClassMeta<?> sType = eType.getSerializedClassMeta(); + setCurrentClass(sType); + + String wrapperAttr = (isRoot && preserveRootElement) ? r.getName().getLocalPart() : null; + String typeAttr = r.getAttributeValue(null, getBeanTypePropertyName(eType)); + int jsonType = getJsonType(typeAttr); + String elementName = getElementName(r); + if (jsonType == 0) { + if (elementName == null || elementName.equals(currAttr)) + jsonType = UNKNOWN; + else { + typeAttr = elementName; + jsonType = getJsonType(elementName); } - return true; } - return false; + + ClassMeta tcm = getClassMeta(typeAttr, pMeta, eType); + if (tcm == null && elementName != null && ! elementName.equals(currAttr)) + tcm = getClassMeta(elementName, pMeta, eType); + if (tcm != null) + sType = eType = tcm; + + Object o = null; + + if (jsonType == NULL) { + r.nextTag(); // Discard end tag + return null; + } + + if (sType.isObject()) { + if (jsonType == OBJECT) { + ObjectMap m = new ObjectMap(this); + parseIntoMap(r, m, string(), object(), pMeta); + if (wrapperAttr != null) + m = new ObjectMap(this).append(wrapperAttr, m); + o = cast(m, pMeta, eType); + } else if (jsonType == ARRAY) + o = parseIntoCollection(r, new ObjectList(this), null, pMeta); + else if (jsonType == STRING) { + o = getElementText(r); + if (sType.isChar()) + o = o.toString().charAt(0); + } + else if (jsonType == NUMBER) + o = parseNumber(getElementText(r), null); + else if (jsonType == BOOLEAN) + o = Boolean.parseBoolean(getElementText(r)); + else if (jsonType == UNKNOWN) + o = getUnknown(r); + } else if (sType.isBoolean()) { + o = Boolean.parseBoolean(getElementText(r)); + } else if (sType.isCharSequence()) { + o = getElementText(r); + } else if (sType.isChar()) { + String s = getElementText(r); + o = s.length() == 0 ? 0 : s.charAt(0); + } else if (sType.isMap()) { + Map m = (sType.canCreateNewInstance(outer) ? (Map)sType.newInstance(outer) : new ObjectMap(this)); + o = parseIntoMap(r, m, sType.getKeyType(), sType.getValueType(), pMeta); + if (wrapperAttr != null) + o = new ObjectMap(this).append(wrapperAttr, m); + } else if (sType.isCollection()) { + Collection l = (sType.canCreateNewInstance(outer) ? (Collection)sType.newInstance(outer) : new ObjectList(this)); + o = parseIntoCollection(r, l, sType, pMeta); + } else if (sType.isNumber()) { + o = parseNumber(getElementText(r), (Class<? extends Number>)sType.getInnerClass()); + } else if (sType.canCreateNewBean(outer)) { + if (sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED) { + String fieldName = r.getLocalName(); + BeanMap<?> m = newBeanMap(outer, sType.getInnerClass()); + BeanPropertyMeta bpm = m.getMeta().getExtendedMeta(XmlBeanMeta.class).getPropertyMeta(fieldName); + ClassMeta<?> cm = m.getMeta().getClassMeta(); + Object value = parseAnything(cm, currAttr, r, m.getBean(false), false, null); + setName(cm, value, currAttr); + bpm.set(m, currAttr, value); + o = m.getBean(); + } else { + BeanMap m = newBeanMap(outer, sType.getInnerClass()); + o = parseIntoBean(r, m).getBean(); + } + } else if (sType.isArray() || sType.isArgs()) { + ArrayList l = (ArrayList)parseIntoCollection(r, new ArrayList(), sType, pMeta); + o = toArray(sType, l); + } else if (sType.canCreateNewInstanceFromString(outer)) { + o = sType.newInstanceFromString(outer, getElementText(r)); + } else if (sType.canCreateNewInstanceFromNumber(outer)) { + o = sType.newInstanceFromNumber(this, outer, parseNumber(getElementText(r), sType.getNewInstanceFromNumberClass())); + } else { + throw new ParseException(loc(r), + "Class ''{0}'' could not be instantiated. Reason: ''{1}'', property: ''{2}''", + sType.getInnerClass().getName(), sType.getNotABeanReason(), pMeta == null ? null : pMeta.getName()); + } + + if (transform != null && o != null) + o = transform.unswap(this, o, eType); + + if (outer != null) + setParent(eType, o, outer); + + return (T)o; + } + + private <K,V> Map<K,V> parseIntoMap(XmlReader r, Map<K,V> m, ClassMeta<K> keyType, + ClassMeta<V> valueType, BeanPropertyMeta pMeta) throws Exception { + int depth = 0; + for (int i = 0; i < r.getAttributeCount(); i++) { + String a = r.getAttributeLocalName(i); + // TODO - Need better handling of namespaces here. + if (! (a.equals(getBeanTypePropertyName(null)))) { + K key = trim(convertAttrToType(m, a, keyType)); + V value = trim(convertAttrToType(m, r.getAttributeValue(i), valueType)); + setName(valueType, value, key); + m.put(key, value); + } + } + do { + int event = r.nextTag(); + String currAttr; + if (event == START_ELEMENT) { + depth++; + currAttr = getElementName(r); + K key = convertAttrToType(m, currAttr, keyType); + V value = parseAnything(valueType, currAttr, r, m, false, pMeta); + setName(valueType, value, currAttr); + if (valueType.isObject() && m.containsKey(key)) { + Object o = m.get(key); + if (o instanceof List) + ((List)o).add(value); + else + m.put(key, (V)new ObjectList(o, value).setBeanSession(this)); + } else { + m.put(key, value); + } + } else if (event == END_ELEMENT) { + depth--; + return m; + } + } while (depth > 0); + return m; + } + + private <E> Collection<E> parseIntoCollection(XmlReader r, Collection<E> l, + ClassMeta<?> type, BeanPropertyMeta pMeta) throws Exception { + int depth = 0; + int argIndex = 0; + do { + int event = r.nextTag(); + if (event == START_ELEMENT) { + depth++; + ClassMeta<?> elementType = type == null ? object() : type.isArgs() ? type.getArg(argIndex++) : type.getElementType(); + E value = (E)parseAnything(elementType, null, r, l, false, pMeta); + l.add(value); + } else if (event == END_ELEMENT) { + depth--; + return l; + } + } while (depth > 0); + return l; + } + + private static int getJsonType(String s) { + if (s == null) + return UNKNOWN; + char c = s.charAt(0); + switch(c) { + case 'o': return (s.equals("object") ? OBJECT : UNKNOWN); + case 'a': return (s.equals("array") ? ARRAY : UNKNOWN); + case 's': return (s.equals("string") ? STRING : UNKNOWN); + case 'b': return (s.equals("boolean") ? BOOLEAN : UNKNOWN); + case 'n': { + c = s.charAt(2); + switch(c) { + case 'm': return (s.equals("number") ? NUMBER : UNKNOWN); + case 'l': return (s.equals("null") ? NULL : UNKNOWN); + } + //return NUMBER; + } + } + return UNKNOWN; + } + + private <T> BeanMap<T> parseIntoBean(XmlReader r, BeanMap<T> m) throws Exception { + BeanMeta<?> bMeta = m.getMeta(); + XmlBeanMeta xmlMeta = bMeta.getExtendedMeta(XmlBeanMeta.class); + + for (int i = 0; i < r.getAttributeCount(); i++) { + String key = getAttributeName(r, i); + String val = r.getAttributeValue(i); + BeanPropertyMeta bpm = xmlMeta.getPropertyMeta(key); + if (bpm == null) { + if (xmlMeta.getAttrsProperty() != null) { + xmlMeta.getAttrsProperty().add(m, key, key, val); + } else { + Location l = r.getLocation(); + onUnknownProperty(r.getPipe(), key, m, l.getLineNumber(), l.getColumnNumber()); + } + } else { + bpm.set(m, key, val); + } + } + + BeanPropertyMeta cp = xmlMeta.getContentProperty(); + XmlFormat cpf = xmlMeta.getContentFormat(); + boolean trim = cp == null || ! cpf.isOneOf(MIXED_PWS, TEXT_PWS); + ClassMeta<?> cpcm = (cp == null ? object() : cp.getClassMeta()); + StringBuilder sb = null; + BeanRegistry breg = cp == null ? null : cp.getBeanRegistry(); + LinkedList<Object> l = null; + + int depth = 0; + do { + int event = r.next(); + String currAttr; + // We only care about text in MIXED mode. + // Ignore if in ELEMENTS mode. + if (event == CHARACTERS) { + if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) { + if (cpcm.isCollectionOrArray()) { + if (l == null) + l = new LinkedList<Object>(); + l.add(getText(r, false)); + } else { + cp.set(m, null, getText(r, trim)); + } + } else if (cpf != ELEMENTS) { + String s = getText(r, trim); + if (s != null) { + if (sb == null) + sb = getStringBuilder(); + sb.append(s); + } + } else { + // Do nothing...we're in ELEMENTS mode. + } + } else if (event == START_ELEMENT) { + if (cp != null && cpf.isOneOf(TEXT, TEXT_PWS)) { + String s = parseText(r); + if (s != null) { + if (sb == null) + sb = getStringBuilder(); + sb.append(s); + } + depth--; + } else if (cpf == XMLTEXT) { + if (sb == null) + sb = getStringBuilder(); + sb.append(getElementAsString(r)); + depth++; + } else if (cp != null && cpf.isOneOf(MIXED, MIXED_PWS)) { + if (isWhitespaceElement(r) && (breg == null || ! breg.hasName(r.getLocalName()))) { + if (cpcm.isCollectionOrArray()) { + if (l == null) + l = new LinkedList<Object>(); + l.add(parseWhitespaceElement(r)); + } else { + cp.set(m, null, parseWhitespaceElement(r)); + } + } else { + if (cpcm.isCollectionOrArray()) { + if (l == null) + l = new LinkedList<Object>(); + l.add(parseAnything(cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp)); + } else { + cp.set(m, null, parseAnything(cpcm, cp.getName(), r, m.getBean(false), false, cp)); + } + } + } else if (cp != null && cpf == ELEMENTS) { + cp.add(m, null, parseAnything(cpcm.getElementType(), cp.getName(), r, m.getBean(false), false, cp)); + } else { + currAttr = getElementName(r); + BeanPropertyMeta pMeta = xmlMeta.getPropertyMeta(currAttr); + if (pMeta == null) { + Location loc = r.getLocation(); + onUnknownProperty(r.getPipe(), currAttr, m, loc.getLineNumber(), loc.getColumnNumber()); + skipCurrentTag(r); + } else { + setCurrentProperty(pMeta); + XmlFormat xf = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat(); + if (xf == COLLAPSED) { + ClassMeta<?> et = pMeta.getClassMeta().getElementType(); + Object value = parseAnything(et, currAttr, r, m.getBean(false), false, pMeta); + setName(et, value, currAttr); + pMeta.add(m, currAttr, value); + } else if (xf == ATTR) { + pMeta.set(m, currAttr, getAttributeValue(r, 0)); + r.nextTag(); + } else { + ClassMeta<?> cm = pMeta.getClassMeta(); + Object value = parseAnything(cm, currAttr, r, m.getBean(false), false, pMeta); + setName(cm, value, currAttr); + pMeta.set(m, currAttr, value); + } + setCurrentProperty(null); + } + } + } else if (event == END_ELEMENT) { + if (depth > 0) { + if (cpf == XMLTEXT) { + if (sb == null) + sb = getStringBuilder(); + sb.append(getElementAsString(r)); + } + else + throw new ParseException("End element found where one was not expected. {0}", XmlUtils.toReadableEvent(r)); + } + depth--; + } else { + throw new ParseException("Unexpected event type: {0}", XmlUtils.toReadableEvent(r)); + } + } while (depth >= 0); + + if (sb != null && cp != null) + cp.set(m, null, sb.toString()); + else if (l != null && cp != null) + cp.set(m, null, XmlUtils.collapseTextNodes(l)); + + returnStringBuilder(sb); + return m; + } + + private static void skipCurrentTag(XmlReader r) throws XMLStreamException { + int depth = 1; + do { + int event = r.next(); + if (event == START_ELEMENT) + depth++; + else if (event == END_ELEMENT) + depth--; + } while (depth > 0); + } + + private Object getUnknown(XmlReader r) throws Exception { + if (r.getEventType() != START_ELEMENT) { + throw new XmlParseException(r.getLocation(), "Parser must be on START_ELEMENT to read next text."); + } + ObjectMap m = null; + + // If this element has attributes, then it's always an ObjectMap. + if (r.getAttributeCount() > 0) { + m = new ObjectMap(this); + for (int i = 0; i < r.getAttributeCount(); i++) { + String key = getAttributeName(r, i); + String val = r.getAttributeValue(i); + if (! key.equals(getBeanTypePropertyName(null))) + m.put(key, val); + } + } + int eventType = r.next(); + StringBuilder sb = getStringBuilder(); + while (eventType != END_ELEMENT) { + if (eventType == CHARACTERS || eventType == CDATA || eventType == SPACE || eventType == ENTITY_REFERENCE) { + sb.append(r.getText()); + } else if (eventType == PROCESSING_INSTRUCTION || eventType == COMMENT) { + // skipping + } else if (eventType == END_DOCUMENT) { + throw new XmlParseException(r.getLocation(), "Unexpected end of document when reading element text content"); + } else if (eventType == START_ELEMENT) { + // Oops...this has an element in it. + // Parse it as a map. + if (m == null) + m = new ObjectMap(this); + int depth = 0; + do { + int event = (eventType == -1 ? r.nextTag() : eventType); + String currAttr; + if (event == START_ELEMENT) { + depth++; + currAttr = getElementName(r); + String key = convertAttrToType(null, currAttr, string()); + Object value = parseAnything(object(), currAttr, r, null, false, null); + if (m.containsKey(key)) { + Object o = m.get(key); + if (o instanceof ObjectList) + ((ObjectList)o).add(value); + else + m.put(key, new ObjectList(o, value).setBeanSession(this)); + } else { + m.put(key, value); + } + + } else if (event == END_ELEMENT) { + depth--; + break; + } + eventType = -1; + } while (depth > 0); + break; + } else { + throw new XmlParseException(r.getLocation(), "Unexpected event type ''{0}''", eventType); + } + eventType = r.next(); + } + String s = sb.toString(); + returnStringBuilder(sb); + s = decodeString(s); + if (m != null) { + if (! s.isEmpty()) + m.put("contents", s); + return m; + } + return s; + } + + private ObjectMap loc(XmlReader r) { + return getLastLocation().append("line", r.getLocation().getLineNumber()).append("column", r.getLocation().getColumnNumber()); } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java new file mode 100644 index 0000000..50c0e5e --- /dev/null +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlReader.java @@ -0,0 +1,301 @@ +// *************************************************************************************************************************** +// * 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.xml; + +import java.io.*; + +import javax.xml.namespace.*; +import javax.xml.stream.*; +import javax.xml.stream.util.*; + +import org.apache.juneau.parser.*; + +/** + * Wrapper class around a {@link XMLStreamReader}. + * + * <p> + * The purpose is to encapsulate the reader with the {@link ParserPipe} object so that it can be retrieved for + * debugging purposes. + */ +public final class XmlReader implements XMLStreamReader { + + private final ParserPipe pipe; + private final XMLStreamReader sr; + + /** + * Constructor. + * + * @param pipe The parser input. + * @param validating The value for the {@link XMLInputFactory#IS_VALIDATING} setting. + * @param reporter The value for the {@link XMLInputFactory#REPORTER} setting. + * @param resolver The value for the {@link XMLInputFactory#RESOLVER} setting. + * @param eventAllocator The value for the {@link XMLInputFactory#ALLOCATOR} setting. + * @throws Exception + */ + protected XmlReader(ParserPipe pipe, boolean validating, XMLReporter reporter, XMLResolver resolver, XMLEventAllocator eventAllocator) throws Exception { + this.pipe = pipe; + try { + Reader r = pipe.getBufferedReader(); + XMLInputFactory factory = XMLInputFactory.newInstance(); + factory.setProperty(XMLInputFactory.IS_VALIDATING, validating); + factory.setProperty(XMLInputFactory.IS_COALESCING, true); + factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, true); // This usually has no effect anyway. + if (factory.isPropertySupported(XMLInputFactory.REPORTER) && reporter != null) + factory.setProperty(XMLInputFactory.REPORTER, reporter); + if (factory.isPropertySupported(XMLInputFactory.RESOLVER) && resolver != null) + factory.setProperty(XMLInputFactory.RESOLVER, resolver); + if (factory.isPropertySupported(XMLInputFactory.ALLOCATOR) && eventAllocator != null) + factory.setProperty(XMLInputFactory.ALLOCATOR, eventAllocator); + sr = factory.createXMLStreamReader(r); + sr.nextTag(); + } catch (Error e) { + throw new ParseException(e.getLocalizedMessage()); + } catch (XMLStreamException e) { + throw new ParseException(e); + } + } + + /** + * Returns the pipe passed into the constructor. + * + * @return The pipe passed into the constructor. + */ + public ParserPipe getPipe() { + return pipe; + } + + @Override /* XMLStreamReader */ + public void close() throws XMLStreamException { + sr.close(); + } + + @Override /* XMLStreamReader */ + public int getAttributeCount() { + return sr.getAttributeCount(); + } + + @Override /* XMLStreamReader */ + public String getAttributeLocalName(int index) { + return sr.getAttributeLocalName(index); + } + + @Override /* XMLStreamReader */ + public QName getAttributeName(int index) { + return sr.getAttributeName(index); + } + + @Override /* XMLStreamReader */ + public String getAttributeNamespace(int index) { + return sr.getAttributeNamespace(index); + } + + @Override /* XMLStreamReader */ + public String getAttributePrefix(int index) { + return sr.getAttributePrefix(index); + } + + @Override /* XMLStreamReader */ + public String getAttributeType(int index) { + return sr.getAttributeType(index); + } + + @Override /* XMLStreamReader */ + public String getAttributeValue(int index) { + return sr.getAttributeValue(index); + } + + @Override /* XMLStreamReader */ + public String getAttributeValue(String namespaceURI, String localName) { + return sr.getAttributeValue(namespaceURI, localName); + } + + @Override /* XMLStreamReader */ + public String getCharacterEncodingScheme() { + return sr.getCharacterEncodingScheme(); + } + + @Override /* XMLStreamReader */ + public String getElementText() throws XMLStreamException { + return sr.getElementText(); + } + + @Override /* XMLStreamReader */ + public String getEncoding() { + return sr.getEncoding(); + } + + @Override /* XMLStreamReader */ + public int getEventType() { + return sr.getEventType(); + } + + @Override /* XMLStreamReader */ + public String getLocalName() { + return sr.getLocalName(); + } + + @Override /* XMLStreamReader */ + public Location getLocation() { + return sr.getLocation(); + } + + @Override /* XMLStreamReader */ + public QName getName() { + return sr.getName(); + } + + @Override /* XMLStreamReader */ + public NamespaceContext getNamespaceContext() { + return sr.getNamespaceContext(); + } + + @Override /* XMLStreamReader */ + public int getNamespaceCount() { + return sr.getNamespaceCount(); + } + + @Override /* XMLStreamReader */ + public String getNamespacePrefix(int index) { + return sr.getNamespacePrefix(index); + } + + @Override /* XMLStreamReader */ + public String getNamespaceURI() { + return sr.getNamespaceURI(); + } + + @Override /* XMLStreamReader */ + public String getNamespaceURI(String prefix) { + return sr.getNamespaceURI(prefix); + } + + @Override /* XMLStreamReader */ + public String getNamespaceURI(int index) { + return sr.getNamespaceURI(index); + } + + @Override /* XMLStreamReader */ + public String getPIData() { + return sr.getPIData(); + } + + @Override /* XMLStreamReader */ + public String getPITarget() { + return sr.getPITarget(); + } + + @Override /* XMLStreamReader */ + public String getPrefix() { + return sr.getPrefix(); + } + + @Override /* XMLStreamReader */ + public Object getProperty(String name) throws IllegalArgumentException { + return sr.getProperty(name); + } + + @Override /* XMLStreamReader */ + public String getText() { + return sr.getText(); + } + + @Override /* XMLStreamReader */ + public char[] getTextCharacters() { + return sr.getTextCharacters(); + } + + @Override /* XMLStreamReader */ + public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws XMLStreamException { + return sr.getTextCharacters(sourceStart, target, targetStart, length); + } + + @Override /* XMLStreamReader */ + public int getTextLength() { + return sr.getTextLength(); + } + + @Override /* XMLStreamReader */ + public int getTextStart() { + return sr.getTextStart(); + } + + @Override /* XMLStreamReader */ + public String getVersion() { + return sr.getVersion(); + } + + @Override /* XMLStreamReader */ + public boolean hasName() { + return sr.hasName(); + } + + @Override /* XMLStreamReader */ + public boolean hasNext() throws XMLStreamException { + return sr.hasNext(); + } + + @Override /* XMLStreamReader */ + public boolean hasText() { + return sr.hasText(); + } + + @Override /* XMLStreamReader */ + public boolean isAttributeSpecified(int index) { + return sr.isAttributeSpecified(index); + } + + @Override /* XMLStreamReader */ + public boolean isCharacters() { + return sr.isCharacters(); + } + + @Override /* XMLStreamReader */ + public boolean isEndElement() { + return sr.isEndElement(); + } + + @Override /* XMLStreamReader */ + public boolean isStandalone() { + return sr.isStandalone(); + } + + @Override /* XMLStreamReader */ + public boolean isStartElement() { + return sr.isStartElement(); + } + + @Override /* XMLStreamReader */ + public boolean isWhiteSpace() { + return sr.isWhiteSpace(); + } + + @Override /* XMLStreamReader */ + public int next() throws XMLStreamException { + return sr.next(); + } + + @Override /* XMLStreamReader */ + public int nextTag() throws XMLStreamException { + return sr.nextTag(); + } + + @Override /* XMLStreamReader */ + public void require(int type, String namespaceURI, String localName) throws XMLStreamException { + sr.require(type, namespaceURI, localName); + } + + @Override /* XMLStreamReader */ + public boolean standaloneSet() { + return sr.standaloneSet(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java index 34cbab0..4c1e89e 100644 --- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSchemaDocSerializer.java @@ -42,18 +42,11 @@ public class XmlSchemaDocSerializer extends XmlSchemaSerializer { * @param propertyStore The property store containing all the settings for this object. */ public XmlSchemaDocSerializer(PropertyStore propertyStore) { - super(propertyStore, null); + super(propertyStore); } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - XmlSerializerSession s = (XmlSerializerSession)session; - XmlWriter w = s.getXmlWriter(out); - w.append("<?xml") - .attr("version", "1.0") - .attr("encoding", "UTF-8") - .appendln("?>"); - w.flush(); - super.doSerialize(s, out, o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new XmlSchemaSerializerSession(ctx, args); } }
