2

The specific example I have in mind is javax.servlet.ServletResponseWrapper:

public class ServletResponseWrapper implements ServletResponse {
    private ServletResponse response;

    /**
     * The default behavior of this method is to call setCharacterEncoding(String charset)
     * on the wrapped response object.
     *
     * @since 2.4
     */
    public void setCharacterEncoding(String charset) {
    this.response.setCharacterEncoding(charset);
    }

    /**
     * The default behavior of this method is to return getCharacterEncoding()
     * on the wrapped response object.
     */
    public String getCharacterEncoding() {
    return this.response.getCharacterEncoding();
    }

     /**
     * The default behavior of this method is to return getOutputStream()
     * on the wrapped response object.
     */

    public ServletOutputStream getOutputStream() throws IOException {
    return this.response.getOutputStream();
    }  

   /** and so on **/
}

ServletResponseWrapper does nothing. It only passes execution to the nested object. So ServletResponseWrapper cannot function unless there is some other class (let's say ServletResponseConcrete) which also implements ServletResponse and does the real work.

In what context would you be able to use ServletResponseWrapper that you couldn't just use ServletResponseConcrete directly? This make absolutely no sense to me. I don't see how it's useful for subclassing either. If I subclass ServletResponseWrapper, then I have to implement every function anyways, so why not just create a class that implements ServletResponse directly?

0

3 Answers 3

4

If I subclass ServletResponseWrapper, then I have to implement every function anyways, so why not just create a class that implements ServletResponse directly?

This is not true. The whole idea of the class is, that one could use it as a base class to inherit from and just has to overwrite the method(s) that need to be changed. If you use the interface directly, you would have to implement all of the methods.

In what context would you be able to use ServletResponseWrapper that you couldn't just use ServletResponseConcrete directly?

One could provide a method that accepts a parameter of type ServletResponse or ServletResponseWrapper without knowing that there is a implementation called ServletResponseConcrete. Or maybe ServletResponseConcrete doesn't even exists yet. Still, you could later on implement ServletResponseConcrete or MyOtherServletResponse and hand it to that method.

This pattern is called "Delegation". Here is a simple example of an implementation that adds a System.out when setLocale is called:

import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper;
import java.util.Locale;

public class TimsServletResponse extends ServletResponseWrapper {

    public TimsServletResponse(ServletResponse response) {
        super(response);
    }

    @Override
    public void setLocale(Locale locale) {
        super.setLocale(locale);
        System.out.printf("setLocale was called (locale: %s)", locale);
    }
}

Create a Filter to make your application server use your wrapper like this:

import javax.servlet.*;
import java.io.IOException;

public class TimsFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) { }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        TimsServletResponse responseWrapper = new TimsServletResponse(response);
        chain.doFilter(request, responseWrapper);
    }

    @Override
    public void destroy() { }
}
8
  • The Wrapper class only passes execution to another instance. If MyWrapper sublcasses ServletResponseWrapper, but only implements one function, then there is still no concrete instance of all the other functions. In other words, you have to implement all functions no matter what. The only difference I see is that this wrapper class means that your compiler won't be able to let you know this, which is worse off. Commented Dec 15, 2015 at 15:35
  • let me give a concrete example to what the core of my confusion is. First (though this wouldn't be done), if I instantiate ServletResponseWrapper directly, what ServletResponse object do I pass in to do the real work? Or, let's say I create MyServletResponse which subclasses ServletResponseWrapper and only implements getCharacterEncoding function. Now I ask the same exact question, what ServletResponse object do I pass in to do the real work for the other functions? Commented Dec 15, 2015 at 15:41
  • As I understand, you are saying that I "can rely" on ServletResponseWrapper to implement the other functions. But it doesn't implement the other function. Read the actual code. The "base implementation" I would be relying on is doing nothing but relying on some other implmentation. To me, this is a recursive problem of depending on someone else to implement the function, but no class actually would in that case Commented Dec 15, 2015 at 15:43
  • ok. So (if I understand) you're saying that delegation can work, it just requires multiple classes to collectively implement all functions? Commented Dec 15, 2015 at 15:48
  • 1
    They are quite similar, yes. Check out this question: stackoverflow.com/questions/13389544/…
    – Tim Büthe
    Commented Dec 15, 2015 at 16:08
1

The example provided in the documentation is, strictly speaking, useless by design. If you follow the example you should have successfully implemented a wrapper class that has basically no meaningful effect on the system whatsoever. It should pass all proper tests, throw no weird errors, and cause no bizarre bugs.

However, if you follow the documentation you learn to create a proper wrapper class, and to hide the private implementation details that are unique to your systems. The example also shows a minimal default implementation of the ServletResponse interface, which would be handy if you needed a class that implemented this interface.

So why use something that doesn't do anything? Well, there is an implied Step 2 - make it do something useful that is specific to your system requirements. Maybe you only support certain character sets, or you always inject something into the ServletResponse, or you have some special write-behind handling when reset() is called.

As to why have both a wrapper and a concrete implementation, the wrapper basically does the minimum required to wrap the underlying object, and that's it. You then use the wrapper to code to the interface, while the concrete implementation is full of the system-specific implementation details that makes real world development messy and challenging.

The wrapper should be boring - the concrete implementation is where things get interesting. Yet if you need to swap out the implementation - such as as to support different platforms, architectures, environments, or particular applications - all you do is hand in a different Concrete class, and your wrapper won't complain or burden other systems to know about your classes at all. So long as they implement the right interface (which your wrapper does), they'll be happy.

This is very common in educational/documentation settings - the example given is the most minimal application of the concept, and it usually seems absolutely pointless. But once you know the use for something and the principles, then later the documentation serves as an excellent reference to implement the simplest thing possible that lets you start working on the tough bits.

0

The key utility of this class has to do with how you use it.

Yes, as written the class is useless. But it isn't meant to be used directly - its just something to pass through values. But what if you want to override one method there on top of the response you've got in your hand.

Well, you could create a new .java file that does everything you want it to.

Or, you could use an anonymous class.

Consider the code:

public ServletResponse filter() {
    ServletResponse resp = something();
    /* I don't care, I  always want it to be 'UTF-8' */
    return new ServletResponseWrapper(resp) {
        @override
        public String getCharacterEncoding() {
          return "UTF-8";
        }
    };
}

Granted, this is a trivial one that could have been done by calling a setter in the response itself, but you get the idea of what it could be used for.

And there you have a very nice and concise bit of code that uses the ServletResponseWrapper. While the wrapper is useless as is, it facilitates other code that is not useless. The alternative code to this is significantly more verbose and the essential information about what it does may be lost in that verbosity.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.