2017-05-17 4 views
1

私はメソッド参照の非常に奇妙な動作を観察します。 Webアプリケーションと一連のサーブレット階層があります。サーブレットAはサーブレットBを拡張しますHttpServlet(なぜこれが必要なのか見落としましょう)。Java 8インスタンスメソッドの参照は、lambda呼び出しと同等ですか?私の場合はそうではありません

ウェブアプリケーションはTomcat/Java 8(web.xml version = "3.1" metadata-complete = "true")でホストしています。私の地元のラップトップ(のTomcat 8.0.35または8.5.15、Javaの8のアップデート131、OSX)で 私は、このようなサーブレットコードのスタックオーバーフローの観察:

public class A extends B { 
    @Override 
    protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException { 
     ServletCommon.servletServiceWrapper(pRequest, pResponse, super::service); 
    } 
} 

スタックオーバーフロー(下記参照)は非常に疑わしい - を階層内にクラスBは含まれていません。 クラスAはHttpServletを直接呼びます(なぜ!!そしてこれも可能です!!!!)。ラムダと同じタイムコードで

が正常に動作します:

public class ServletCommon { 
    @FunctionalInterface 
    public interface MyBiConsumer<T, U>{ 
     void accept(T t, U u) throws ServletException, IOException ; 
    } 
public static void servletServiceWrapper(HttpServletRequest request, HttpServletResponse response, 
     MyBiConsumer<HttpServletRequest, HttpServletResponse> pDelegate) throws ServletException, IOException { 
     pDelegate.accept(request, response); 
    } 
} 

スタックトレース

java.lang.StackOverflowError 
    ServletA.lambda$service$0(ServletA.java:19) 
    ServletCommon.servletServiceWrapper(ServletCommon.java:31) 
    ServletA.service(ServletA.java:19) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    ServletA.lambda$service$0(ServletA.java:19) 
    ServletCommon.servletServiceWrapper(ServletCommon.java:31) 
    ServletA.service(ServletA.java:19) 
    javax.servlet.http.HttpServlet.service(HttpServlet.java:729) 
    ... 

任意のアイデア:

public class A extends B { 
    @Override 
    protected void service(HttpServletRequest pRequest, HttpServletResponse pResponse) throws ServletException, IOException { 
     ServletCommon.servletServiceWrapper(pRequest, pResponse, (t, u) -> super.service(t, u)); 
    } 
} 

ラッパーはまた、非常に単純なコードが含まれていますか?

+1

[最小限のテストケース](http://stackoverflow.com/help/mcve)を構築できますか?私はこの行動を再現することはできません:http://ideone.com/khkDCK。 –

答えて

1

Pretty much, yeah

service()メソッド(HttpServletRequestの保護されたものではなく、ServletRequestの公開されたもの)を間違った方法で呼び出すと、無限ループが発生します。しかし、あなたのサンプルコードは、それが起こっている理由を示すのに十分ではありません。

+0

あなたは正しいですが、なぜ "super :: service"がHttpServlet.service(ServletRequest req、ServletResponse res)を指していますが、 "(t、u) - > super.service(t、u) B.サービス(HttpServletRequest pRequest、HttpServletResponse pResponse)」を参照してください。私はその動作が実行時環境と異なることを観察しています。 (Eclipse、Tomcat、Jettyなど) – FoxyBOA

+1

可能な限り単純なテストケースを試してみて、動作が実際に環境によって異なるかどうかを確認してください。メソッドの解決が非決定論的な仕方で機能する場合、バグレポートを保証することができます。 – Kayaman

+2

コンパイラのバグのように聞こえます。そのバグを持っている 'javac'のバージョンが見つからなかったので、おそらく、そのバグを持つ' ecj'バージョンがあります... – Holger

関連する問題