JAXB関連のエラー対応

JAXB関連のエラー

エラーその1

Java Swingでの開発中に表題の様なエラーが出ました。

javax.swing.SingleSelectionModelはインタフェースです。JAXBはインタフェースを処理できません。

実装内容としては、次のようになっています。

  1. XMLファイルを読み込み
  2. 対応するデータをクラスで保持する⇔XMLファイルに出力

このエラーは、

実装部分としては下のようなコードです。
<処理部分>

public class InputSelector extends JPopupMenu {
    ・・・
    private void openCommandMenu(SelectMenu item) {
        List<Command> cmdList = play.getJob().getCommandList();
        for (Command cmd : cmdList) {
            cmd.addActionListener(this);
            add(cmd);
            addSeparator();
        }
    }
    ・・・
} 

add()しているCommandクラスをJMenuItemで拡張しています。※拡張したらエラーになりました。
JMenuItemを継承したのでエラーになりました。
なので、このクラスを保持するクラスを作成して、エラーを直しました。

@Data
public class Command extends JMenuItem implements ConfigIF {
    private String id;
    private String name;
    private Formula formula;

    public Command() {
    }

    public Command(String id, String name, Formula formula) {
        this.id = id;
        this.name = name;
        this.formula = formula;
    }
}

新たに作成したクラス
<CommandMenu>

import javax.swing.*;

public class CommandMenu extends JMenuItem {

    private Command command;

    public CommandMenu() {
    }

    public CommandMenu(Command cmd) {
        super(cmd.getName());
        this.command = cmd;
    }

    public Command getCommand() { return command; }
    public void setCommand(Command cmd) { this.command = cmd; }
}

余談1

JAXBでXMLからクラスを生成するとき、対象のクラスには、デフォルトコンストラクタが定義されていないとエラーになる。
<XMLの一部抜粋>

<config>
    <views>HP</views>
    <views>MP</views>
    <views>LV</views>
    <money>
        <key>NIG</key>
        <name>ニギ</name>
        <value>0</value>
    </money>
    <money>
        <key>GLD</key>
        <name>ゴールド</name>
        <value>1</value>
    </money>
    <element>
        <id>FIR</id>
        <name>火</name>
    </element>
    <element>
        <id>WIN</id>
        <name>風</name>
    </element>
    <element>
        <id>WAT</id>
        <name>水</name>
    </element>
    <element>
        <id>EAT</id>
        <name>土</name>
    </element>
</config>

<クラス>

package jp.zenryoku.rpg.data.config;

import lombok.Data;
/**
 * このゲームで使用する要素・エレメントを定義する。
 * 
 * @author (Takunoji)
 * @version (1.0)
 */
@Data
public class Element
{
    /** ID */
    private String id;
    /** 要素名 */
    private String name;

    /** デフォルトコンストラクタ */
    public Element() {
    }

    public Element(String id, String name) {
        this.id = id;
        this.name = name;
    }
}

エラーその2

下の様なエラーが出ました。

javax.xml.bind.DataBindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
プロパティmoneyが存在しますが、@XmlType.propOrderに指定されていません

XML出力の順番を指定する「\@XmlType(propOrder=XXX)」の指定の中にフィールド変数の「money」が登録されていなかった。
下のコードは追加した後です。

対象のクラス

@XmlRootElement( name="player")
@XmlType(propOrder={"level", "name", "sex", "status", "items", "job", "state", "wepon", "armor", "money"})
@Data
public class Player implements Cloneable
{
    private static final boolean isDebug = true;
    /** 名前 */
    protected String name;
    /** レベル */
    protected int level;
    /** 性別 */
    protected SEX sex;
    /** ステータス */
    protected Map<String, Params> status;
    /** 所持アイテム */
    protected List<Item> items;
    /** 職業 */
    protected Job job;
    /** 状態 */
    protected State state;
    /** 武器 */
    protected Wepon wepon;
    /** 防具 */
    protected Armor armor;
    /** お金 */
    protected int money;
    ...
}

エラーその3

javax.xml.bind.DataBindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
プロパティmoneyが@XmlType.propOrderにありますが、そのようなプロパティは存在しません。noの誤りである可能性があります。

対象のクラス

もともとholdmneyの部分がmoneyになっていた。
propOrderの中身を正しく書き換えたら治った。

@Data
@XmlRootElement( name="monster")
@XmlType(propOrder={"no", "talk", "message", "type", "holdmoney", "exp"})
public class Monster extends Player implements Cloneable, Serializable
{
    /** 番号 */
    private int no;
    /** 話す */
    private boolean talk;
    /** 話すときのメッセージ */ 
    private String message;
    /** モンスタータイプ */
    private MonsterType type;
    /** お金 */
    private int holdmoney;
    /** 経験値 */
    private int exp;
    ...
}

Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException: Cannot invoke “java.lang.CharSequence.toString()” because “replacement” is null

because "replacement" is null

下のようなコードを実行したらエラーが出ました。

// 基本計算記号の変換
Set<String> fSet = formulas.keySet();
for (String key : fSet) {
    System.out.println("key: " + key);
    if (resFormula.contains(key)) {
        Formula f = formulas.get(key);
        resFormula = resFormula.replace(key, f.getFormulaStr());
    }
}

解決方法

String#replace()の第二引数がNULLになっていた。。。

実装は、Githubにアップしてあります。

Java Servlet エラー ~フォワードできません

フォワードできません

以下のようなエラーが出ました。

java.lang.IllegalStateException: レスポンスをコミットした後でフォワードできません

未入力の場合、リクエストスコープにエラーメッセージをリクエストスコープに保存して画面をフォワードしたときに上記のエラーが出ました。

具体的なコードは以下のようなものです。

/** POSTリクエスト */
/**
 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
 */
protected void doPost(HttpServletRequest request
        , HttpServletResponse response) throws ServletException, IOException {
    request.setCharacterEncoding("UTF-8");
    String text = request.getParameter("text");

    // 入力チェック
    if (text == null || "".equals(text)) {
        System.out.println("*** in Error ***");
        // エラーメッセージをリクエストスコープに設定
        request.setAttribute("errorMsg", "つぶやきが入力されていません");
        // フォワード
        forwardMain(request, response);
    }
    ServletContext application = this.getServletContext();
    // アプリケーションスコープ
    List<Mutter> mutterList =
            (List<Mutter>)application.getAttribute("mutterList");
    // セッションスコープ
    HttpSession sess = request.getSession();
    // ユーザークラス
    User user = (User) sess.getAttribute("loginUser");
    // つぶやきリストに追加
    Mutter mutter = new Mutter(user.getName(), text);
    new PostMutterLogic().execute(mutter, mutterList);
    // アプリケーションスコープに保存
    application.setAttribute("mutterList", mutterList);
    // フォワード
    forwardMain(request, response);
}

private void forwardMain(HttpServletRequest request
        , HttpServletResponse response) throws ServletException, IOException{
    // フォワード
    RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/main.jsp");
    dispatcher.forward(request, response);
}

エラーの原因を探る

元々エラー処理、パラメータの入力チェックを行っていなかったところにエラー処理if (text == null || "".equals(text)) {を入れ、フォワードするように実装しました。
原因部分はここになるのですが、調べてみると。下の処理を2回行っているところがありました。

    // フォワード
    RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/main.jsp");
    dispatcher.forward(request, response);

まとめ

2回フォワードしているのでエラーになったということでした。。。

でわでわ。。。

Java Servlet Filter ~画面遷移しない~

イントロダクション

Java ServletでFilterの実装を祖小名いました。

    <filter>
        <filter-name>docoFilter</filter-name>
        <filter-class>filter.DocoFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>docoFilter</filter-name>
        <url-pattern>*</url-pattern>
    </filter-mapping>
@Override
public void init(FilterConfig filterConfig) throws ServletException {
    log = Logger.getLogger("logFilter");

    log.info("*** フィルター処理開始");
}

@Override
public void destroy() {
    log.info("*** フィルター処理終了");
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    log.info("** Before doFilter ");
    log.info("ContentType: " + request.getContentType());
    log.info("** Url: " + req.getRequestURI());

    long start = System.currentTimeMillis();
    System.out.println("Milliseconds in: " + start);
    chain.doFilter(request, response);
    long end = System.currentTimeMillis();
    log.info("** After doFilter / " + (end - start));
}

初回のリクエストは問題なく、初期画面が表示されるが、次のログイン後の画面が表示されない。。。

下のような実装をしました。

    @Override
    protected void doGet(HttpServletRequest request
            , HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("UTF-8");
        String name = request.getParameter("name");
        String pass = request.getParameter("pass");

        // ユーザークラス
        User user = new User(name, pass);
        // ログイン処理
        LoginLogic logic = new LoginLogic();
        boolean isLogin = logic.execute(user);

        if (isLogin) {
            HttpSession sess = request.getSession();
            sess.setAttribute("loginUser", user);
        }
        System.out.println("LoginServlet");
        // フォワード
        RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/jsp/loginResult.jsp");
        dispatcher.forward(request, response);
    }
    }
    @Override
    protected void doPost(HttpServletRequest request
            , HttpServletResponse response) throws ServletException, IOException {

    }

原因

ズバリ、doGetとdoPostのメソッドを間違えた。。。

確認した内容

  1. doFilterを実装していたので、Filterにエラーがあると思ったが、問題なく。。。
  2. 画面の遷移先URLが正しいか確認
  3. 表示先のJSPにエラーがないか確認

結局のところは、凡ミスでした。。。。

でわでわ。。。

Maven エラー ~execute but there is no POM in this directory (/home/pi/repos)~

but there is no POM

ラズパイでMavenを使用してgithubから作成したプログラムをダウンロードしようとしたところ表題のようなエラーが出ました。

エラーメッセージ

he goal you specified requires a project to execute but there is no POM in this directory (/home/pi/repos). Please verify you invoked Maven from the correct directory. -> [Help 1]

こちらのサイトでは、POMファイルのあるディレクトリで実行すればOKみたいなことを記載していたので、そのようにしました。

そしたら次のようなエラーに代わりました。

Unknown lifecycle phase "pom.xml". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]

mvn clean

とりあえずは、一度きれいにしたほうが良いと思い、「mvn clean」コマンドを実行

どうやら、成功したようです。

mvn default

次に、通常のビルドをかけようと考え、上記の「mvn default」を実行しました。
リモートデスクトップ環境なのとラズパイ2なので、まぁ遅いです。。。
※インストールしているOSはRaspberry Desltopです。。。

そして、出力されたエラーは下のようなものです。

Unknown lifecycle phase "default". You must specify a valid lifecycle phase or a goal in the format <plugin-prefix>:<goal> or <plugin-group-id>:<plugin-artifact-id>[:<plugin-version>]:<goal>. Available lifecycle phases are: validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy, pre-clean, clean, post-clean, pre-site, site, post-site, site-deploy. -> [Help 1]

初めに出たエラーと同様なものです。つまりは、mvn XXXXのXXXX部分が不適切であろうという判断ができます。

そんなわけで、初めに実行したコマンドから「pom.xml」を取り除き再度実行しました。以下のコマンドです。

mvn install

EclipseプロジェクトのMaven化

IntelliJ IDEA

IntelliJ IDEA でのMavenプロジェクト作成方法

mvn install

改めて、上記のコマンドを実行したところWarninngはあるけど何とか成功しました。

でわでわ。。。