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

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

ただいまの
回答率

87.59%

タイトル:Javaのフィールド変数について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 894

score 16

前提・実現したいこと

ここに質問の内容を詳しく書いてください。
いつもお世話になっております。
現在、Javaで開発を行っているのですが、下記問題が発生しています。
DbaccessクラスでUserinformationdtoクラスのフィールドに値を格納し、UserconfimationクラスでUserinformationdtoクラスの
フィールドをUserconfimationクラスの「System.out.println(this.userInfDto.getUser());」で確認しようとしたのですが、
そのタイミングで「nullpointerexception」が発生しました。
個人的には恐らくフィールドの初期化タイミングを理解していないことが原因だとは考えているのですが、調べてもいまいちピンと
来ませんでしたので今回質問させていただきました。
どなたかご存知の方がいましたらご教授お願い致します。
私自身Javaは現在勉強し始めたばかりなので今回の原因が初歩的なものだとしたら申し訳ありません。

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

フィールド参照時にNullの為、「nullpointerexception」が発生

java.lang.NullPointerException
    at jp.co.controller.todo.Userconfirmation.doPost(Userconfirmation.java:39)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:110)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:169)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:637)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)

該当のソースコード

package jp.co.controller.todo;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;

import jp.co.model.todo.Dbaccess;
import jp.co.model.todo.Userinformationdto;

public class Userconfirmation extends HttpServlet{

    boolean bool;
    Dbaccess dbaccess;
    Userinformationdto userInfDto;

    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws IOException, ServletException{

        String user = null;
        int psw = 0;

        try {
            user = request.getParameter("user");
            psw = Integer.parseInt(request.getParameter("psw"));
        } catch (Exception e) {

        }

        dbaccess = new Dbaccess();

        bool = dbaccess.Confimation(user, psw);
        try {
            if (bool == true) {
                System.out.println(this.userInfDto.getUser());
                System.out.println(this.userInfDto.getPsw());
                if (!StringUtils.isEmpty(this.userInfDto.getUser()) && this.userInfDto.getPsw() != 0) {
                    request.setAttribute("user", user);
                    request.setAttribute("psw", psw);
                    request.setAttribute("userinformationList", this.userInfDto.getUserInformationList());
                    request.getRequestDispatcher("/Loginsuccess.jsp").forward(request, response);
                }
            } else {
                request.getRequestDispatcher("/Login.jsp").forward(request, response);
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }

    }

}

該当のソースコード

package jp.co.model.todo;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.sql.DataSource;

public class Dbaccess extends Userinformationdto{

    DataSource ds;
    Userinformationdto userInfDto;

    public Dbaccess() throws ServletException {
        try {
            InitialContext ic = new InitialContext();
            ds = (DataSource)ic.lookup("java:/comp/env/jdbc/SQLServer");

        } catch(Exception e) {

        }
    }

    public boolean Confimation(String user, int psw ) {

        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rset = null;

        try {
            con = ds.getConnection();
            if (user != null && psw != 0) {

                StringBuffer sql = new StringBuffer();

                sql.append("select user_id, user_name, user_password from user_table where user_name='" + user +"'" + "and user_password=" + psw );

                // sql文実行準備
                pstmt = con.prepareStatement(new String(sql));

                // sql文実行
                pstmt.execute();

                // 実行結果を、ResultSetクラスに代入
                rset = pstmt.executeQuery();
                if(rset.next()) {
                    setUser(rset.getString("user_name"));
                    setPsw(rset.getInt("user_password"));
                    System.out.println(getUser());
                    System.out.println(getPsw());
                    //StringBuilderの初期化を行います。
                    sql.delete(0, sql.length());
                    sql.append("select task_number, task_title, task_start_date, task_end_date, task_status, task_description from user_table INNER JOIN user_task_table on user_table.user_id='" + rset.getString("user_id") + "'");
                    System.out.println(sql);
                    // sql文実行準備
                    pstmt = con.prepareStatement(new String(sql));
                    // sql文実行
                    pstmt.execute();
                    //結果格納前に初期化を行います。
                    rset = null;
                    System.out.println(getUser());
                    System.out.println(getPsw());
                    // 実行結果を、ResultSetクラスに代入
                    rset = pstmt.executeQuery();
                    ArrayList arrayList = new ArrayList();
                    List<ArrayList> list = new ArrayList();
                    while (rset.next()) {
                        arrayList.add(rset.getInt("task_number"));
                        arrayList.add(rset.getString("task_title"));
                        arrayList.add(rset.getDate("task_start_date"));
                        arrayList.add(rset.getDate("task_end_date"));
                        arrayList.add(rset.getInt("task_status"));
                        arrayList.add(rset.getString("task_description"));
                        list.add(arrayList);
                    }
                    setUserInformationList(list);
                }
            } else {
                return false;
            }
        } catch (SQLException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        } finally {
            try {
                if (con != null) {
                    con.close();
                }
            } catch (SQLException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
        }
        return true;
    }

}

該当のソースコード

package jp.co.model.todo;

import java.util.ArrayList;
import java.util.List;

public class Userinformationdto {

    private String user;

    private int psw;

    private List<ArrayList> userInformationList;

    public String getUser() {
        return user;
    }

    protected void setUser(String user) {
        this.user = user;
    }

    public int getPsw() {
        return psw;
    }

    protected void setPsw(int psw) {
        this.psw = psw;
    }

    public List<ArrayList> getUserInformationList() {
        return userInformationList;
    }

    protected void setUserInformationList(List<ArrayList> userInformationList) {
        this.userInformationList = userInformationList;
    }



}

試したこと

ここに問題に対して試したことを記載してください。

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

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2019/02/24 03:15

    NullPointerExceptionのスタックトレースを追記してください。
    おそらくuserInfDtoのインスタンスがnullだと思います。このインスタンスはいつ初期化するのでしょうか?

    キャンセル

  • pokemn

    2019/02/24 13:30

    申し訳ありません。スタックトレースの追記を致しました。
    おそらくuserInfDtoのインスタンスがnullだと思います。このインスタンスはいつ初期化するのでしょうか?
    →私の認識ですと、DbaccessクラスでDtoに値を格納したあとはUserconfirmationクラスの
     フィールドuserInfDtoでgetすれば格納した値を参照できるという認識だった為、
     インスタンス初期化を行うという認識はありませんでした。

    キャンセル

  • 退会済みユーザー

    退会済みユーザー

    2019/02/24 14:05

    > 私の認識ですと、DbaccessクラスでDtoに値を格納したあとはUserconfirmationクラスの
    > フィールドuserInfDtoでgetすれば格納した値を参照できるという認識だった為、
    おっしゃるとおりです。getすれば、NullPointerExceptionはなくなるでしょう。解決のためにコードを書いてみませんか。その他いろいろな問題がありそうですが、有識者の回答を待ちましょう。

    キャンセル

回答 1

checkベストアンサー

0

NullPointerExceptionの対処

doPost()のなかで使うthis.userInfDtoのインスタンスが生成されていないのでNullPointerExceptionが起きます。つまり、this.userInfDtoを使っているところは例外が発生します。

System.out.println(this.userInfDto.getUser());
System.out.println(this.userInfDto.getPsw());
if (!StringUtils.isEmpty(this.userInfDto.getUser()) && this.userInfDto.getPsw() != 0) {
request.setAttribute("userinformationList", this.userInfDto.getUserInformationList());


これらのthis.userInfDto.xxxを、dbaccess.xxxに置き換えれば問題は起きません。たぶん回答はこれでいいのでしょうけれど、その他いろいろ問題がありますね。

技術的な問題点

  • スレッドセーフではない
    サーブレットがシングルスレッドモデルを採用しない場合(ほとんどの場合)、サーブレットのインスタンス変数は保護されません。同様にDBAccessのインスタンス変数もマルチスレッドから保護されません。クラスのインスタンス変数は削除して、メソッドのローカル変数だけで処理してください。
  • List<ArrayList>の使い方がジェネリクスの利点を享受していない。
    user_task_tableのDtoを用意してList<UserTaskDto>として使いましょう。
  • Dtoはセッションに格納することを考慮してSerializableを実装する。
  • JDBCのPreparedStatementの使い方に誤りがある。SQLインジェクションを避けるために値をバインドする。
  • SQLが二回発行されている(execute/executeQuery)。
  • AutoClosableなリソースにtry-with-resource構文を使ってもよい。できれば使ってほしい。

技術的な問題は必ず解決しましょう。本格的に学習することをおすすめします。学習内容はおよそ次のとおりです。

  • Java Servlet (+Threadの知識)
  • JDBC
  • Javaシリアライゼーション + Java Beans
  • アプリケーションアーキテクチャ設計パターン

クラス設計についての提言

一般的にはMVCパターンで考えるようですが、レイヤー(層) パターンで考えてみます。レイヤーにすることで、機能ごとに独立性を高めて、作りやすく、保守性をよくします。Webアプリケーションではレイヤーを三層または四層に分て考えます。

層 (レイヤー) 担当機能 クラス Java依存関係
プレゼンテーション層 GUIを担当する Servlet,JSP Java EE (Web)
ビジネスロジック層 本質的なシナリオを実行する (提示されたソースにはありません) Java SE(+トランザクション管理?)
永続化層 データベースなどの永続データを扱う層 DAO(Data Access Object) JDBC
すべての層 層をまたがって移動するデータ DTO(Data Transfer Object) Java SE

レイヤーパターンには整合性を保つために規約が必要です。たとえば、各層は相互に依存してはならない(ビジネスロジック層はServletクラスに依存しない(importしない)など)。呼び出しは上位層から下位層へ。引数、戻り値として使用するオブジェクトを取り決める。下位層から上位層へ投げる例外を取り決める、トランザクションの扱いなど、多々あります。

レイヤーパターンから見た改善点

  • できればビジネスロジックに相当するクラスを用意してGUIから分離してください。
    ログイン機能に本質的な、ユーザーの存在チェックを行う。ユーザーのタスク一覧を作成すること。
  • DbAccessがDTOの派生クラスになっていてレイヤー機能の分離ができていません。
    永続化層にアクセスする機能(JDBC)がDtoを汚染しています。Dtoは軽量にしてください。
  • user_table, user_task_tableのアクセス機能が混在しています。
    再利用性を考えると分離すべきです。そうすれば他のビジネスロジックからも利用できるようになります。
  • 同様に、user_table, user_task_tableのDtoを作成する。
    上のアクセス機能ごとにDtoを作成するのが良いと思います。やはり再利用性のため。

以下のようなクラス分けにすることを提案します。

層 (レイヤー) クラス案
プレゼンテーション層 Userconfirmation,Loginsuccess.jsp,Login.jsp
ビジネスロジック層 LoginLogic
永続化層 DBAccess(UserTableAccess,UsserTaskTableAccess),ConnectionManager
すべての層 UserDto,UserTaskDto

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/25 08:49

    回答ありがとうございます。
    無事解決致しました。

    技術的な問題点とクラス設計の提言についてもご指摘の通り修正してみます。
    またこれを機に一度上記で挙げられた4つの内容を本格的に学習致します。

    キャンセル

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

  • ただいまの回答率 87.59%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る