Repository: incubator-juneau Updated Branches: refs/heads/master 8879750c6 -> 2a37f3103
http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java index f711dc1..1603f0d 100644 --- a/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java +++ b/juneau-core/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java @@ -14,7 +14,10 @@ package org.apache.juneau.xml; import static org.apache.juneau.msgpack.MsgPackSerializerContext.*; import static org.apache.juneau.xml.NamespaceFactory.*; +import static org.apache.juneau.xml.XmlSerializerSession.ContentResult.*; +import static org.apache.juneau.xml.XmlSerializerSession.JsonType.*; import static org.apache.juneau.xml.XmlSerializerContext.*; +import static org.apache.juneau.xml.annotation.XmlFormat.*; import static org.apache.juneau.internal.StringUtils.*; import static org.apache.juneau.internal.ArrayUtils.*; @@ -22,30 +25,32 @@ 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.xml.annotation.*; /** * Session object that lives for the duration of a single use of {@link XmlSerializer}. * * <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("hiding") -public class XmlSerializerSession extends SerializerSession { +@SuppressWarnings({"hiding","unchecked","rawtypes"}) +public class XmlSerializerSession extends WriterSerializerSession { - private final boolean + final boolean autoDetectNamespaces, enableNamespaces, addNamespaceUrlsToRoot, addBeanTypeProperties; - private Namespace + Namespace defaultNamespace; - private final Namespace + final Namespace xsNamespace; - private Namespace[] namespaces = new Namespace[0]; + Namespace[] namespaces = new Namespace[0]; /** * Create a new session using properties specified in the context. @@ -53,25 +58,17 @@ public class XmlSerializerSession 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}. */ - public XmlSerializerSession(XmlSerializerContext 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 XmlSerializerSession(XmlSerializerContext ctx, SerializerSessionArgs args) { + super(ctx, args); + ObjectMap p = getProperties(); + if (p.isEmpty()) { enableNamespaces = ctx.enableNamespaces; autoDetectNamespaces = ctx.autoDetectNamespaces; addNamespaceUrlsToRoot = ctx.addNamespaceUrlsToRoot; @@ -80,13 +77,13 @@ public class XmlSerializerSession extends SerializerSession { xsNamespace = ctx.xsNamespace; addBeanTypeProperties = ctx.addBeanTypeProperties; } else { - enableNamespaces = op.getBoolean(XML_enableNamespaces, ctx.enableNamespaces); - autoDetectNamespaces = op.getBoolean(XML_autoDetectNamespaces, ctx.autoDetectNamespaces); - addNamespaceUrlsToRoot = op.getBoolean(XML_addNamespaceUrisToRoot, ctx.addNamespaceUrlsToRoot); - namespaces = (op.containsKey(XML_namespaces) ? parseNamespaces(op.get(XML_namespaces)) : ctx.namespaces); - defaultNamespace = findDefaultNamespace(op.containsKey(XML_defaultNamespace) ? op.getString(XML_defaultNamespace) : ctx.defaultNamespace); - xsNamespace = (op.containsKey(XML_xsNamespace) ? parseNamespace(op.get(XML_xsNamespace)) : ctx.xsNamespace); - addBeanTypeProperties = op.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties); + enableNamespaces = p.getBoolean(XML_enableNamespaces, ctx.enableNamespaces); + autoDetectNamespaces = p.getBoolean(XML_autoDetectNamespaces, ctx.autoDetectNamespaces); + addNamespaceUrlsToRoot = p.getBoolean(XML_addNamespaceUrisToRoot, ctx.addNamespaceUrlsToRoot); + namespaces = (p.containsKey(XML_namespaces) ? parseNamespaces(p.get(XML_namespaces)) : ctx.namespaces); + defaultNamespace = findDefaultNamespace(p.containsKey(XML_defaultNamespace) ? p.getString(XML_defaultNamespace) : ctx.defaultNamespace); + xsNamespace = (p.containsKey(XML_xsNamespace) ? parseNamespace(p.get(XML_xsNamespace)) : ctx.xsNamespace); + addBeanTypeProperties = p.getBoolean(MSGPACK_addBeanTypeProperties, ctx.addBeanTypeProperties); } } @@ -105,12 +102,12 @@ public class XmlSerializerSession extends SerializerSession { addNamespace(ns); } - /** + /* * Add a namespace to this session. * * @param ns The namespace being added. */ - public void addNamespace(Namespace ns) { + private void addNamespace(Namespace ns) { if (ns == defaultNamespace) return; @@ -125,93 +122,607 @@ public class XmlSerializerSession extends SerializerSession { } /** - * Returns the list of namespaces being used in the current XML serialization. + * Returns the {@link XmlSerializerContext#XML_addBeanTypeProperties} setting value for this session. * - * @return The list of namespaces being used in the current XML serialization. + * @return The {@link XmlSerializerContext#XML_addBeanTypeProperties} setting value for this session. */ - public Namespace[] getNamespaces() { - return namespaces; + @Override /* SerializerSession */ + protected boolean isAddBeanTypeProperties() { + return addBeanTypeProperties; } /** - * Returns the {@link XmlSerializerContext#XML_autoDetectNamespaces} setting value in this context. + * Returns <jk>true</jk> if we're serializing HTML. + * + * <p> + * The difference in behavior is how empty non-void elements are handled. + * The XML serializer will produce a collapsed tag, whereas the HTML serializer will produce a start and end tag. * - * @return The {@link XmlSerializerContext#XML_autoDetectNamespaces} setting value in this context. + * @return <jk>true</jk> if we're generating HTML. */ - public final boolean isAutoDetectNamespaces() { - return enableNamespaces && autoDetectNamespaces; + protected boolean isHtmlMode() { + return false; } /** - * Returns the {@link XmlSerializerContext#XML_enableNamespaces} setting value in this context. + * Converts the specified output target object to an {@link XmlWriter}. * - * @return The {@link XmlSerializerContext#XML_enableNamespaces} setting value in this context. + * @param out The output target object. + * @return The output target object wrapped in an {@link XmlWriter}. + * @throws Exception */ - public final boolean isEnableNamespaces() { - return enableNamespaces; + public final XmlWriter getXmlWriter(SerializerPipe out) throws Exception { + Object output = out.getRawOutput(); + if (output instanceof XmlWriter) + return (XmlWriter)output; + XmlWriter w = new XmlWriter(out.getWriter(), isUseWhitespace(), getMaxIndent(), isTrimStrings(), getQuoteChar(), getUriResolver(), enableNamespaces, defaultNamespace); + out.setWriter(w); + return w; } - /** - * Returns the {@link XmlSerializerContext#XML_addNamespaceUrisToRoot} setting value in this context. - * - * @return The {@link XmlSerializerContext#XML_addNamespaceUrisToRoot} setting value in this context. - */ - public final boolean isAddNamespaceUrlsToRoot() { - return addNamespaceUrlsToRoot; + @Override /* Serializer */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + if (enableNamespaces && autoDetectNamespaces) + findNsfMappings(o); + serializeAnything(getXmlWriter(out), o, getExpectedRootType(o), null, null, enableNamespaces && addNamespaceUrlsToRoot, XmlFormat.DEFAULT, false, false, null); } /** - * Returns the {@link XmlSerializerContext#XML_addBeanTypeProperties} setting value for this session. + * Recursively searches for the XML namespaces on the specified POJO and adds them to the serializer context object. * - * @return The {@link XmlSerializerContext#XML_addBeanTypeProperties} setting value for this session. + * @param o The POJO to check. + * @throws SerializeException */ - @Override /* SerializerSession */ - public boolean isAddBeanTypeProperties() { - return addBeanTypeProperties; + protected final void findNsfMappings(Object o) throws SerializeException { + ClassMeta<?> aType = null; // The actual type + aType = push(null, o, null); + + if (aType != null) { + Namespace ns = aType.getExtendedMeta(XmlClassMeta.class).getNamespace(); + if (ns != null) { + if (ns.uri != null) + addNamespace(ns); + else + ns = null; + } + } + + // Handle recursion + if (aType != null && ! aType.isPrimitive()) { + + BeanMap<?> bm = null; + if (aType.isBeanMap()) { + bm = (BeanMap<?>)o; + } else if (aType.isBean()) { + bm = toBeanMap(o); + } else if (aType.isDelegate()) { + ClassMeta<?> innerType = ((Delegate<?>)o).getClassMeta(); + Namespace ns = innerType.getExtendedMeta(XmlClassMeta.class).getNamespace(); + if (ns != null) { + if (ns.uri != null) + addNamespace(ns); + else + ns = null; + } + + if (innerType.isBean()) { + for (BeanPropertyMeta bpm : innerType.getBeanMeta().getPropertyMetas()) { + ns = bpm.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + if (ns != null && ns.uri != null) + addNamespace(ns); + } + + } else if (innerType.isMap()) { + for (Object o2 : ((Map<?,?>)o).values()) + findNsfMappings(o2); + } else if (innerType.isCollection()) { + for (Object o2 : ((Collection<?>)o)) + findNsfMappings(o2); + } + + } else if (aType.isMap()) { + for (Object o2 : ((Map<?,?>)o).values()) + findNsfMappings(o2); + } else if (aType.isCollection()) { + for (Object o2 : ((Collection<?>)o)) + findNsfMappings(o2); + } else if (aType.isArray() && ! aType.getElementType().isPrimitive()) { + for (Object o2 : ((Object[])o)) + findNsfMappings(o2); + } + if (bm != null) { + for (BeanPropertyValue p : bm.getValues(isTrimNulls())) { + + Namespace ns = p.getMeta().getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace(); + if (ns != null && ns.uri != null) + addNamespace(ns); + + try { + findNsfMappings(p.getValue()); + } catch (Throwable x) { + // Ignore + } + } + } + } + + pop(); } /** - * Returns the {@link XmlSerializerContext#XML_defaultNamespace} setting value in this context. + * Workhorse method. * - * @return The {@link XmlSerializerContext#XML_defaultNamespace} setting value in this context. + * @param out The writer to send the output to. + * @param o The object to serialize. + * @param eType The expected type if this is a bean property value being serialized. + * @param elementName The root element name. + * @param elementNamespace The namespace of the element. + * @param addNamespaceUris Flag indicating that namespace URIs need to be added. + * @param format The format to serialize the output to. + * @param isMixed We're serializing mixed content, so don't use whitespace. + * @param preserveWhitespace + * <jk>true</jk> if we're serializing {@link XmlFormat#MIXED_PWS} or {@link XmlFormat#TEXT_PWS}. + * @param pMeta The bean property metadata if this is a bean property being serialized. + * @return The same writer passed in so that calls to the writer can be chained. + * @throws Exception If a problem occurred trying to convert the output. */ - public final Namespace getDefaultNamespace() { - return defaultNamespace; + protected XmlWriter serializeAnything( + XmlWriter out, + Object o, + ClassMeta<?> eType, + String elementName, + Namespace elementNamespace, + boolean addNamespaceUris, + XmlFormat format, + boolean isMixed, + boolean preserveWhitespace, + BeanPropertyMeta pMeta) throws Exception { + + JsonType type = null; // The type string (e.g. <type> or <x x='type'> + int i = isMixed ? 0 : indent; // Current indentation + ClassMeta<?> aType = null; // The actual type + ClassMeta<?> wType = null; // The wrapped type (delegate) + ClassMeta<?> sType = object(); // The serialized type + + aType = push(elementName, o, eType); + + if (eType == null) + eType = object(); + + // Handle recursion + if (aType == null) { + o = null; + aType = object(); + } + + if (o != null) { + + if (aType.isDelegate()) { + wType = aType; + eType = aType = ((Delegate<?>)o).getClassMeta(); + } + + sType = aType.getSerializedClassMeta(); + + // 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); + } + } else { + sType = eType.getSerializedClassMeta(); + } + + // Does the actual type match the expected type? + boolean isExpectedType = true; + if (o == null || ! eType.same(aType)) { + if (eType.isNumber()) + isExpectedType = aType.isNumber(); + else if (eType.isMap()) + isExpectedType = aType.isMap(); + else if (eType.isCollectionOrArray()) + isExpectedType = aType.isCollectionOrArray(); + else + isExpectedType = false; + } + + String resolvedDictionaryName = isExpectedType ? null : aType.getDictionaryName(); + + // Note that the dictionary name may be specified on the actual type or the serialized type. + // HTML templates will have them defined on the serialized type. + String dictionaryName = aType.getDictionaryName(); + if (dictionaryName == null) + dictionaryName = sType.getDictionaryName(); + + // char '\0' is interpreted as null. + if (o != null && sType.isChar() && ((Character)o).charValue() == 0) + o = null; + + boolean isCollapsed = false; // If 'true', this is a collection and we're not rendering the outer element. + + // Get the JSON type string. + if (o == null) { + type = NULL; + } else if (sType.isCharSequence() || sType.isChar()) { + type = STRING; + } else if (sType.isNumber()) { + type = NUMBER; + } else if (sType.isBoolean()) { + type = BOOLEAN; + } else if (sType.isMapOrBean()) { + isCollapsed = sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED; + type = OBJECT; + } else if (sType.isCollectionOrArray()) { + isCollapsed = (format == COLLAPSED && ! addNamespaceUris); + type = ARRAY; + } else { + type = STRING; + } + + if (format.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT) && type.isOneOf(NULL,STRING,NUMBER,BOOLEAN)) + isCollapsed = true; + + // Is there a name associated with this bean? + if (elementName == null && dictionaryName != null) { + elementName = dictionaryName; + isExpectedType = true; + } + + if (enableNamespaces) { + if (elementNamespace == null) + elementNamespace = sType.getExtendedMeta(XmlClassMeta.class).getNamespace(); + if (elementNamespace == null) + elementNamespace = aType.getExtendedMeta(XmlClassMeta.class).getNamespace(); + if (elementNamespace != null && elementNamespace.uri == null) + elementNamespace = null; + if (elementNamespace == null) + elementNamespace = defaultNamespace; + } else { + elementNamespace = null; + } + + // Do we need a carriage return after the start tag? + boolean cr = o != null && (sType.isMapOrBean() || sType.isCollectionOrArray()) && ! isMixed; + + String en = elementName; + if (en == null) { + en = type.toString(); + type = null; + } + boolean encodeEn = elementName != null; + String ns = (elementNamespace == null ? null : elementNamespace.name); + String dns = null, elementNs = null; + if (enableNamespaces) { + dns = elementName == null && defaultNamespace != null ? defaultNamespace.name : null; + elementNs = elementName == null ? dns : ns; + if (elementName == null) + elementNamespace = null; + } + + // Render the start tag. + if (! isCollapsed) { + out.oTag(i, elementNs, en, encodeEn); + if (addNamespaceUris) { + out.attr((String)null, "xmlns", defaultNamespace.getUri()); + + for (Namespace n : namespaces) + out.attr("xmlns", n.getName(), n.getUri()); + } + if (! isExpectedType) { + if (resolvedDictionaryName != null) + out.attr(dns, getBeanTypePropertyName(eType), resolvedDictionaryName); + else if (type != null && type != STRING) + out.attr(dns, getBeanTypePropertyName(eType), type); + } + if (o == null) { + if ((sType.isBoolean() || sType.isNumber()) && ! sType.isNullable()) + o = sType.getPrimitiveDefault(); + } + + if (o != null && ! (sType.isMapOrBean())) + out.append('>'); + + if (cr && ! (sType.isMapOrBean())) + out.nl(i+1); + } + + ContentResult rc = CR_ELEMENTS; + + // Render the tag contents. + if (o != null) { + if (sType.isUri() || (pMeta != null && pMeta.isUri())) { + out.textUri(o); + } else if (sType.isCharSequence() || sType.isChar()) { + if (format == XMLTEXT) + out.append(o); + else + out.text(o, preserveWhitespace); + } else if (sType.isNumber() || sType.isBoolean()) { + out.append(o); + } else if (sType.isMap() || (wType != null && wType.isMap())) { + if (o instanceof BeanMap) + rc = serializeBeanMap(out, (BeanMap)o, elementNamespace, isCollapsed, isMixed); + else + rc = serializeMap(out, (Map)o, sType, eType.getKeyType(), eType.getValueType(), isMixed); + } else if (sType.isBean()) { + rc = serializeBeanMap(out, toBeanMap(o), elementNamespace, isCollapsed, isMixed); + } else if (sType.isCollection() || (wType != null && wType.isCollection())) { + if (isCollapsed) + this.indent--; + serializeCollection(out, o, sType, eType, pMeta, isMixed); + if (isCollapsed) + this.indent++; + } else if (sType.isArray()) { + if (isCollapsed) + this.indent--; + serializeCollection(out, o, sType, eType, pMeta, isMixed); + if (isCollapsed) + this.indent++; + } else { + if (format == XMLTEXT) + out.append(toString(o)); + else + out.text(toString(o)); + } + } + + pop(); + + // Render the end tag. + if (! isCollapsed) { + if (rc == CR_EMPTY) { + if (isHtmlMode()) + out.append('>').eTag(elementNs, en, encodeEn); + else + out.append('/').append('>'); + } else if (rc == CR_VOID || o == null) { + out.append('/').append('>'); + } + else + out.ie(cr && rc != CR_MIXED ? i : 0).eTag(elementNs, en, encodeEn); + if (! isMixed) + out.nl(i); + } + + return out; } - /** - * Returns the {@link XmlSerializerContext#XML_xsNamespace} setting value in this context. - * - * @return The {@link XmlSerializerContext#XML_xsNamespace} setting value in this context. - */ - public final Namespace getXsNamespace() { - return xsNamespace; + private ContentResult serializeMap(XmlWriter out, Map m, ClassMeta<?> sType, + ClassMeta<?> eKeyType, ClassMeta<?> eValueType, boolean isMixed) throws Exception { + + m = sort(m); + + ClassMeta<?> keyType = eKeyType == null ? sType.getKeyType() : eKeyType; + ClassMeta<?> valueType = eValueType == null ? sType.getValueType() : eValueType; + + boolean hasChildren = false; + for (Iterator i = m.entrySet().iterator(); i.hasNext();) { + Map.Entry e = (Map.Entry)i.next(); + + Object k = e.getKey(); + if (k == null) { + k = "\u0000"; + } else { + k = generalize(k, keyType); + if (isTrimStrings() && k instanceof String) + k = k.toString().trim(); + } + + Object value = e.getValue(); + + if (! hasChildren) { + hasChildren = true; + out.append('>').nlIf(! isMixed, indent); + } + serializeAnything(out, value, valueType, toString(k), null, false, XmlFormat.DEFAULT, isMixed, false, null); + } + return hasChildren ? CR_ELEMENTS : CR_EMPTY; } - /** - * Returns <jk>true</jk> if we're serializing HTML. - * - * <p> - * The difference in behavior is how empty non-void elements are handled. - * The XML serializer will produce a collapsed tag, whereas the HTML serializer will produce a start and end tag. - * - * @return <jk>true</jk> if we're generating HTML. - */ - public boolean isHtmlMode() { - return false; + private ContentResult serializeBeanMap(XmlWriter out, BeanMap<?> m, + Namespace elementNs, boolean isCollapsed, boolean isMixed) throws Exception { + boolean hasChildren = false; + BeanMeta<?> bm = m.getMeta(); + + List<BeanPropertyValue> lp = m.getValues(isTrimNulls()); + + XmlBeanMeta xbm = bm.getExtendedMeta(XmlBeanMeta.class); + + Set<String> + attrs = xbm.getAttrPropertyNames(), + elements = xbm.getElementPropertyNames(), + collapsedElements = xbm.getCollapsedPropertyNames(); + String + attrsProperty = xbm.getAttrsPropertyName(), + contentProperty = xbm.getContentPropertyName(); + + XmlFormat cf = null; + + Object content = null; + ClassMeta<?> contentType = null; + for (BeanPropertyValue p : lp) { + String n = p.getName(); + if (attrs.contains(n) || attrs.contains("*") || n.equals(attrsProperty)) { + 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; + + Namespace ns = (enableNamespaces && pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() != elementNs ? pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace() : null); + + if (pMeta.isUri() ) { + out.attrUri(ns, key, value); + } else if (n.equals(attrsProperty)) { + if (value instanceof BeanMap) { + BeanMap<?> bm2 = (BeanMap)value; + for (BeanPropertyValue p2 : bm2.getValues(true)) { + String key2 = p2.getName(); + Object value2 = p2.getValue(); + Throwable t2 = p2.getThrown(); + if (t2 != null) + onBeanGetterException(pMeta, t); + out.attr(ns, key2, value2); + } + } else /* Map */ { + Map m2 = (Map)value; + for (Map.Entry e : (Set<Map.Entry>)(m2.entrySet())) { + out.attr(ns, toString(e.getKey()), e.getValue()); + } + } + } else { + out.attr(ns, key, value); + } + } + } + + boolean + hasContent = false, + preserveWhitespace = false, + isVoidElement = xbm.getContentFormat() == VOID; + + for (BeanPropertyValue p : lp) { + BeanPropertyMeta pMeta = p.getMeta(); + ClassMeta<?> cMeta = p.getClassMeta(); + + String n = p.getName(); + if (n.equals(contentProperty)) { + content = p.getValue(); + contentType = p.getClassMeta(); + hasContent = true; + cf = xbm.getContentFormat(); + if (cf.isOneOf(MIXED,MIXED_PWS,TEXT,TEXT_PWS,XMLTEXT)) + isMixed = true; + if (cf.isOneOf(MIXED_PWS, TEXT_PWS)) + preserveWhitespace = true; + if (contentType.isCollection() && ((Collection)content).isEmpty()) + hasContent = false; + else if (contentType.isArray() && Array.getLength(content) == 0) + hasContent = false; + } else if (elements.contains(n) || collapsedElements.contains(n) || elements.contains("*") || collapsedElements.contains("*") ) { + 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 (! hasChildren) { + hasChildren = true; + out.appendIf(! isCollapsed, '>').nlIf(! isMixed, indent); + } + + XmlBeanPropertyMeta xbpm = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class); + serializeAnything(out, value, cMeta, key, xbpm.getNamespace(), false, xbpm.getXmlFormat(), isMixed, false, pMeta); + } + } + if (! hasContent) + return (hasChildren ? CR_ELEMENTS : isVoidElement ? CR_VOID : CR_EMPTY); + out.append('>').nlIf(! isMixed, indent); + + // Serialize XML content. + if (content != null) { + if (contentType == null) { + } else if (contentType.isCollection()) { + Collection c = (Collection)content; + for (Iterator i = c.iterator(); i.hasNext();) { + Object value = i.next(); + serializeAnything(out, value, contentType.getElementType(), null, null, false, cf, isMixed, preserveWhitespace, null); + } + } else if (contentType.isArray()) { + Collection c = toList(Object[].class, content); + for (Iterator i = c.iterator(); i.hasNext();) { + Object value = i.next(); + serializeAnything(out, value, contentType.getElementType(), null, null, false, cf, isMixed, preserveWhitespace, null); + } + } else { + serializeAnything(out, content, contentType, null, null, false, cf, isMixed, preserveWhitespace, null); + } + } else { + if (! isTrimNulls()) { + if (! isMixed) + out.i(indent); + out.text(content); + if (! isMixed) + out.nl(indent); + } + } + return isMixed ? CR_MIXED : CR_ELEMENTS; + } + + private XmlWriter serializeCollection(XmlWriter out, Object in, ClassMeta<?> sType, + ClassMeta<?> eType, BeanPropertyMeta ppMeta, boolean isMixed) throws Exception { + + ClassMeta<?> seType = sType.getElementType(); + if (seType == null) + seType = object(); + ClassMeta<?> eeType = eType.getElementType(); + + Collection c = (sType.isCollection() ? (Collection)in : toList(sType.getInnerClass(), in)); + + c = sort(c); + + String type2 = null; + if (sType != eType) + type2 = sType.getDictionaryName(); + + String eName = type2; + Namespace eNs = null; + + if (ppMeta != null) { + XmlBeanPropertyMeta xbpm = ppMeta.getExtendedMeta(XmlBeanPropertyMeta.class); + eName = xbpm.getChildName(); + eNs = xbpm.getNamespace(); + } + + for (Iterator i = c.iterator(); i.hasNext();) { + Object value = i.next(); + serializeAnything(out, value, eeType, eName, eNs, false, XmlFormat.DEFAULT, isMixed, false, null); + } + return out; + } + + static enum JsonType { + STRING("string"),BOOLEAN("boolean"),NUMBER("number"),ARRAY("array"),OBJECT("object"),NULL("null"); + + private final String value; + private JsonType(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + + boolean isOneOf(JsonType...types) { + for (JsonType type : types) + if (type == this) + return true; + return false; + } } /** - * Converts the specified output target object to an {@link XmlWriter}. - * - * @param out The output target object. - * @return The output target object wrapped in an {@link XmlWriter}. - * @throws Exception + * Identifies what the contents were of a serialized bean. */ - public XmlWriter getXmlWriter(SerializerOutput out) throws Exception { - Object output = out.getRawOutput(); - if (output instanceof XmlWriter) - return (XmlWriter)output; - return new XmlWriter(out.getWriter(), isUseWhitespace(), getMaxIndent(), isTrimStrings(), getQuoteChar(), getUriResolver(), isEnableNamespaces(), getDefaultNamespace()); + static enum ContentResult { + CR_VOID, // No content...append "/>" to the start tag. + CR_EMPTY, // No content...append "/>" to the start tag if XML, "/></end>" if HTML. + CR_MIXED, // Mixed content...don't add whitespace. + CR_ELEMENTS // Elements...use normal whitespace rules. } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-core/src/main/javadoc/overview.html ---------------------------------------------------------------------- diff --git a/juneau-core/src/main/javadoc/overview.html b/juneau-core/src/main/javadoc/overview.html index 855fcec..2f41325 100644 --- a/juneau-core/src/main/javadoc/overview.html +++ b/juneau-core/src/main/javadoc/overview.html @@ -6892,14 +6892,32 @@ <h6 class='topic'>org.apache.juneau</h6> <ul class='spaced-list'> <li> - Serializers can now serialize to {@link StringBuilder StringBuilders}. + Serializers can now serialize to {@link java.util.StringBuilder StringBuilders}. + <li> + {@link org.apache.juneau.serializer.SerializerSession} and {@link org.apache.juneau.parser.ParserSession} + objects are now reusable if used within the same thread. + <p class='bcode'> + <jc>// Old way (still works)</jc> + JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer1, pojo1); + JsonSerializer.<jsf>DEFAULT</jsf>.serialize(writer2, pojo2); + + <jc>// Same, but using a session object</jc> + SerializerSession session = JsonSerializer.<jsf>DEFAULT</jsf>.createSession(); + <jk>try</jk> { + session.serialize(writer1, pojo1); + session.serialize(writer2, pojo2); + } <jk>finally</jk> { + session.close(); + } + </p> + This is mostly an internal change and doesn't affect the existing APIs. </ul> <h6 class='topic'>org.apache.juneau.rest</h6> <ul class='spaced-list'> <li> Simplified {@link org.apache.juneau.rest.widget.MenuItemWidget}. - <br>Exposes an abstract method {@link org.apache.juneau.rest.widget.MenuItemWidget#getContent()} that + <br>Exposes an abstract method {@link org.apache.juneau.rest.widget.MenuItemWidget#getContent(RestRequest)} that can return raw HTML via readers or char-sequences, or any other object (such as HTML5 beans) that will get converted to HTML using {@link org.apache.juneau.html.HtmlSerializer#DEFAULT}. <li> @@ -7265,7 +7283,7 @@ <li>{@link org.apache.juneau.rest.client.RestClientBuilder#listeners(Class,Class)} </ul> <li>The {@link org.apache.juneau.BeanContext#BEAN_debug} flag will now capture parser input and make it - available through the {@link org.apache.juneau.parser.ParserSession#getInputAsString()} method so that it can be used + available through the <code><del>ParserSession.getInputAsString()</del></code> method so that it can be used in the listeners. <li>Significant new functionality introduced to the HTML serializer. <br>Lots of new options for customizing the HTML output. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java ---------------------------------------------------------------------- diff --git a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java index 94cefcc..79e094a 100644 --- a/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java +++ b/juneau-examples-rest/src/main/java/org/apache/juneau/examples/rest/PhotosResource.java @@ -142,11 +142,17 @@ public class PhotosResource extends Resource { super(propertyStore); } - @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - RenderedImage image = (RenderedImage)o; - String mediaType = session.getProperty("mediaType"); - ImageIO.write(image, mediaType.substring(mediaType.indexOf('/')+1), out.getOutputStream()); + @Override /* Serializer */ + public OutputStreamSerializerSession createSession(SerializerSessionArgs args) { + return new OutputStreamSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + RenderedImage image = (RenderedImage)o; + String mediaType = getProperty("mediaType"); + ImageIO.write(image, mediaType.substring(mediaType.indexOf('/')+1), out.getOutputStream()); + } + }; } } @@ -163,9 +169,15 @@ public class PhotosResource extends Resource { } @Override /* Parser */ - @SuppressWarnings("unchecked") - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)ImageIO.read(session.getInputStream()); + public InputStreamParserSession createSession(final ParserSessionArgs args) { + return new InputStreamParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)ImageIO.read(pipe.getInputStream()); + } + }; } } -} +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java ---------------------------------------------------------------------- diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java index 4e2adb8..9b8f45b 100644 --- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java +++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestCallLogger.java @@ -70,7 +70,7 @@ public class RestCallLogger extends RestCallInterceptor { public void onRetry(RestCall restCall, int statusCode, HttpRequest req, HttpResponse res, Exception ex) { if (log.isLoggable(level)) { if (ex == null) - log.log(level, format("Call to {0} returned {1}. Will retry.", req.getRequestLine().getUri(), statusCode)); + log.log(level, format("Call to {0} returned {1}. Will retry.", req.getRequestLine().getUri(), statusCode)); else log.log(level, format("Call to {0} caused exception {1}. Will retry.", req.getRequestLine().getUri(), ex.getLocalizedMessage()), ex); } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java ---------------------------------------------------------------------- diff --git a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java index 8767730..c37bb84 100644 --- a/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java +++ b/juneau-rest-client/src/main/java/org/apache/juneau/rest/client/RestRequestEntity.java @@ -53,17 +53,18 @@ public final class RestRequestEntity extends BasicHttpEntity { if (serializer == null) { // If no serializer specified, just close the stream. os.close(); - } else if (! serializer.isWriterSerializer()) { - OutputStreamSerializer s2 = (OutputStreamSerializer)serializer; - s2.serialize(output, os); - os.flush(); - os.close(); } else { - Writer w = new OutputStreamWriter(os, UTF8); - WriterSerializer s2 = (WriterSerializer)serializer; - s2.serialize(output, w); - w.flush(); - w.close(); + SerializerSession session = serializer.createSession(); + if (session.isWriterSerializer()) { + Writer w = new OutputStreamWriter(os, UTF8); + session.serialize(w, output); + w.flush(); + w.close(); + } else { + session.serialize(os, output); + os.flush(); + os.close(); + } } } catch (SerializeException e) { throw new org.apache.juneau.rest.client.RestCallException(e); http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java ---------------------------------------------------------------------- diff --git a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java index a2137a1..ecdee93 100644 --- a/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java +++ b/juneau-rest-jaxrs/src/main/java/org/apache/juneau/rest/jaxrs/BaseProvider.java @@ -105,7 +105,7 @@ public class BaseProvider implements MessageBodyReader<Object>, MessageBodyWrite @Override /* MessageBodyWriter */ public void writeTo(Object o, Class<?> type, Type gType, Annotation[] a, MediaType mediaType, - MultivaluedMap<String,Object> headers, OutputStream out) throws IOException, WebApplicationException { + MultivaluedMap<String,Object> headers, OutputStream os) throws IOException, WebApplicationException { try { SerializerMatch sm = serializers.getSerializerMatch(mediaType.toString()); if (sm == null) @@ -115,21 +115,16 @@ public class BaseProvider implements MessageBodyReader<Object>, MessageBodyWrite mp.append("mediaType", mediaType.toString()); Locale locale = getLocale(headers); TimeZone timeZone = getTimeZone(headers); + + SerializerSession session = s.createSession(new SerializerSessionArgs(mp, null, locale, timeZone, sm.getMediaType(), null)); + if (s.isWriterSerializer()) { - WriterSerializer s2 = (WriterSerializer)s; - OutputStreamWriter w = new OutputStreamWriter(out, UTF8); - SerializerOutput sout = new SerializerOutput(w); - SerializerSession session = s.createSession(mp, null, locale, timeZone, sm.getMediaType(), null); - s2.serialize(session, sout, o); - w.flush(); - w.close(); + OutputStreamWriter w = new OutputStreamWriter(os, UTF8); + session.serialize(w, o); + w.close(); // Leave open if exception occurs. } else { - OutputStreamSerializer s2 = (OutputStreamSerializer)s; - SerializerOutput sout = new SerializerOutput(s2); - SerializerSession session = s.createSession(mp, null, locale, timeZone, sm.getMediaType(), null); - s2.serialize(session, sout, o); - out.flush(); - out.close(); + session.serialize(os, o); + os.close(); // Leave open if exception occurs. } } catch (SerializeException e) { throw new IOException(e); @@ -153,15 +148,13 @@ public class BaseProvider implements MessageBodyReader<Object>, MessageBodyWrite mp.put("mediaType", mediaType.toString()); Locale locale = getLocale(headers); TimeZone timeZone = getTimeZone(headers); - if (p.isReaderParser()) { - ReaderParser p2 = (ReaderParser)p; - InputStreamReader r = new InputStreamReader(in, UTF8); - ParserSession session = p2.createSession(r, mp, null, null, locale, timeZone, pm.getMediaType()); - return p2.parseSession(session, p.getBeanContext().getClassMeta(gType)); + ParserSession session = p.createSession(new ParserSessionArgs(mp, null, locale, timeZone, pm.getMediaType(), null)); + try { + Object in2 = session.isReaderParser() ? new InputStreamReader(in, UTF8) : in; + return session.parse(in2, p.getBeanContext().getClassMeta(gType)); + } finally { + session.close(); } - InputStreamParser p2 = (InputStreamParser)p; - ParserSession session = p2.createSession(in, mp, null, null, locale, timeZone, pm.getMediaType()); - return p2.parseSession(session, p.getBeanContext().getClassMeta(gType)); } catch (ParseException e) { throw new IOException(e); } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java index 94051a7..4919b75 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/AcceptCharsetResource.java @@ -61,10 +61,16 @@ public class AcceptCharsetResource extends RestServlet { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)session.getProperty("characterEncoding"); + public InputStreamParserSession createSession(ParserSessionArgs args) { + return new InputStreamParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)getProperty("characterEncoding"); + } + }; } } @@ -76,11 +82,16 @@ public class AcceptCharsetResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - Writer w = new OutputStreamWriter(out.getOutputStream()); - w.append(o.toString()).append('/').append(session.getProperty("characterEncoding")); - w.flush(); - w.close(); + public OutputStreamSerializerSession createSession(SerializerSessionArgs args) { + return new OutputStreamSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + Writer w = new OutputStreamWriter(out.getOutputStream()); + w.append(o.toString()).append('/').append(getProperty("characterEncoding")); + w.flush(); + } + }; } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java index e9cf51e..e9ed395 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/CharsetEncodingsResource.java @@ -39,10 +39,16 @@ public class CharsetEncodingsResource extends RestServlet { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)read(session.getReader()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)read(pipe.getReader()); + } + }; } } @@ -54,8 +60,14 @@ public class CharsetEncodingsResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write(o.toString()); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(o.toString()); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java index 2634056..22fd963 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/DefaultContentTypesResource.java @@ -112,10 +112,16 @@ public class DefaultContentTypesResource extends RestServlet { this.name = name; } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)name; + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)name; + } + }; } } @@ -129,8 +135,14 @@ public class DefaultContentTypesResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object output) throws Exception { - out.getWriter().write(name + "/" + output); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(name + "/" + o); + } + }; } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java index 493136d..233e9ef 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/GroupsResource.java @@ -44,8 +44,14 @@ public class GroupsResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object output) throws Exception { - out.getWriter().write("text/s," + output); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("text/s," + o); + } + }; } } @@ -56,10 +62,16 @@ public class GroupsResource extends RestServlet { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)read(session.getReader()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)read(pipe.getReader()); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java index 7d5af0d..5b25414 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/InheritanceResource.java @@ -229,8 +229,14 @@ public class InheritanceResource extends RestServlet { } @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return null; + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return null; + } + }; } } @@ -241,8 +247,14 @@ public class InheritanceResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write(o.toString()); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(o.toString()); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java index 62de96b..183889d 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/NlsPropertyResource.java @@ -60,8 +60,14 @@ public class NlsPropertyResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write(session.getProperty("TestProperty")); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(getProperty("TestProperty")); + } + }; } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java index c509fc5..04e1218 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPostCallResource.java @@ -12,11 +12,15 @@ // *************************************************************************************************************************** package org.apache.juneau.rest.test; +import java.util.*; + import org.apache.juneau.*; import org.apache.juneau.annotation.*; import org.apache.juneau.rest.*; import org.apache.juneau.rest.annotation.*; +import org.apache.juneau.rest.annotation.Properties; import org.apache.juneau.serializer.*; +import org.apache.juneau.utils.*; /** * JUnit automated testcase resource. @@ -43,14 +47,22 @@ public class OnPostCallResource extends RestServlet { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write("p1="+session.getProperty("p1")+",p2="+session.getProperty("p2")+",p3="+session.getProperty("p3")+",p4="+session.getProperty("p4")+",p5="+session.getProperty("p5")+",contentType="+session.getProperty("mediaType")); - } - @Override /* Serializer */ - public ObjectMap getResponseHeaders(ObjectMap properties) { - if (properties.containsKey("Override-Content-Type")) - return new ObjectMap().append("Content-Type", properties.get("Override-Content-Type")); - return null; + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("p1="+getProperty("p1")+",p2="+getProperty("p2")+",p3="+getProperty("p3")+",p4="+getProperty("p4")+",p5="+getProperty("p5")+",contentType="+getProperty("mediaType")); + } + + @Override /* SerializerSession */ + public Map<String,String> getResponseHeaders() { + ObjectMap p = getProperties(); + if (p.containsKey("Override-Content-Type")) + return new AMap<String,String>().append("Content-Type", p.getString("Override-Content-Type")); + return Collections.emptyMap(); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java index d4f6e20..81e24e3 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/OnPreCallResource.java @@ -44,11 +44,17 @@ public class OnPreCallResource extends RestServlet { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - String matchingContentType = session.getProperty("mediaType"); - return (T)("p1="+session.getProperty("p1")+",p2="+session.getProperty("p2")+",p3="+session.getProperty("p3")+",p4="+session.getProperty("p4")+",p5="+session.getProperty("p5")+",contentType="+matchingContentType); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + String matchingContentType = getProperty("mediaType"); + return (T)("p1="+getProperty("p1")+",p2="+getProperty("p2")+",p3="+getProperty("p3")+",p4="+getProperty("p4")+",p5="+getProperty("p5")+",contentType="+matchingContentType); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java index 24823a2..1142263 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/ParsersResource.java @@ -41,10 +41,16 @@ public class ParsersResource extends RestServletDefault { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)("text/a - " + read(session.getReader()).trim()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)("text/a - " + read(pipe.getReader()).trim()); + } + }; } } @@ -71,10 +77,16 @@ public class ParsersResource extends RestServletDefault { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)("text/b - " + read(session.getReader()).trim()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)("text/b - " + read(pipe.getReader()).trim()); + } + }; } } @@ -93,10 +105,16 @@ public class ParsersResource extends RestServletDefault { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)("text/c - " + read(session.getReader()).trim()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)("text/c - " + read(pipe.getReader()).trim()); + } + }; } } @@ -115,10 +133,16 @@ public class ParsersResource extends RestServletDefault { super(propertyStore); } - @SuppressWarnings("unchecked") @Override /* Parser */ - protected <T> T doParse(ParserSession session, ClassMeta<T> type) throws Exception { - return (T)("text/d - " + read(session.getReader()).trim()); + public ReaderParserSession createSession(ParserSessionArgs args) { + return new ReaderParserSession(args) { + + @Override /* ParserSession */ + @SuppressWarnings("unchecked") + protected <T> T doParse(ParserPipe pipe, ClassMeta<T> type) throws Exception { + return (T)("text/d - " + read(pipe.getReader()).trim()); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java index dcb0873..604d485 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/PropertiesResource.java @@ -67,10 +67,16 @@ public class PropertiesResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object output) throws Exception { - out.getWriter().write(format("A1=%s,A2=%s,B1=%s,B2=%s,C=%s,R1a=%s,R1b=%s,R2=%s,R3=%s,R4=%s,R5=%s,R6=%s", - session.getProperty("A1"), session.getProperty("A2"), session.getProperty("B1"), session.getProperty("B2"), session.getProperty("C"), - session.getProperty("R1a"), session.getProperty("R1b"), session.getProperty("R2"), session.getProperty("R3"), session.getProperty("R4"), session.getProperty("R5"), session.getProperty("R6"))); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(format("A1=%s,A2=%s,B1=%s,B2=%s,C=%s,R1a=%s,R1b=%s,R2=%s,R3=%s,R4=%s,R5=%s,R6=%s", + getProperty("A1"), getProperty("A2"), getProperty("B1"), getProperty("B2"), getProperty("C"), + getProperty("R1a"), getProperty("R1b"), getProperty("R2"), getProperty("R3"), getProperty("R4"), getProperty("R5"), getProperty("R6"))); + } + }; } } @@ -90,8 +96,14 @@ public class PropertiesResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object output) throws Exception { - out.getWriter().write(format("A=%s,P=%s,H=%s", session.getProperty("A"), session.getProperty("P"), session.getProperty("h"))); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write(format("A=%s,P=%s,H=%s", getProperty("A"), getProperty("P"), getProperty("h"))); + } + }; } } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java index 092c9af..c4578c2 100644 --- a/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java +++ b/juneau-rest-test/src/main/java/org/apache/juneau/rest/test/SerializersResource.java @@ -38,8 +38,14 @@ public class SerializersResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write("text/a - " + o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("text/a - " + o); + } + }; } } @@ -51,8 +57,14 @@ public class SerializersResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write("text/b - " + o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("text/b - " + o); + } + }; } } @@ -88,8 +100,14 @@ public class SerializersResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write("text/c - " + o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("text/c - " + o); + } + }; } } @@ -109,8 +127,14 @@ public class SerializersResource extends RestServletDefault { } @Override /* Serializer */ - protected void doSerialize(SerializerSession session, SerializerOutput out, Object o) throws Exception { - out.getWriter().write("text/d - " + o); + public WriterSerializerSession createSession(SerializerSessionArgs args) { + return new WriterSerializerSession(args) { + + @Override /* SerializerSession */ + protected void doSerialize(SerializerPipe out, Object o) throws Exception { + out.getWriter().write("text/d - " + o); + } + }; } } http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java index 5da647a..40ad1f7 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RequestBody.java @@ -358,14 +358,9 @@ public class RequestBody { MediaType mediaType = pm.getMediaType(); try { req.getProperties().append("mediaType", mediaType).append("characterEncoding", req.getCharacterEncoding()); - if (! p.isReaderParser()) { - InputStreamParser p2 = (InputStreamParser)p; - ParserSession session = p2.createSession(getInputStream(), req.getProperties(), req.getJavaMethod(), req.getContext().getResource(), locale, timeZone, mediaType); - return p2.parseSession(session, cm); - } - ReaderParser p2 = (ReaderParser)p; - ParserSession session = p2.createSession(getUnbufferedReader(), req.getProperties(), req.getJavaMethod(), req.getContext().getResource(), locale, timeZone, mediaType); - return p2.parseSession(session, cm); + ParserSession session = p.createSession(new ParserSessionArgs(req.getProperties(), req.getJavaMethod(), locale, timeZone, mediaType, req.getContext().getResource())); + Object in = session.isReaderParser() ? getUnbufferedReader() : getInputStream(); + return session.parse(in, cm); } catch (ParseException e) { throw new RestException(SC_BAD_REQUEST, "Could not convert request body content to class type ''{0}'' using parser ''{1}''.", http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java index 0bc4181..60d1ff3 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestConfig.java @@ -118,7 +118,7 @@ public class RestConfig implements ServletConfig { String[] htmlLinks; String clientVersionHeader = "X-Client-Version"; - Object resourceResolver = RestResourceResolver.Default.class; + Object resourceResolver = RestResourceResolverSimple.class; Object logger = RestLogger.Normal.class; Object callHandler = RestCallHandler.class; Object infoProvider = RestInfoProvider.class; @@ -156,7 +156,7 @@ public class RestConfig implements ServletConfig { this.inner = config; this.resourceClass = resourceClass; this.parentContext = parentContext; - this.resourceResolver = parentContext == null ? RestResourceResolver.Default.class : parentContext.getResourceResolver(); + this.resourceResolver = parentContext == null ? RestResourceResolverSimple.class : parentContext.getResourceResolver(); try { ConfigFileBuilder cfb = new ConfigFileBuilder(); @@ -1024,7 +1024,7 @@ public class RestConfig implements ServletConfig { * <p> * The resource resolver is used to resolve instances from {@link Class} objects defined in the * {@link RestResource#children()} annotation. - * The default value is {@link RestResourceResolver.Default}. + * The default value is {@link RestResourceResolverSimple}. * * <p> * This is the programmatic equivalent to the http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java index 1d21176..4a1fb02 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestRequest.java @@ -200,6 +200,9 @@ public final class RestRequest extends HttpServletRequestWrapper { + "\n=== END ========================================================================"; context.getLogger().log(Level.WARNING, msg); } + + if (isPlainText()) + this.properties.put(SerializerContext.SERIALIZER_useWhitespace, true); } /** http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java index 337fbce..30f9d83 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolver.java @@ -12,10 +12,6 @@ // *************************************************************************************************************************** package org.apache.juneau.rest; -import static org.apache.juneau.internal.ClassUtils.*; - -import java.lang.reflect.*; - import org.apache.juneau.rest.annotation.*; /** @@ -34,52 +30,12 @@ import org.apache.juneau.rest.annotation.*; * </ul> * * <p> - * The default implementation simply instantiates the class using one of the following constructors: - * <ul> - * <li><code><jk>public</jk> T(RestConfig)</code> - * <li><code><jk>public</jk> T()</code> - * </ul> - * - * <p> - * The former constructor can be used to get access to the {@link RestConfig} object to get access to the - * config file and initialization information or make programmatic modifications to the resource before - * full initialization. - * - * <p> - * Non-<code>RestServlet</code> classes can also add the following two methods to get access to the - * {@link RestConfig} and {@link RestContext} objects: - * <ul> - * <li><code><jk>public void</jk> init(RestConfig);</code> - * <li><code><jk>public void</jk> init(RestContext);</code> - * </ul> - * - * <p> * An instance of this class can also be passed in through the servlet context as the context attribute * {@link RestContext#REST_resourceResolver}. */ public interface RestResourceResolver { /** - * Denotes the default resolver. - */ - public static class Default implements RestResourceResolver { - @Override - public Object resolve(Class<?> c, RestConfig config) throws RestServletException { - try { - Constructor<?> c1 = findPublicConstructor(c, RestConfig.class); - if (c1 != null) - return c1.newInstance(config); - c1 = findPublicConstructor(c); - if (c1 != null) - return c1.newInstance(); - } catch (Exception e) { - throw new RestServletException("Could not instantiate resource class ''{0}''", c.getName()).initCause(e); - } - throw new RestServletException("Could not find public constructor for class ''{0}''.", c); - } - } - - /** * Resolves the specified class to a resource object. * * <p> http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java new file mode 100644 index 0000000..91bf3eb --- /dev/null +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/RestResourceResolverSimple.java @@ -0,0 +1,59 @@ +// *************************************************************************************************************************** +// * 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.rest; + +import static org.apache.juneau.internal.ClassUtils.*; + +import java.lang.reflect.*; + +/** + * Denotes the default resolver. + * + * <p> + * The default implementation simply instantiates the class using one of the following constructors: + * <ul> + * <li><code><jk>public</jk> T(RestConfig)</code> + * <li><code><jk>public</jk> T()</code> + * </ul> + * + * <p> + * The former constructor can be used to get access to the {@link RestConfig} object to get access to the + * config file and initialization information or make programmatic modifications to the resource before + * full initialization. + * + * <p> + * Non-<code>RestServlet</code> classes can also add the following two methods to get access to the + * {@link RestConfig} and {@link RestContext} objects: + * <ul> + * <li><code><jk>public void</jk> init(RestConfig);</code> + * <li><code><jk>public void</jk> init(RestContext);</code> + * </ul> + * + */ +public class RestResourceResolverSimple implements RestResourceResolver { + + @Override /* RestResourceResolver */ + public Object resolve(Class<?> c, RestConfig config) throws RestServletException { + try { + Constructor<?> c1 = findPublicConstructor(c, RestConfig.class); + if (c1 != null) + return c1.newInstance(config); + c1 = findPublicConstructor(c); + if (c1 != null) + return c1.newInstance(); + } catch (Exception e) { + throw new RestServletException("Could not instantiate resource class ''{0}''", c.getName()).initCause(e); + } + throw new RestServletException("Could not find public constructor for class ''{0}''.", c); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java index 48473a9..025bb03 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/annotation/RestResource.java @@ -635,7 +635,7 @@ public @interface RestResource { * <br>The value (class or instance) can also be set via the servlet context attribute * * {@link RestContext#REST_resourceResolver}. */ - Class<? extends RestResourceResolver> resourceResolver() default RestResourceResolver.Default.class; + Class<? extends RestResourceResolver> resourceResolver() default RestResourceResolverSimple.class; /** * Specifies the logger class to use for logging. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java index 42e9b70..aac9172 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java @@ -15,6 +15,7 @@ package org.apache.juneau.rest.response; import static javax.servlet.http.HttpServletResponse.*; import java.io.*; +import java.util.*; import org.apache.juneau.*; import org.apache.juneau.annotation.*; @@ -49,43 +50,35 @@ public class DefaultHandler implements ResponseHandler { if (mediaType == null) mediaType = sm.getMediaType(); res.setContentType(mediaType.toString()); - ObjectMap headers = s.getResponseHeaders(res.getProperties()); - if (headers != null) - for (String key : headers.keySet()) - res.setHeader(key, headers.getString(key)); try { ObjectMap p = res.getProperties(); if (req.isPlainText()) { - p.put(SerializerContext.SERIALIZER_useWhitespace, true); res.setContentType("text/plain"); } p.append("mediaType", mediaType).append("characterEncoding", res.getCharacterEncoding()); - if (! s.isWriterSerializer()) { + + SerializerSession session = s.createSession(new SerializerSessionArgs(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.getUriContext())); + + for (Map.Entry<String,String> h : session.getResponseHeaders().entrySet()) + res.setHeader(h.getKey(), h.getValue()); + + if (! session.isWriterSerializer()) { if (req.isPlainText()) { - OutputStreamSerializer s2 = (OutputStreamSerializer)s; Writer w = res.getNegotiatedWriter(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); - SerializerOutput sout = new SerializerOutput(baos); - SerializerSession session = s.createSession(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.getUriContext()); - s2.serialize(session, sout, output); + session.serialize(baos, output); w.write(StringUtils.toHex(baos.toByteArray())); - w.close(); + w.close(); // Leave open if exception occurs. } else { - OutputStreamSerializer s2 = (OutputStreamSerializer)s; OutputStream os = res.getNegotiatedOutputStream(); - SerializerOutput sout = new SerializerOutput(os); - SerializerSession session = s.createSession(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.getUriContext()); - s2.serialize(session, sout, output); - os.close(); + session.serialize(os, output); + os.close(); // Leave open if exception occurs. } } else { - WriterSerializer s2 = (WriterSerializer)s; Writer w = res.getNegotiatedWriter(); - SerializerOutput sout = new SerializerOutput(w); - SerializerSession session = s.createSession(p, req.getJavaMethod(), req.getLocale(), req.getHeaders().getTimeZone(), mediaType, req.getUriContext()); - s2.serialize(session, sout, output); - w.close(); + session.serialize(w, output); + w.close(); // Leave open if exception occurs. } } catch (SerializeException e) { throw new RestException(SC_INTERNAL_SERVER_ERROR, e); http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java index 66c773e..a3962e2 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/FileVar.java @@ -63,10 +63,7 @@ import org.apache.juneau.utils.*; */ public class FileVar extends DefaultingVar { - /** - * The name of the session or context object that identifies the {@link RestRequest} object. - */ - public static final String SESSION_req = "req"; + private static final String SESSION_req = "req"; /** * The name of this variable. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java index 550a57e..a90d28d 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/RequestVar.java @@ -23,7 +23,7 @@ import org.apache.juneau.svl.*; * * <p> * The format for this var is <js>"$R{key[,defaultValue]}"</js>. - * + * * <p> * The possible values are: * <ul> @@ -63,6 +63,7 @@ public class RequestVar extends DefaultingVar { */ public static final String SESSION_req = "req"; + /** The name of this variable. */ public static final String NAME = "R"; http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java index 12fa846..365d48e 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/UrlVar.java @@ -42,10 +42,7 @@ import org.apache.juneau.svl.*; */ public class UrlVar extends SimpleVar { - /** - * The name of the session or context object that identifies the {@link RestRequest} object. - */ - public static final String SESSION_req = "req"; + private static final String SESSION_req = "req"; /** The name of this variable. */ public static final String NAME = "U"; http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java index 1b11155..2c3516c 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/vars/WidgetVar.java @@ -40,7 +40,7 @@ public class WidgetVar extends SimpleVar { /** * The name of the session or context object that identifies the {@link RestRequest} object. */ - public static final String SESSION_req = "req"; + private static final String SESSION_req = "req"; /** * The name of this variable. http://git-wip-us.apache.org/repos/asf/incubator-juneau/blob/2a37f310/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java ---------------------------------------------------------------------- diff --git a/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java b/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java index e65ca3f..3671573 100644 --- a/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java +++ b/juneau-rest/src/main/java/org/apache/juneau/rest/widget/MenuItemWidget.java @@ -17,6 +17,7 @@ import java.io.*; import org.apache.juneau.html.*; import org.apache.juneau.internal.*; import org.apache.juneau.rest.*; +import org.apache.juneau.serializer.*; /** * A subclass of widgets for rendering menu items with drop-down windows. @@ -78,15 +79,23 @@ public abstract class MenuItemWidget extends Widget { sb.append("" + "<div class='menu-item'>" + "\n\t<a class='link' onclick='menuClick(this)'>"+getLabel(req)+"</a>" - + "\n\t<div class='popup-content'>" + + "\n\t<div class='popup-content'>\n" ); Object o = getContent(req); if (o instanceof Reader) IOUtils.pipe((Reader)o, new StringBuilderWriter(sb)); else if (o instanceof CharSequence) sb.append((CharSequence)o); - else - HtmlSerializer.DEFAULT.serialize(getContent(req), sb); + else { + SerializerSessionArgs args = new SerializerSessionArgs(req.getProperties(), null, req.getLocale(), null, null, req.getUriContext()); + WriterSerializerSession session = HtmlSerializer.DEFAULT.createSession(args); + try { + session.indent = 2; + session.serialize(sb, o); + } finally { + session.close(); + } + } sb.append("" + "\n\t</div>" + "\n</div>" @@ -114,8 +123,8 @@ public abstract class MenuItemWidget extends Widget { * <li>{@link Reader} - Serialized directly to the output. * <li>{@link CharSequence} - Serialized directly to the output. * <li>Other - Serialized as HTML using {@link HtmlSerializer#DEFAULT}. + * <br>Note that this includes any of the {@link org.apache.juneau.dto.html5} beans. * </ul> - * Note that this includes any of the {@link org.apache.juneau.dto.html5} beans. * @throws Exception */ public abstract Object getContent(RestRequest req) throws Exception;
