You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ff...@apache.org on 2017/10/20 02:04:48 UTC

[cxf] branch 3.1.x-fixes updated (d5dd85e -> 7785fa6)

This is an automated email from the ASF dual-hosted git repository.

ffang pushed a change to branch 3.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git.


    from d5dd85e  Removing unused code in JAXBUtils, spotted by Colm
     new 59235d7  [CXF-7532]REST on JMS transport can't handle the request message with text messageType
     new 7785fa6  [CXF-7532]some clean up

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../java/org/apache/cxf/io/ReaderInputStream.java  | 296 +++++++++++++++++++++
 .../org/apache/cxf/jaxrs/impl/ResponseImpl.java    |   7 +
 .../org/apache/cxf/jaxrs/utils/JAXRSUtils.java     |   8 +-
 .../apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java |  90 ++++++-
 4 files changed, 399 insertions(+), 2 deletions(-)
 create mode 100644 core/src/main/java/org/apache/cxf/io/ReaderInputStream.java

-- 
To stop receiving notification emails like this one, please contact
['"commits@cxf.apache.org" <co...@cxf.apache.org>'].

[cxf] 01/02: [CXF-7532]REST on JMS transport can't handle the request message with text messageType

Posted by ff...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ffang pushed a commit to branch 3.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 59235d7eda4393c1c26ad9609c9cb97fdfe58acf
Author: Freeman Fang <fr...@gmail.com>
AuthorDate: Thu Oct 19 11:15:50 2017 +0800

    [CXF-7532]REST on JMS transport can't handle the request message with text messageType
    
    (cherry picked from commit 1d66475b4dea2a0031dcb1765e8e9fd08430ec9b)
    
    Conflicts:
    	systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java
---
 .../org/apache/cxf/jaxrs/impl/ResponseImpl.java    |   5 +
 .../org/apache/cxf/jaxrs/utils/JAXRSUtils.java     |   6 +-
 .../apache/cxf/jaxrs/utils/ReaderInputStream.java  | 296 +++++++++++++++++++++
 .../apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java |  90 ++++++-
 4 files changed, 395 insertions(+), 2 deletions(-)

diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
index fa56e9f..61b0b14 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
@@ -58,6 +58,7 @@ import org.apache.cxf.jaxrs.provider.ProviderFactory;
 import org.apache.cxf.jaxrs.utils.HttpUtils;
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.jaxrs.utils.ReaderInputStream;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 
@@ -352,6 +353,10 @@ public final class ResponseImpl extends Response {
             entityStreamAvailable = entityStream != null;
         } else if (entity instanceof InputStream) {
             entityStream = InputStream.class.cast(entity);
+        } else {
+            Message inMessage = getResponseMessage();
+            Reader reader = inMessage.getContent(Reader.class);
+            entityStream = InputStream.class.cast(new ReaderInputStream(reader));
         }
         
         // we need to check for readers even if no IS is set - the readers may still do it
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
index 27b0d8f..173ae80 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
@@ -833,7 +833,11 @@ public final class JAXRSUtils {
                                            OperationResourceInfo ori) 
         throws IOException, WebApplicationException {
         InputStream is = message.getContent(InputStream.class);
-
+        if (is == null) {
+            //may use the jms transport so check the Reader;
+            Reader reader = message.getContent(Reader.class);
+            is = new ReaderInputStream(reader);
+        }
         if (parameter.getType() == ParameterType.REQUEST_BODY) {
             
             if (parameterClass == AsyncResponse.class) {
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java
new file mode 100644
index 0000000..c7b142e
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java
@@ -0,0 +1,296 @@
+/**
+ * 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.cxf.jaxrs.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.nio.charset.CodingErrorAction;
+
+/**
+ * {@link InputStream} implementation that reads a character stream from a {@link Reader}
+ * and transforms it to a byte stream using a specified charset encoding. The stream
+ * is transformed using a {@link CharsetEncoder} object, guaranteeing that all charset
+ * encodings supported by the JRE are handled correctly. In particular for charsets such as
+ * UTF-16, the implementation ensures that one and only one byte order marker
+ * is produced.
+ * <p>
+ * Since in general it is not possible to predict the number of characters to be read from the
+ * {@link Reader} to satisfy a read request on the {@link ReaderInputStream}, all reads from
+ * the {@link Reader} are buffered. There is therefore no well defined correlation
+ * between the current position of the {@link Reader} and that of the {@link ReaderInputStream}.
+ * This also implies that in general there is no need to wrap the underlying {@link Reader}
+ * in a {@link java.io.BufferedReader}.
+ * <p>
+ * {@link ReaderInputStream} implements the inverse transformation of {@link java.io.InputStreamReader};
+ * in the following example, reading from <tt>in2</tt> would return the same byte
+ * sequence as reading from <tt>in</tt> (provided that the initial byte sequence is legal
+ * with respect to the charset encoding):
+ * <pre>
+ * InputStream in = ...
+ * Charset cs = ...
+ * InputStreamReader reader = new InputStreamReader(in, cs);
+ * ReaderInputStream in2 = new ReaderInputStream(reader, cs);</pre>
+ * {@link ReaderInputStream} implements the same transformation as {@link java.io.OutputStreamWriter},
+ * except that the control flow is reversed: both classes transform a character stream
+ * into a byte stream, but {@link java.io.OutputStreamWriter} pushes data to the underlying stream,
+ * while {@link ReaderInputStream} pulls it from the underlying stream.
+ * <p>
+ * Note that while there are use cases where there is no alternative to using
+ * this class, very often the need to use this class is an indication of a flaw
+ * in the design of the code. This class is typically used in situations where an existing
+ * API only accepts an {@link InputStream}, but where the most natural way to produce the data
+ * is as a character stream, i.e. by providing a {@link Reader} instance. An example of a situation
+ * where this problem may appear is when implementing the {@link javax.activation.DataSource}
+ * interface from the Java Activation Framework.
+ * <p>
+ * Given the fact that the {@link Reader} class doesn't provide any way to predict whether the next
+ * read operation will block or not, it is not possible to provide a meaningful
+ * implementation of the {@link InputStream#available()} method. A call to this method
+ * will always return 0. Also, this class doesn't support {@link InputStream#mark(int)}.
+ * <p>
+ * Instances of {@link ReaderInputStream} are not thread safe.
+ * 
+ * @see org.apache.commons.io.output.WriterOutputStream
+ * 
+ * @since 2.0
+ */
+public class ReaderInputStream extends InputStream {
+    private static final int DEFAULT_BUFFER_SIZE = 1024;
+
+    private final Reader reader;
+    private final CharsetEncoder encoder;
+
+    /**
+     * CharBuffer used as input for the decoder. It should be reasonably
+     * large as we read data from the underlying Reader into this buffer.
+     */
+    private final CharBuffer encoderIn;
+
+    /**
+     * ByteBuffer used as output for the decoder. This buffer can be small
+     * as it is only used to transfer data from the decoder to the
+     * buffer provided by the caller.
+     */
+    private final ByteBuffer encoderOut;
+
+    private CoderResult lastCoderResult;
+    private boolean endOfInput;
+
+    /**
+     * Construct a new {@link ReaderInputStream}.
+     * 
+     * @param reader the target {@link Reader}
+     * @param encoder the charset encoder
+     * @since 2.1
+     */
+    public ReaderInputStream(Reader reader, CharsetEncoder encoder) {
+        this(reader, encoder, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream}.
+     * 
+     * @param reader the target {@link Reader}
+     * @param encoder the charset encoder
+     * @param bufferSize the size of the input buffer in number of characters
+     * @since 2.1
+     */
+    public ReaderInputStream(Reader reader, CharsetEncoder encoder, int bufferSize) {
+        this.reader = reader;
+        this.encoder = encoder;
+        this.encoderIn = CharBuffer.allocate(bufferSize);
+        this.encoderIn.flip();
+        this.encoderOut = ByteBuffer.allocate(128);
+        this.encoderOut.flip();
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream}.
+     * 
+     * @param reader the target {@link Reader}
+     * @param charset the charset encoding
+     * @param bufferSize the size of the input buffer in number of characters
+     */
+    public ReaderInputStream(Reader reader, Charset charset, int bufferSize) {
+        this(reader,
+             charset.newEncoder()
+                    .onMalformedInput(CodingErrorAction.REPLACE)
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE),
+             bufferSize);
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream} with a default input buffer size of
+     * 1024 characters.
+     * 
+     * @param reader the target {@link Reader}
+     * @param charset the charset encoding
+     */
+    public ReaderInputStream(Reader reader, Charset charset) {
+        this(reader, charset, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream}.
+     * 
+     * @param reader the target {@link Reader}
+     * @param charsetName the name of the charset encoding
+     * @param bufferSize the size of the input buffer in number of characters
+     */
+    public ReaderInputStream(Reader reader, String charsetName, int bufferSize) {
+        this(reader, Charset.forName(charsetName), bufferSize);
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream} with a default input buffer size of
+     * 1024 characters.
+     * 
+     * @param reader the target {@link Reader}
+     * @param charsetName the name of the charset encoding
+     */
+    public ReaderInputStream(Reader reader, String charsetName) {
+        this(reader, charsetName, DEFAULT_BUFFER_SIZE);
+    }
+
+    /**
+     * Construct a new {@link ReaderInputStream} that uses the default character encoding
+     * with a default input buffer size of 1024 characters.
+     * 
+     * @param reader the target {@link Reader}
+     */
+    public ReaderInputStream(Reader reader) {
+        this(reader, Charset.defaultCharset());
+    }
+
+    /**
+     * Fills the internal char buffer from the reader.
+     * 
+     * @throws IOException
+     *             If an I/O error occurs
+     */
+    private void fillBuffer() throws IOException {
+        if (!endOfInput && (lastCoderResult == null || lastCoderResult.isUnderflow())) {
+            encoderIn.compact();
+            int position = encoderIn.position();
+            // We don't use Reader#read(CharBuffer) here because it is more efficient
+            // to write directly to the underlying char array (the default implementation
+            // copies data to a temporary char array).
+            int c = reader.read(encoderIn.array(), position, encoderIn.remaining());
+            if (c == -1) {
+                endOfInput = true;
+            } else {
+                encoderIn.position(position + c);
+            }
+            encoderIn.flip();
+        }
+        encoderOut.compact();
+        lastCoderResult = encoder.encode(encoderIn, encoderOut, endOfInput);
+        encoderOut.flip();
+    }
+    
+    /**
+     * Read the specified number of bytes into an array.
+     * 
+     * @param b the byte array to read into
+     * @param off the offset to start reading bytes into
+     * @param len the number of bytes to read
+     * @return the number of bytes read or <code>-1</code>
+     *         if the end of the stream has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+        if (b == null) {
+            throw new NullPointerException("Byte array must not be null");
+        }
+        if (len < 0 || off < 0 || (off + len) > b.length) {
+            throw new IndexOutOfBoundsException("Array Size=" + b.length 
+                    + ", offset=" + off + ", length=" + len);
+        }
+        int read = 0;
+        if (len == 0) {
+            return 0; // Always return 0 if len == 0
+        }
+        while (len > 0) {
+            if (encoderOut.hasRemaining()) {
+                int c = Math.min(encoderOut.remaining(), len);
+                encoderOut.get(b, off, c);
+                off += c;
+                len -= c;
+                read += c;
+            } else {
+                fillBuffer();
+                if (endOfInput && !encoderOut.hasRemaining()) {
+                    break;
+                }
+            }
+        }
+        return read == 0 && endOfInput ? -1 : read;
+    }
+
+    /**
+     * Read the specified number of bytes into an array.
+     * 
+     * @param b the byte array to read into
+     * @return the number of bytes read or <code>-1</code>
+     *         if the end of the stream has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read(byte[] b) throws IOException {
+        return read(b, 0, b.length);
+    }
+
+    /**
+     * Read a single byte.
+     *
+     * @return either the byte read or <code>-1</code> if the end of the stream
+     *         has been reached
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public int read() throws IOException {
+        for (;;) {
+            if (encoderOut.hasRemaining()) {
+                return encoderOut.get() & 0xFF;
+            } else {
+                fillBuffer();
+                if (endOfInput && !encoderOut.hasRemaining()) {
+                    return -1;
+                }
+            }
+        }
+    }
+
+    /**
+     * Close the stream. This method will cause the underlying {@link Reader}
+     * to be closed.
+     * @throws IOException if an I/O error occurs
+     */
+    @Override
+    public void close() throws IOException {
+        reader.close();
+    }
+}
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java
index 95d29e6..a1b9da0 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/jms/JAXRSJmsTest.java
@@ -98,6 +98,25 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
     }
     
     @Test
+    public void testGetBookFromWebClientWithTextJMSMessage() throws Exception {
+        // setup the the client
+        String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
+             + "?replyToName=dynamicQueues/test.jmstransport.response"
+             + "&jndiInitialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+             + "&jndiURL=tcp://localhost:" + JMS_PORT
+             + "&messageType=text";
+
+        WebClient client = WebClient.create(endpointAddressUrlEncoded);
+        WebClient.getConfig(client).getInInterceptors().add(new LoggingInInterceptor());
+        WebClient.getConfig(client).getRequestContext()
+            .put(org.apache.cxf.message.Message.REQUEST_URI, "/bookstore/books/123");
+
+        Book book = client.get(Book.class);
+        assertEquals("Get a wrong response code.", 200, client.getResponse().getStatus());
+        assertEquals("Get a wrong book id.", 123, book.getId());
+    }
+
+    @Test
     public void testPutBookOneWayWithWebClient() throws Exception {
         // setup the the client
         String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
@@ -136,7 +155,6 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
             }
         }
     }
-    
     @Test
     public void testGetBookFromWebClientWithPath() throws Exception {
         // setup the the client
@@ -155,6 +173,25 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
     }
     
     @Test
+    public void testGetBookFromWebClientWithPathWithTextJMSMessage() throws Exception {
+        // setup the the client
+        String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
+             + "?jndiInitialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+             + "&replyToName=dynamicQueues/test.jmstransport.response"
+             + "&jndiURL=tcp://localhost:" + JMS_PORT
+             + "&jndiConnectionFactoryName=ConnectionFactory"
+             + "&messageType=text";
+
+        WebClient client = WebClient.create(endpointAddressUrlEncoded);
+        client.path("bookstore").path("books").path("123");
+
+        Book book = client.get(Book.class);
+        assertEquals("Get a wrong response code.", 200, client.getResponse().getStatus());
+        assertEquals("Get a wrong book id.", 123, book.getId());
+    }
+
+    
+    @Test
     public void testGetBookFromProxyClient() throws Exception {
         // setup the the client
         String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
@@ -170,6 +207,22 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
     }
     
     @Test
+    public void testGetBookFromProxyClientWithTextJMSMessage() throws Exception {
+        // setup the the client
+        String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
+             + "?jndiInitialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+             + "&replyToName=dynamicQueues/test.jmstransport.response"
+             + "&jndiURL=tcp://localhost:" + JMS_PORT
+             + "&jndiConnectionFactoryName=ConnectionFactory" 
+             + "&messageType=text";
+
+        JMSBookStore client = JAXRSClientFactory.create(endpointAddressUrlEncoded, JMSBookStore.class);
+        Book book = client.getBook("123");
+        assertEquals("Get a wrong response code.", 200, WebClient.client(client).getResponse().getStatus());
+        assertEquals("Get a wrong book id.", 123, book.getId());
+    }
+
+    @Test
     public void testGetBookFromSubresourceProxyClient() throws Exception {
         // setup the the client
         String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
@@ -186,6 +239,23 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
     }
     
     @Test
+    public void testGetBookFromSubresourceProxyClientWithTextJMSMessage() throws Exception {
+        // setup the the client
+        String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
+             + "?jndiInitialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+             + "&replyToName=dynamicQueues/test.jmstransport.response"
+             + "&jndiURL=tcp://localhost:" + JMS_PORT
+             + "&jndiConnectionFactoryName=ConnectionFactory"
+             + "&messageType=text";
+
+        JMSBookStore client = JAXRSClientFactory.create(endpointAddressUrlEncoded, JMSBookStore.class);
+        Book bookProxy = client.getBookSubResource("123");
+        Book book = bookProxy.retrieveState();
+        assertEquals("Get a wrong response code.", 200, WebClient.client(bookProxy).getResponse().getStatus());
+        assertEquals("Get a wrong book id.", 123, book.getId());
+    }
+
+    @Test
     public void testGetBookFromProxyClientWithQuery() throws Exception {
         // setup the the client
         String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
@@ -199,6 +269,24 @@ public class JAXRSJmsTest extends AbstractBusClientServerTestBase {
         assertEquals("Get a wrong response code.", 200, WebClient.client(client).getResponse().getStatus());
         assertEquals("Get a wrong book id.", 123, book.getId());
     }
+
+    
+    @Test
+    public void testGetBookFromProxyClientWithQueryWithTextJMSMessage() throws Exception {
+        // setup the the client
+        String endpointAddressUrlEncoded = "jms:jndi:dynamicQueues/test.jmstransport.text"
+             + "?jndiInitialContextFactory=org.apache.activemq.jndi.ActiveMQInitialContextFactory"
+             + "&replyToName=dynamicQueues/test.jmstransport.response"
+             + "&jndiURL=tcp://localhost:" + JMS_PORT
+             + "&jndiConnectionFactoryName=ConnectionFactory"
+             + "&messageType=text";
+
+        JMSBookStore client = JAXRSClientFactory.create(endpointAddressUrlEncoded, JMSBookStore.class);
+        Book book = client.getBookByURLQuery(new String[] {"1", "2", "3"});
+        assertEquals("Get a wrong response code.", 200, WebClient.client(client).getResponse().getStatus());
+        assertEquals("Get a wrong book id.", 123, book.getId());
+    }
+
     
     @Test
     public void testGetBook() throws Exception {

-- 
To stop receiving notification emails like this one, please contact
"commits@cxf.apache.org" <co...@cxf.apache.org>.

[cxf] 02/02: [CXF-7532]some clean up

Posted by ff...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ffang pushed a commit to branch 3.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 7785fa66801dc534634f6c0e1f34d954c68fd8bd
Author: Freeman Fang <fr...@gmail.com>
AuthorDate: Fri Oct 20 09:25:04 2017 +0800

    [CXF-7532]some clean up
    
    (cherry picked from commit 2201d34986f6657cb3262e8c042cd440a1f89bb0)
---
 .../src/main/java/org/apache/cxf/io}/ReaderInputStream.java         | 2 +-
 .../jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java | 6 ++++--
 .../jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java  | 6 ++++--
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java b/core/src/main/java/org/apache/cxf/io/ReaderInputStream.java
similarity index 99%
rename from rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java
rename to core/src/main/java/org/apache/cxf/io/ReaderInputStream.java
index c7b142e..dd4c533 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/ReaderInputStream.java
+++ b/core/src/main/java/org/apache/cxf/io/ReaderInputStream.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.cxf.jaxrs.utils;
+package org.apache.cxf.io;
 
 import java.io.IOException;
 import java.io.InputStream;
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
index 61b0b14..0300b18 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/impl/ResponseImpl.java
@@ -54,11 +54,11 @@ import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
 import javax.xml.stream.XMLStreamReader;
 
 import org.apache.cxf.helpers.IOUtils;
+import org.apache.cxf.io.ReaderInputStream;
 import org.apache.cxf.jaxrs.provider.ProviderFactory;
 import org.apache.cxf.jaxrs.utils.HttpUtils;
 import org.apache.cxf.jaxrs.utils.InjectionUtils;
 import org.apache.cxf.jaxrs.utils.JAXRSUtils;
-import org.apache.cxf.jaxrs.utils.ReaderInputStream;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 
@@ -356,7 +356,9 @@ public final class ResponseImpl extends Response {
         } else {
             Message inMessage = getResponseMessage();
             Reader reader = inMessage.getContent(Reader.class);
-            entityStream = InputStream.class.cast(new ReaderInputStream(reader));
+            if (reader != null) {
+                entityStream = InputStream.class.cast(new ReaderInputStream(reader));
+            }
         }
         
         // we need to check for readers even if no IS is set - the readers may still do it
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
index 173ae80..eb5bba9 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/JAXRSUtils.java
@@ -89,6 +89,7 @@ import org.apache.cxf.common.util.ReflectionUtil;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.helpers.DOMUtils;
 import org.apache.cxf.interceptor.Fault;
+import org.apache.cxf.io.ReaderInputStream;
 import org.apache.cxf.jaxrs.JAXRSServiceImpl;
 import org.apache.cxf.jaxrs.ext.ContextProvider;
 import org.apache.cxf.jaxrs.ext.DefaultMethod;
@@ -834,9 +835,10 @@ public final class JAXRSUtils {
         throws IOException, WebApplicationException {
         InputStream is = message.getContent(InputStream.class);
         if (is == null) {
-            //may use the jms transport so check the Reader;
             Reader reader = message.getContent(Reader.class);
-            is = new ReaderInputStream(reader);
+            if (reader != null) {
+                is = new ReaderInputStream(reader);
+            }
         }
         if (parameter.getType() == ParameterType.REQUEST_BODY) {
             

-- 
To stop receiving notification emails like this one, please contact
"commits@cxf.apache.org" <co...@cxf.apache.org>.