【问题标题】:How do I get a subclass to use a parent class' protected methods?如何让子类使用父类的受保护方法?
【发布时间】:2011-10-09 08:46:21
【问题描述】:

我正在为 webapps 编写一个前端控制器 servlet 类。前端控制器旨在区分三种基本情况:

  1. 文件请求(调用FileRequestHandler 实例)
  2. 数据请求(调用DataRequestHandler 实例)
  3. Servlet 请求(调用ServletRequestHandler 实例)

为了测试,我想使用 Tomcat 的 DefaultServlet (javadoc,source code) 来提供文件,但我无法让它工作。问题是,即使我的FileRequestHandler 类应该正确扩展DefaultServlet,我也无法访问其受保护的方法(特别是doGet 用于处理GET 请求)。顺便说一句,这些类位于不同的包中。


代码:

public class FileRequestHandler extends DefaultServlet {

// fields

    private static final long serialVersionUID = 1L;

// methods

    public void setResponse(HttpServletRequest request , HttpServletResponse response, URI uri) 
            throws IOException, ServletException 
    {
                                                                                                                                    /* DEBUG */try {
            System.out.println("(!!) doGet >> " + DefaultServlet.class.getMethod("doGet",new Class[]{HttpServletRequest.class,HttpServletResponse.class}) ) ;
            doGet(request,response) ;
                                                                                                                                    /* DEBUG */}
                                                                                                                                    /* DEBUG */catch(Exception e) { System.out.println("(!) " + this.getClass( ).getName( ) + " >> buildResponse >> " + e.toString( ) ) ; }
    }

 }

堆栈跟踪:

(指向 NullPointer 的部分)

在 org.apache.catalina.servlets.DefaultServlet.serveResource(DefaultServlet.java:741) 在 org.apache.catalina.servlets.DefaultServlet.doGet(DefaultServlet.java:398) 在 org.pulse.web.FileRequestHandler.buildResponse(FileRequestHandler.java:39)


更新:

据我所知,我可能需要澄清前端控制器 servlet 将拦截所有 HttpRequests(web.xml 中的<url-pattern>/</url-pattern>),因此由 servlet 容器实例化的 DefaultServlet 将不会收到任何请求。 我现在在前端控制器类中明确调用了DefaultServlet#init

 FileRequestHandler fileRequestHandler = new FileRequestHandler( ) ;
 fileRequestHandler.init( ) ;

现在我得到一个 404 Servlet 不可用。

更新2:问题——事实证明——实际上是扩展类使用不足的后续问题,而不是继承的直接问题。


我添加的用于检测问题根源的日志帖子将引发NoSuchMethodException。如果我省略它,我会得到一个NullPointerException

它看起来如此简单。我仍然无法让它按照我想要的方式工作。有什么想法、建议或见解?

TIA,

FK

【问题讨论】:

    标签: java inheritance methods subclass protected


    【解决方案1】:

    Class.getMethod 返回 public 方法 - 没有这样的 public 方法,因此例外。您可以使用getDeclaredMethod 获取非公共方法。

    不清楚为什么在没有记录的情况下尝试它时得到NullPointerException - 如果您可以发布更完整的堆栈跟踪,它可能会更清楚。

    编辑:从source code for DefaultServlet 看来,这是引发异常的行:

    CacheEntry cacheEntry = resources.lookupCache(path);
    

    但这并没有多大意义,因为init() 在这种情况下应该抛出异常......在您的日志中还有其他报告错误吗?

    【讨论】:

    • 更新了我的帖子。 requestresponse 都不是空的。
    • @FK82:你用的是什么版本的Tomcat?
    • @John Skeet:也许我需要明确地打电话给init 吗?根据文档 (download.oracle.com/javaee/6/api/javax/servlet/…),Servlet 容器通常会这样做。
    • @FK82:你不需要,不。这应该作为 servlet 生命周期的一部分自动调用。在此异常之前,您的日志中有什么有趣的事情吗?
    • @John Skeet:直到 NullPointer 的堆栈跟踪没有什么是预期的方法调用链。请看看我的更新。
    【解决方案2】:

    为了从超类调用受保护的方法,您不必做任何特殊的事情。事实上,由于您没有在 servlet 中覆盖 doGet(),因此它的 doGet() 方法实际上应该是超类方法。除了正常调用它之外,您不必做任何特别的事情,例如:

    public void setResponse(HttpServletRequest request , HttpServletResponse response, URI uri) 
            throws IOException, ServletException  {
    
            doGet(request,response) ;
    }
    

    如果您愿意,可以将doGet(request,response) 替换为super.doGet(request,response),但在这种情况下不会有任何区别,因为您没有在子类中覆盖doGet()

    【讨论】:

    • 是的,我也是这么想的。 :-)
    猜你喜欢
    • 1970-01-01
    • 2013-04-06
    • 2013-02-04
    • 2010-10-01
    • 2011-07-09
    • 2017-12-09
    • 2020-05-02
    • 2015-08-04
    相关资源
    最近更新 更多