InputStream to servletInputStream

前端 未结 3 856
后悔当初
后悔当初 2020-12-19 00:50

I have this InputStream:

InputStream inputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));

How can I convert t

相关标签:
3条回答
  • 2020-12-19 01:19

    You can only cast something like this:

    ServletInputStream  servletInputStream = (ServletInputStream) inputStream;
    

    if the inputStream you are trying to cast is actually a ServletInputStream already. It will complain if it's some other implementation of InputStream. You can't cast an object to something it isn't.

    In a Servlet container, you can get a ServletInputStream from a ServletRequest:

    ServletInputStream  servletInputStream = request.getInputStream();
    

    So, what are you actually trying to do?

    EDIT

    I'm intrigued as to why you want to convert your request to lower-case - why not just make your servlet case-insensitive? In other words, your code to lower-case the request data can be copied into your servlet, then it can process it there... always look for the simplest solution!

    0 讨论(0)
  • 2020-12-19 01:37

    My advice: don't create the ByteArrayInputStream, just use the byte array you got from the getBytes method already. This should be enough to create a ServletInputStream.

    Most basic solution

    Unfortunately, aksappy's answer only overrides the read method. While this may be enough in Servlet API 3.0 and below, in the later versions of Servlet API there are three more methods you have to implement.

    Here is my implementation of the class, although with it becoming quite long (due to the new methods introduced in Servlet API 3.1), you might want to think about factoring it out into a nested or even top-level class.

        final byte[] myBytes = myString.getBytes("UTF-8");
        ServletInputStream servletInputStream = new ServletInputStream() {
            private int lastIndexRetrieved = -1;
            private ReadListener readListener = null;
    
            @Override
            public boolean isFinished() {
                return (lastIndexRetrieved == myBytes.length-1);
            }
    
            @Override
            public boolean isReady() {
                // This implementation will never block
                // We also never need to call the readListener from this method, as this method will never return false
                return isFinished();
            }
    
            @Override
            public void setReadListener(ReadListener readListener) {
                this.readListener = readListener;
                if (!isFinished()) {
                    try {
                        readListener.onDataAvailable();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                } else {
                    try {
                        readListener.onAllDataRead();
                    } catch (IOException e) {
                        readListener.onError(e);
                    }
                }
            }
    
            @Override
            public int read() throws IOException {
                int i;
                if (!isFinished()) {
                    i = myBytes[lastIndexRetrieved+1];
                    lastIndexRetrieved++;
                    if (isFinished() && (readListener != null)) {
                        try {
                            readListener.onAllDataRead();
                        } catch (IOException ex) {
                            readListener.onError(ex);
                            throw ex;
                        }
                    }
                    return i;
                } else {
                    return -1;
                }
            }
        };
    

    Adding expected methods

    Depending on your requirements, you may also want to override other methods. As romfret pointed out, it's advisable to override some methods, such as close and available. If you don't implement them, the stream will always report that there are 0 bytes available to be read, and the close method will do nothing to affect the state of the stream. You can probably get away without overriding skip, as the default implementation will just call read a number of times.

        @Override
        public int available() throws IOException {
            return (myBytes.length-lastIndexRetrieved-1);
        }
    
        @Override
        public void close() throws IOException {
            lastIndexRetrieved = myBytes.length-1;
        }
    

    Writing a better close method

    Unfortunately, due to the nature of an anonymous class, it's going to be difficult for you to write an effective close method because as long as one instance of the stream has not been garbage-collected by Java, it maintains a reference to the byte array, even if the stream has been closed.

    However, if you factor out the class into a nested or top-level class (or even an anonymous class with a constructor which you call from the line in which it is defined), the myBytes can be a non-final field rather than a final local variable, and you can add a line like:

    myBytes = null;
    

    to your close method, which will allow Java to free memory taken up by the byte array.

    Of course, this will require you to write a constructor, such as:

        private byte[] myBytes;
    
        public StringServletInputStream(String str) {
            try {
                myBytes = str.getBytes("UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new IllegalStateException("JVM did not support UTF-8", e);
            }
        }
    

    Mark and Reset

    You may also want to override mark, markSupported and reset if you want to support mark/reset. I am not sure if they are ever actually called by your container though.

        private int readLimit = -1;
        private int markedPosition = -1;
    
        @Override
        public boolean markSupported() {
            return true;
        }
    
        @Override
        public synchronized void mark(int readLimit) {
            this.readLimit = readLimit;
            this.markedPosition = lastIndexRetrieved;
        }
    
        @Override
        public synchronized void reset() throws IOException {
            if (markedPosition == -1) {
                throw new IOException("No mark found");
            } else {
                lastIndexRetrieved = markedPosition;
                readLimit = -1;
            }
        }
    
        // Replacement of earlier read method to cope with readLimit
        @Override
        public int read() throws IOException {
            int i;
            if (!isFinished()) {
                i = myBytes[lastIndexRetrieved+1];
                lastIndexRetrieved++;
                if (isFinished() && (readListener != null)) {
                    try {
                        readListener.onAllDataRead();
                    } catch (IOException ex) {
                        readListener.onError(ex);
                        throw ex;
                    }
                    readLimit = -1;
                }
                if (readLimit != -1) {
                    if ((lastIndexRetrieved - markedPosition) > readLimit) {
                        // This part is actually not necessary in our implementation
                        // as we are not storing any data. However we need to respect
                        // the contract.
                        markedPosition = -1;
                        readLimit = -1;
                    }
                }
                return i;
            } else {
                return -1;
            }
        }
    
    0 讨论(0)
  • 2020-12-19 01:40

    Try this code.

    ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(myString.getBytes(StandardCharsets.UTF_8));
        ServletInputStream servletInputStream=new ServletInputStream(){
            public int read() throws IOException {
              return byteArrayInputStream.read();
            }
          }
    
    0 讨论(0)
提交回复
热议问题