質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
NullPointerException

null値の参照型変数を参照しようとした場合に投げられる、Javaにおける例外のひとつです。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

Q&A

解決済

3回答

5780閲覧

クラス変数のListの要素にnullが設定される原因について

nakamuh

総合スコア13

NullPointerException

null値の参照型変数を参照しようとした場合に投げられる、Javaにおける例外のひとつです。

Spring

Spring Framework は、Javaプラットフォーム向けのオープンソースアプリケーションフレームワークです。 Java Platform上に、 Web ベースのアプリケーションを設計するための拡張機能が数多く用意されています。

0グッド

0クリップ

投稿2019/03/25 09:50

前提・実現したいこと

OncePerRequestFilterを継承したfilterクラスを作成し
リクエストのURLが特定のURLの場合に例外を発生させる処理を
実装しています。

特定のURL文字列はList型のクラス変数に設定し、
このクラス変数は宣言と同時に初期化しています。
Listの要素の設定は「コンテキストパス+固定の文字列」で、
固定文字列を含む文字列を設定しています。

コード上はクラス変数list自体もその要素自体も
nullが設定されることはないと考えていますが
javaのコード自体や、springFwの不具合等の観点でも
nullが設定される可能性はないか、情報がありましたら
ご教授いただけますか。

発生している問題・エラーメッセージ

コード上はlistにnullの要素が設定されることはないと思いますが
CheckUrl.isOkメソッドのs.equalsでNullPointerExceptionが発生します。

現在、本番稼働中、発生頻度は極小(数年前に1回発生)
(※下記ログの内容は一部変更しています、ご容赦ください)

<2019/mm/dd hh時mm分ss秒 JST> <Error> <HTTP> <BEA-101020> <[ServletContext@9999999999[app: module: path:null spec-version:3.0]] Servlet failed with an Exception java.lang.NullPointerException at jp.co.test.presentation.com.filter.CheckUrl.isOk(CheckUrl.java:99) at jp.co.test.presentation.com.filter.CheckUrlFilter.doFilterInternal(CheckUrlFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) Truncated. see log file for complete stacktrace

該当のソースコード

Java

1 2public final class CheckUrl { 3 4 private CheckUrl() {} 5 6 protected static boolean isOk(String path, List<String> list) { 7 for (String s : list) { 8 if (s.equals(path)) { // ←ここでNullPointerException発生 9 return true; 10 } 11 } 12 return false; 13 } 14 15}

Java

1@Profile({"development","it","production"}) 2@Component("checkUrlFilter") 3public class CheckUrlFilter extends OncePerRequestFilter { 4 5 private static final String REDIRECT_URL = "/jsp/test/test/Error.jsp"; 6 7 private List<String> requestUrl = new ArrayList<>(); 8 9 public CheckUrlFilter() { 10 } 11 12 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { 13 14 String curPath = request.getServletPath(); 15 addRequestUrl(request); 16 if (!CheckUrl.isOk(curPath, requestUrl)) { // ←CheckUrl.isOkを呼出し 17 // ここで意図した例外をスロー 18 } 19 chain.doFilter(request, response); 20 } 21 22 private void addRequestUrl(HttpServletRequest request) { 23 requestUrl.add(request.getContextPath() + REDIRECT_URL); 24 }  // ↑リクエストごとに同じ文字列が設定されている実装は微妙だが、 25 // ここでnullが設定されるとは考えにくい 26} 27

試したこと(再現性の検証)

①requestUrlへ追加する要素を1リクエストごとに1万回設定し画面を任意に操作
→再現ぜず、100万回にするとOutOfMemory発生(NullPointerException発生せず)

②原因不明ではあるが、念のため同時アクセス(複数名で同時に画面操作)を実施
→再現せず  

試したこと(「null + 固定文字列」の結果)

system.out.println(null + "/jsp/test/test/Error.jsp");
→"null/jsp/test/test/Error.jsp"で出力されたため、
やはりnullの要素がlistに設定されることはない、と考えています。

補足情報(FW/ツールのバージョンなど)

springFwは4.0.5(aop,beans,context,core,expression,jdbc,tx,web,webmvc)
java 1.7、weblogic 12.1.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/03/25 11:06

isOKを呼び出してる方のコード、リストを作っている方のコードを提示しましょう
nakamuh

2019/03/25 13:38

「該当のソースコード」にあるCheckUrlFilterクラスのほうになります。リストへの値の設定とそのあとにisOKを呼び出す処理があります。
退会済みユーザー

退会済みユーザー

2019/03/25 23:22

こんていんつかえよとおもう
nakamuh

2019/03/27 12:18

実装変更時はコンテインを使うか、また別の方法を検討したいと思っています。ありがとうございます!
guest

回答3

0

ベストアンサー

× クラス変数
〇 インスタンス変数 OR メンバ変数 OR フィールド

Filter はスレッドセーフでなければいけないが、ArrayList#add() 呼び出しているのでスレッドセーフになっていない。

多数のリクエストが同時に来ているところで ArrayList の capacity が拡大したら null が出てくることもあるかも。

投稿2019/04/09 02:58

wtokuno

総合スコア448

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakamuh

2019/04/09 04:08 編集

ご回答ありがとうございます。 クラス変数・・失礼しました。インスタンス変数です!ご指摘ありがとうございます。 ArrayListのcapaityの拡大によりnull・・・このあたりも調べてみます。
wtokuno

2019/04/09 04:06

んー、調べて分かるものなのだろうか。実験はできるだろうけど。 言語仕様的には動作は未定義だろうし、Javaの実装やバージョン、実行状態(JITの影響とか)によっても結果が変わるかもしれないし、何が起こるかわからない。
nakamuh

2019/04/09 04:16

聞いてばかりですみませんが、実験方法は何かこころあたりありますでしょうか? なんらかの状況でnullがリスとに入ることが再現できればと。 こちらのソースはすべて確認したのですが、listにaddしている箇所はすべて固定の文字列をaddしており、実装でnullを明示的にいれている箇所はありませんでした。
wtokuno

2019/04/09 04:45

私の環境では下のコードで主にConcurrentModificationExceptionになるけど そこそこの割合でNullPointerException、ごくまれにIndexOutOfBoundsExceptionも出る模様。 (実行環境やマシンのスペック、その他のタスクの負荷状況などで結果は変わります) ```java package sample; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; public class Sample { public static void main(String[] args) throws InterruptedException { ArrayList<String> list = new ArrayList<String>(); Collection<Callable<Void>> tasks = new ArrayList<>(); for (int i = 0; i < 100; i++) { final int num = i; tasks.add(() -> { list.add("item" + num); for (String item : list) { if (item.equals("item" + num)) { System.out.println("hit"); } } return null; }); } List<Future<Void>> results = Executors.newWorkStealingPool(10).invokeAll(tasks); for (Future<Void> future : results) { try { future.get(); } catch (ExecutionException e) { System.out.println(e); } } } } ```
nakamuh

2019/04/10 06:48

返信遅くすみません。上記コードをこちらでも試してみます。ありがとうございます!!!
nakamuh

2019/04/17 05:18

遅くなりすみません。検証してみたところリストの要素にnullが設定される事象が再現できました!! コード上は"item"+numでリストの要素にnullが設定されることはありえない、 と見えますが何度か実行してみると確かにnullが設定されています。 そもそもの実装方法を見直して対応したいと思います。 非常に助かりましたありがとうございます。
guest

0

当該コードや、Spring FrameworkやJavaのランタイムによって書かれている問題は発生しません。

考えられるのは、その初期化した際のListがどこからか書き換えていたコードがあって数年前は発生していた、などでしょう。

投稿2019/04/05 23:34

A-pZ

総合スコア12011

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakamuh

2019/04/06 10:21 編集

ご回答ありがとうございます。数年前に1回発生し、2月に再び発生しました。 やはりfwやjavaで発生しませんよね。「Listがどこからか書き換えていた」という点を もう一度確認してみようと思います。
guest

0

実装サンプル(javadoc記載)とcontainsのススメ

投稿2019/03/25 23:30

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nakamuh

2019/03/27 12:19

こちらもありがとうございます。javadoc読んでみます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問