[ 
https://issues.apache.org/jira/browse/CXF-3148?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Dobes Vandermeer updated CXF-3148:
----------------------------------

    Description: 
In 
org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollection(Class<?>, 
Object, Class<?>, Type, String, OutputStream, MediaType), it converts the 
resulting collection into an array before serializing it.

Unfortunately, this prevents us from using a collection that lazily loads its 
contents from the DB as it goes, since toArray() would require us to create and 
return all the results immediately.

Ideally this method would be changed to operate in a manner that is "friendly" 
to lazy collections, by only using the collection's iterator (once).

This version iterates over the collection only once, which would be the most 
efficient for collections that are backed by out of memory storage:

{code}
        protected void marshalCollection(Class<?> originalCls, Object 
actualObject, Class<?> actualClass, Type genericType, String encoding,
                        OutputStream os, MediaType m) throws Exception {

                Collection c = originalCls.isArray() ? Arrays.asList((Object[]) 
actualObject) : (Collection) actualObject;
                
                Iterator it = c.iterator();
                
                boolean empty = false == it.hasNext();
                Object firstObj = empty?null:it.next();
                QName qname = null;
                if (firstObj instanceof JAXBElement) {
                        JAXBElement el = (JAXBElement) firstObj;
                        qname = el.getName();
                        actualClass = el.getDeclaredType();
                } else {
                        qname = getCollectionWrapperQName(actualClass, 
genericType, actualObject, true);
                }
                if (qname == null) {
                        String message = new 
org.apache.cxf.common.i18n.Message("NO_COLLECTION_ROOT", BUNDLE).toString();
                        throw new 
WebApplicationException(Response.serverError().entity(message).build());
                }

                String startTag = null;
                String endTag = null;
                if (qname.getNamespaceURI().length() > 0) {
                        startTag = "<ns1:" + qname.getLocalPart() + " 
xmlns:ns1=\"" + qname.getNamespaceURI() + "\">";
                        endTag = "</ns1:" + qname.getLocalPart() + ">";
                } else {
                        startTag = "<" + qname.getLocalPart() + ">";
                        endTag = "</" + qname.getLocalPart() + ">";
                }
                os.write(startTag.getBytes());
                if(!empty) {
                        marshalCollectionMember(firstObj instanceof JAXBElement 
? ((JAXBElement) firstObj).getValue() : firstObj, actualClass, genericType, 
encoding, os, m, qname
                                        .getNamespaceURI());
                        while (it.hasNext()) {
                                Object o = it.next();
                                marshalCollectionMember(o instanceof 
JAXBElement ? ((JAXBElement) o).getValue() : firstObj, actualClass, 
genericType, encoding, os, m, qname
                                                .getNamespaceURI());
                        }
                }
                os.write(endTag.getBytes());
        }
{code}


  was:
In 
org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollection(Class<?>, 
Object, Class<?>, Type, String, OutputStream, MediaType), it converts the 
resulting collection into an array before serializing it.

Unfortunately, this prevents us from using a collection that lazily loads its 
contents from the DB as it goes, since toArray() would require us to create and 
return all the results immediately.

Ideally this method would be changed to operate in a manner that is "friendly" 
to lazy collections, by only using the collection's iterator (once).

This version iterates over the collection only once, which would be the most 
efficient for collections that are backed by out of memory storage:

{code}
        protected void marshalCollection(Class<?> originalCls, Object 
actualObject, Class<?> actualClass, Type genericType, String encoding,
                        OutputStream os, MediaType m) throws Exception {

                Collection c = originalCls.isArray() ? Arrays.asList((Object[]) 
actualObject) : (Collection) actualObject;
                
                Iterator it = c.iterator();
                
                boolean empty = false == it.hasNext();
                Object firstObj = empty?null:it.next();
                QName qname = null;
                if (firstObj instanceof JAXBElement) {
                        JAXBElement el = (JAXBElement) firstObj;
                        qname = el.getName();
                        actualClass = el.getDeclaredType();
                } else {
                        qname = getCollectionWrapperQName(actualClass, 
genericType, actualObject, true);
                }
                if (qname == null) {
                        String message = new 
org.apache.cxf.common.i18n.Message("NO_COLLECTION_ROOT", BUNDLE).toString();
                        throw new 
WebApplicationException(Response.serverError().entity(message).build());
                }

                String startTag = null;
                String endTag = null;
                if (qname.getNamespaceURI().length() > 0) {
                        startTag = "<ns1:" + qname.getLocalPart() + " 
xmlns:ns1=\"" + qname.getNamespaceURI() + "\">";
                        endTag = "</ns1:" + qname.getLocalPart() + ">";
                } else {
                        startTag = "<" + qname.getLocalPart() + ">";
                        endTag = "</" + qname.getLocalPart() + ">";
                }
                os.write(startTag.getBytes());
                marshalCollectionMember(firstObj instanceof JAXBElement ? 
((JAXBElement) firstObj).getValue() : firstObj, actualClass, genericType, 
encoding, os, m, qname
                                .getNamespaceURI());
                while (it.hasNext()) {
                        Object o = it.next();
                        marshalCollectionMember(o instanceof JAXBElement ? 
((JAXBElement) o).getValue() : firstObj, actualClass, genericType, encoding, 
os, m, qname
                                        .getNamespaceURI());
                }
                os.write(endTag.getBytes());
        }
{code}



> CXF converts collections to arrays during serialization
> -------------------------------------------------------
>
>                 Key: CXF-3148
>                 URL: https://issues.apache.org/jira/browse/CXF-3148
>             Project: CXF
>          Issue Type: Bug
>    Affects Versions: 2.3.0
>            Reporter: Dobes Vandermeer
>
> In 
> org.apache.cxf.jaxrs.provider.JAXBElementProvider.marshalCollection(Class<?>, 
> Object, Class<?>, Type, String, OutputStream, MediaType), it converts the 
> resulting collection into an array before serializing it.
> Unfortunately, this prevents us from using a collection that lazily loads its 
> contents from the DB as it goes, since toArray() would require us to create 
> and return all the results immediately.
> Ideally this method would be changed to operate in a manner that is 
> "friendly" to lazy collections, by only using the collection's iterator 
> (once).
> This version iterates over the collection only once, which would be the most 
> efficient for collections that are backed by out of memory storage:
> {code}
>       protected void marshalCollection(Class<?> originalCls, Object 
> actualObject, Class<?> actualClass, Type genericType, String encoding,
>                       OutputStream os, MediaType m) throws Exception {
>               Collection c = originalCls.isArray() ? Arrays.asList((Object[]) 
> actualObject) : (Collection) actualObject;
>               
>               Iterator it = c.iterator();
>               
>               boolean empty = false == it.hasNext();
>               Object firstObj = empty?null:it.next();
>               QName qname = null;
>               if (firstObj instanceof JAXBElement) {
>                       JAXBElement el = (JAXBElement) firstObj;
>                       qname = el.getName();
>                       actualClass = el.getDeclaredType();
>               } else {
>                       qname = getCollectionWrapperQName(actualClass, 
> genericType, actualObject, true);
>               }
>               if (qname == null) {
>                       String message = new 
> org.apache.cxf.common.i18n.Message("NO_COLLECTION_ROOT", BUNDLE).toString();
>                       throw new 
> WebApplicationException(Response.serverError().entity(message).build());
>               }
>               String startTag = null;
>               String endTag = null;
>               if (qname.getNamespaceURI().length() > 0) {
>                       startTag = "<ns1:" + qname.getLocalPart() + " 
> xmlns:ns1=\"" + qname.getNamespaceURI() + "\">";
>                       endTag = "</ns1:" + qname.getLocalPart() + ">";
>               } else {
>                       startTag = "<" + qname.getLocalPart() + ">";
>                       endTag = "</" + qname.getLocalPart() + ">";
>               }
>               os.write(startTag.getBytes());
>               if(!empty) {
>                       marshalCollectionMember(firstObj instanceof JAXBElement 
> ? ((JAXBElement) firstObj).getValue() : firstObj, actualClass, genericType, 
> encoding, os, m, qname
>                                       .getNamespaceURI());
>                       while (it.hasNext()) {
>                               Object o = it.next();
>                               marshalCollectionMember(o instanceof 
> JAXBElement ? ((JAXBElement) o).getValue() : firstObj, actualClass, 
> genericType, encoding, os, m, qname
>                                               .getNamespaceURI());
>                       }
>               }
>               os.write(endTag.getBytes());
>       }
> {code}

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to