20191021のJavaに関する記事は15件です。

単純なコールバックを作ってみる

〇概要

Androidアプリでアーキテクチャーが複雑化してくると非同期の情報を行うクラスとそれを使うクラスが分かれてきます。
そうなると非同期で得たデータを取得したタイミングで別クラスに教えてあげなければならないわけですが結構面倒。
というわけで、サポートライブラリのAsyncTaskLoaderとかイベントバスを扱うライブラリ(EventBusやRxJavaなど)が色々あるわけですが、インターフェースを利用した原始的なコールバックの作り方の情報があまりなかったのでまとめてみました。

〇サンプルソース

GitHub

〇クラス一覧

MainActivity

・メインクラス
・TasksRepositoryとTasksBackgroundDataSourceのインスタンスを生成。
・シンプルにするためにViewの表示関数もここに入れてあります。

TasksRepository

・データを保持して操作するクラス。
・生成時にTasksBackgroundDataSourceのインスタンスを取得しています。
・データ取得の依頼をTasksBackgroundDataSourceに投げたり、コールバックを受け取りMainActivityに表示の依頼を投げる。

TasksBackgroundDataSource

・非同期でデータを持ってくるクラス。
・TasksDataSourceインターフェースをimplementsしている。
・(ネットワークからデータを持ってくる処理を書くと処理が煩雑になるので、別スレッド立ててデータ埋め込んでいるだけ)

TasksDataSource

・データ取得の処理関係をまとめたインターフェース。

Task

・取得した値を管理するデータクラス。

〇コールバック部分抜粋

(注)理解しやすいために上のクラス一覧とは逆順に記載

データ取得の関数とコールバックとして呼ばれる関数を定義

TasksDataSource
public interface TasksDataSource {

    // コールバックとして呼ばれる関数
    interface LoadTasksCallback {
        void onTasksLoaded(List<Task> tasks);
        void onDataNotAvailable();
    }

    // データ取得関数(別に書かなくてよいがまとめて書いておく)
    void getTasks(@NonNull LoadTasksCallback callback);
}

データ取得関数getTasksを実装
取得後はコールバック関数を呼んであげる

TasksBackgroundDataSource
public class TasksBackgroundDataSource implements TasksDataSource {

    @Override
    public void getTasks(@NonNull final LoadTasksCallback callback) {

        final Handler handler = new Handler();

        // スレッド立ち上げ
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                 // Handlerを使用してメインスレッドに処理を依頼する(View更新のため)
                 handler.post(new Runnable() {
                     @Override
                     public void run() {

                         // データ取得
                         //  ・
                         //  ・

                         if (tasks.isEmpty()) {
                             // データがない時の処理
                             callback.onDataNotAvailable();

                         } else {
                             // データがあった時の処理
                             callback.onTasksLoaded(tasks);
                         }
                     }
                 });

            }
        });
        thread.start();
    }
}

TasksBackgroundDataSourceのgetTaskを呼び出して引数にLoadTasksCallbackのインスタンスを生成して呼び出してほしい関数を実装して渡す。

TasksRepository
        mTasksBackgroundSource.getTasks(new TasksDataSource.LoadTasksCallback() {
            // データ取得後に呼ばれる処理(データありの時)
            @Override
            public void onTasksLoaded(List<Task> tasks) {
                MainActivity.showTextMsg(changeTasksToString(tasks));
            }
            // データ取得後に呼ばれる処理(データなしの時)
            @Override
            public void onDataNotAvailable() {
                Log.w("DEBUG_DATA","TaskRepository onDataNotAvailable");
            }
        });

〇まとめ

結局はこれ呼んどいてね!ってデータ取得する関数に処理を実装したインスタンスを投げてるだけですが、それを実現するための設計が複雑ですね。
これはGoogleのMVPサンプルを元につくったのですが、そこでは
PresenterがRepositoryのgetTaskを呼び、そうするとDataSourceのgetTaskが呼ばれてと、数珠つなぎでcallbackが呼ばれていくという仕組みでした。
取得先も増えてくるとわけわからなくなってくるので、やっぱりライブラリを使いましょうということですね。
とりあえず基本をまとめてみました。

〇参考

android/architecture-samples

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java 8 lambda expression Feature

Java 8 introduced lambda expression to move toward functional programming. A lambda expression is an anonymous function that doesn’t have a name and doesn’t belong to any class.

Where to use the Lambda Expression
A lambda expression can only be used where the type they are matched against is a single abstract method(SAM) interface or functional interface.

To use a lambda expression, you can either create your own functional interface or use the predefined functional interface provided by Java.

Example of a pre-defined interface: Runnable, callable, ActionListener, etc.

Pre Java 8: Use anonymous inner classes.
Post-Java 8: Now use lambda expression instead of anonymous inner classes.

Points to remember
Lambda expression is also known as a closure that allows us to treat functionality as a method arguments (passing functions around) or treat code as data.
Lambda expression concept was first introduced in the LISP programming language.
Lambda expression is used to provide an implementation of a functional interface or Single Method Interface.
Lambda expression treated as a function so the compiler does not create .class file.
Lambda expression doesn’t need to define a method again for implementation.
Lambda expression benefit is less coding.
Java Lambda expression Syntax
To create a lambda expression, On the left side of the symbol lambda operator(->) specify input parameters (if there are any), and on the right side place the expression or block of statements.

(parameter_list) -> {function_body}
For example, the lambda expression (x, y) -> x + y specifies that lambda expression takes two arguments x and y and returns the sum of these.

Note:

Optional type declaration: No need to declare the data type of a parameter. The compiler can inference the data type from the value of the parameter.
The optional parenthesis around parameter: No needs to declare a single parameter in parenthesis. For multiple parameters, parentheses are required.
Optional curly braces: For a single line of the statement, No need to use curly braces in the expression body.
Optional return keyword: The compiler automatically returns the value if the body has a single expression statement to return the value. Curly braces are required to indicate that expression statement returns a value.
Here is some Lamda expression example according to a number of arguments.

No Argument Syntax

()->{
//write some statemnet here
}
One Argument Syntax

(arg1)->{
//write some statemnet here
}
Two Argument Syntax

(arg1,arg2)->{
//write some statemnet here
}
Method vs Lambda Expression in Java
A function (or method) in Java has four main parts:
1. Name
2. Parameter list
3. Body
4. return type.

A lambda expression has these main parts:
Lambda expression only has a parameter list and body.
1. No name – Lambda expression is an anonymous function that doesn’t have a name.
2. Parameter list
3. Body – This is the main part of the function where implementation is written.
4. No return type – Don’t need to write a return statement explicitly. The compiler is able to infer the return type by checking the code.

Related on

Spring boot interview questions and answers

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Eclipse - Springboot

環境

  • Elipcse 2018-09(4.9) ※Pleiades All in oneを使用
  • Java 8

EclipseにSTSを入れる

Spring Tools 4をインストール

  • EclipseマーケットでSTS4を探してインストールを押す
    image.png
  • 確認を押す
    image.png
  • 「使用条件の条項に同意します」を選択して完了を押す
    image.png
  • 今すぐ再起動を押してEclipseを再起動する
    image.png

Eclipseのパースペクティブを表示する

  • メニュから「ウインドウ→パースペクティブ→パースペクティブを開く→その他」を選択する
    image.png
  • Springを選択して開くを押す
    image.png
  • パースペクティブのSpringを選択する
    image.png

プロジェクト作成

  • メニュー「ファイル→新規作成→Springスタータープロジェクト」を選択する
  • 次へを押す
    image.png
  • 依存関係を追加指定し完了を押す
    image.png
  • 依存関係のインポートを待つ
    image.png
  • pom.xmlの1行目で不明なエラーが出たらmaven pluginのバージョン指定を追加する
pom.xml
    <properties>
            <java.version>1.8</java.version> 
            <!-- 下の1行を追加する -->  
            <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
    </properties>

動作確認

Controllerを作成する

HelloController.java
package com.example.demo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class HelloContoller {

    @RequestMapping("/")
    public String hello() {
        return "hello";
    }
}

HTMLを作成する

hello.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Spring demo</title>
</head>
<body>
  <h1>Hello</h1>
</body>
</html>

ツールバー実行から「実行→Spring bootアプリケーション」を選択して「http://localhost:8080」にアクセスする

image.png

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Talendコンポーネント活用(5)コンポーネントを自作する

Talendのコンポーネントを自作する

以前に標準コンポーネントでは実現できない処理をカスタムコンポーネントで使用する方法を紹介しましたが、今回はコンポーネントを作成する方法を紹介いたします。

Talendバージョン7以降ではコンポーネント作成手法が変更

Talendのバージョン6以前ではTalendStudioにComponent Designerという機能が付随されており、これを使ってコンポーネントの作成ができるようになっていました。
しかしバージョン7以降ではComponent Designerが廃止され、EclipseやIntelliJなどのJava統合開発環境で開発する方法に変更されました。

開発環境準備

コンポーネントの開発にはTalend Component Kitが必要になりますので、プラグインが利用可能なIntelliJを使用します。
IntelliJを起動して空のプロジェクトを作成し、メニューのファイルから設定画面を開き、プラグインのマーケットプレイスの検索タブからTalendを入力するとTalend Component Kitが表示されますので、これを選択してインストールしてIntelliJを再起動します。
なお、JavaはJava JDK1.8.xが必須となります。

プロジェクトの新規作成

IntelliJ IDEA へようこそ画面からプロジェクトの新規作成をクリックし、Talend Component Kitを選択して次へをクリックします。
00_新規プロジェクト_Talend Component Kit選択.jpg
下図のTalend STARTER TOOLKITが表示されます。
01_STARTER TOOLKIT_開始直後.jpg

メタデータの定義

Talend STARTER TOOLKIT画面ではコンポーネントとプロジェクトのメタデータを定義します。
今回は下図の内容を設定します。
02_STARTER TOOLKIT_メタデータ入力後.jpg
各項目を入力し画面左側の③Add A ComponentをクリックするとConfigration画面が表示されます。
03_STARTER TOOLKIT_Add_Component_クリック直後.jpg

コンポーネントの標準定義設定

Configration画面ではコンポーネントの名前と入出力設定を行います。
今回は下図のように名前のみをLoggerに変更し入出力はデフォルト設定で行います。
04_STARTER TOOLKIT_Add_Component_Logger入力後.jpg
次へをクリックすると下図のプロジェクト名と保存場所の設定画面が表示されますので、必要に応じて変更して完了ボタンをクリックします。
06_プロジェクト保存場所.jpg

プロジェクトの確認

STARTER TOOLKITが完了するとIntelliJのプロジェクト画面に移行します。
この時点でコンポーネントの作成に必要な最低限の設定は完了しています。
プロジェクトからLoggerProcessor.javaを開くと、コンポーネント作成に必要なコードの下地が既に作成されています。
07_プロジェクト保存後のLoggerProcessor.jpg

コンポーネントのコンパイルとデプロイ

この時点では特に何も機能しないコンポーネントではありますが、TalendOpenStudioへのデプロイまで実行してみます。
IntelliJのターミナルでmvnw clear installを入力してコンパイルを実行します。
08_IntelliJ_ターミナル_mvnwコマンド.jpg
下図のようにコンパイルが実行され正常に終了します。
09_IntelliJ_ターミナル_mvnwコマンド実行後.jpg
続いて、mvnw talend-component:deploy-in-studio -Dtalend.component.studioHome="C:\Talend\7.1.1_TOS_DI"を入力してTalendOpenStudioへのデプロイを実行します。
ダブルクォーテーションで囲まれているパスには、デプロイするコンポーネントを使用するTalendOpenStudioのホームのパスを設定します。
10_TalendOpenStudioへのデプロイコマンド入力後.jpg
下図のようにデプロイが実行され正常に終了します。
11_TalendOpenStudioへのデプロイコマンド実行後.jpg

TalendOpenStudioから作成したコンポーネントを使用する

デプロイ先に指定したTalendOpenStudioを起動して空のジョブを作成します。
PaletteのMiscを開くと、STARTER TOOLKITのメタデータで定義したSampleFamilyが表示され、デプロイしたコンポーネントSampleFamilyLoggerが使用できるようになっていますので、これをジョブに配置して使用できることを確認します。
12_TalendOpenStudioでジョブからコンポーネント使用.jpg

入力内容を表示するコードを追加する

このままでは実行しても見た目の結果が何もないコンポーネントなので、入力内容を表示するコンポーネントに変更します。
TalendOpenStudioを終了してIntelliJに戻り、LoggerProcessor.javaを開いて@ElementListenerを探して以下の2行を追加します。
//Log to the console
System.out.println("Input["+defaultInput+"]");
13_Inputを表示するコードを追加.jpg
先ほどと同様にターミナルからコンパイルとデプロイを実行します。
再びTalendOpenStudioを起動して、先ほどのジョブを開いてコンポーネントのInput側にtFileInputDelimitedeを追加してジョブを実行すると、実行結果にファイルからの入力内容が表示されます。
14_出力追加後のジョブ実行結果.jpg

まとめ

IntelliJとTalend Component Kitを使用することにより、簡単にコンポーネントの下地を作成することができました。
次回はもう少し深堀してコンポーネントを作成したいと考えてます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Kotlin】Kotlin 1.4未満では型パラメータに対するアノテーションが機能しない【BeanValidation】

TL;DR

内容はタイトルの通りです。
ただし、「バージョン1.4未満」としたのは暫定の表現で、実際に解決されるか、解決されるとして具体的にいつになるかなど、具体的なことは定かではありません。

前提

SpringBoot等でよく利用されるBeanValidationは、リスト等の型パラメータ(型引数、Type Argumentとも)に対してアノテーションを振ることで、内容に対するバリデーションが可能です1

Javaで型パラメータにアノテーションを付与したフィールドの例
private final List<@Size(max = 255, message = "{max}文字以内で入力してください。") String> hoge;

問題点

Kotlinで同じように書いてもバリデーションが機能しません。

Kotlinで型パラメータにアノテーションを付与したフィールドの例(機能しない)
private val hoge: List<@Size(max = 255, message = "{max}文字以内で入力してください。") String>

このことは既にissueになっています。

問題解決の目処

KT-13228にはTarget Versions: 1.4が指定されていますが、少なくともこの問題は3年以上放置されています。

参考にさせていただいた記事


  1. この機能がサポートされたのはBeanValidation 2.0から。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Kotlin】Kotlin 1.4.x未満では型パラメータに対するアノテーションが機能しない【BeanValidation】

TL;DR

内容はタイトルの通りです。
ただし、「バージョン1.4.x未満」としたのは暫定の表現で、実際に解決されるか、解決されるとして具体的にいつになるかなど、具体的なことは定かではありません。

前提

SpringBoot等でよく利用されるBeanValidationは、リスト等の型パラメータ(型引数、Type Argumentとも)に対してアノテーションを振ることで、内容に対するバリデーションが可能です1

Javaで型パラメータにアノテーションを付与したフィールドの例
private final List<@Size(max = 255, message = "{max}文字以内で入力してください。") String> hoge;

問題点

Kotlinで同じように書いてもバリデーションが機能しません。

Kotlinで型パラメータにアノテーションを付与したフィールドの例(機能しない)
private val hoge: List<@Size(max = 255, message = "{max}文字以内で入力してください。") String>

このことは既にissueになっています。

問題解決の目処

KT-13228にはTarget Versions: 1.4が指定されていますが、少なくともこの問題は3年以上放置されています。

参考にさせていただいた記事


  1. この機能がサポートされたのはBeanValidation 2.0から。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

replaceトラップ

だまされたわ

メールで試してみる

MailTemplate.java
package mail;

public class MailTemplate {

    /** from */
    private String from;
    /** to */
    private String to;
    /** cc */
    private String cc;
    /** title */
    private String title;
    /** body */
    private String body;

    public String getFrom() {
        return from;
    }
    public void setFrom(String from) {
        this.from = from;
    }
    public String getTo() {
        return to;
    }
    public void setTo(String to) {
        this.to = to;
    }
    public String getCc() {
        return cc;
    }
    public void setCc(String cc) {
        this.cc = cc;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getBody() {
        return body;
    }
    public void setBody(String body) {
        this.body = body;
    }
}

本文を作成するならこんな感じですよね

Test1.java
package test;

import mail.MailTemplate;

/**
 * test
 *
 * @author me
 *
 */
public class Test1 {

    /** mail template */
    private static MailTemplate mail = new MailTemplate();

    /** body template */
    private static final String BODY = "[time]に[place]でまちあわせな。\r\nこなかったら[kill]。";

    /**
     * main
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(join(createMail()));
    }

    private static String join(MailTemplate mail) {
        String crlf = "\r\n";
        return mail.getFrom() + crlf + mail.getTo() + crlf + mail.getCc() + crlf + mail.getTitle() + crlf + mail.getBody();
    }

    /**
     * create
     * @return
     */
    private static MailTemplate createMail() {

        // from
        mail.setFrom("おくりぬし");
        // to
        mail.setTo("おくりさき");
        // cc
        mail.setCc("ほかのひと");
        // title
        mail.setTitle("けんめい");
        // body
        mail.setBody(replaceBody(BODY));

        return mail;
    }

    /**
     * replace
     * @param text
     * @return
     */
    private static String replaceBody(String text) {
        text.replace("[time]", "2019/12/25");
        text.replace("[place]", "東京駅");
        text.replace("[kill]", "びんた");
        return text;
    }

}

で、結果

おくりぬし
おくりさき
ほかのひと
けんめい
[time]に[place]でまちあわせな。
こなかったら[kill]。

replaceって

Getter Setterみたいにできないわけですね

ただしくは

Test2.java
package test;

import mail.MailTemplate;

/**
 * test
 *
 * @author me
 *
 */
public class Test2 {

    /** mail template */
    private static MailTemplate mail = new MailTemplate();

    /** body template */
    private static final String BODY = "[time]に[place]でまちあわせな。\r\nこなかったら[kill]。";

    /**
     * main
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(join(createMail()));
    }

    private static String join(MailTemplate mail) {
        String crlf = "\r\n";
        return mail.getFrom() + crlf + mail.getTo() + crlf + mail.getCc() + crlf + mail.getTitle() + crlf + mail.getBody();
    }

    /**
     * create
     * @return
     */
    private static MailTemplate createMail() {

        // from
        mail.setFrom("おくりぬし");
        // to
        mail.setTo("おくりさき");
        // cc
        mail.setCc("ほかのひと");
        // title
        mail.setTitle("けんめい");
        // body
        mail.setBody(replaceBody(BODY));

        return mail;
    }

    /**
     * replace
     * @param text
     * @return
     */
    private static String replaceBody(String text) {
        text = text.replace("[time]", "2019/12/25")
                .replace("[place]", "東京駅")
                .replace("[kill]", "びんた");
        return text;
    }

}

結果

おくりぬし
おくりさき
ほかのひと
けんめい
2019/12/25に東京駅でまちあわせな。
こなかったらびんた。

しっかり上書きしないとなんも変わらないの、以外と盲点でキレそう

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Maven Dependency Plugin で system スコープの jar ファイルもひとつにまとめる

概要

  • 依存する JAR ファイルをローカルに置いて pom.xml で <scope>system</scope> を指定している状況を想定
  • mvn package コマンドで作成する JAR ファイルに、依存 JAR ファイル内のすべてのクラスファイルが入るように設定する
  • 今回の環境: Apache Maven 3.6.2

方法

Maven Dependency Plugin で以下にように設定する。

  • phase: prepare-package
  • goal: unpack-dependencies
  • outputDirectory: コンパイルしたクラスファイルが置かれるディレクトリを指定
  • includeArtifactIds: JAR ファイルに含めたいライブラリの artifactId をカンマ区切りで指定
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <phase>prepare-package</phase>
      <goals>
        <goal>unpack-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/classes</outputDirectory>
        <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
      </configuration>
    </execution>
  </executions>
</plugin>

この設定で mvn package を実行すると、JAR ファイルを作成する前に、ライブラリなどの依存 JAR ファイルからクラスファイル等が展開され、outputDirectory で指定したディレクトリにコピーされる。
JAR ファイルを作成する際には、依存 JAR ファイルの中にあったクラスファイルもひとつの JAR ファイルにまとめられる。

実例

pom.xml ファイルを用意。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>sample</name>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <!-- Apache Maven Dependency Plugin -->
      <!-- https://maven.apache.org/plugins/maven-dependency-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/classes</outputDirectory>
              <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
            </configuration>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>ajd4jp</groupId>
      <artifactId>ajd4jp</artifactId>
      <version>1.4.6.2019</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/ajd4jp-1.4.6.2019.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>jdom</groupId>
      <artifactId>jdom</artifactId>
      <version>1.1.3</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/jdom-1.1.3.jar</systemPath>
    </dependency>

  </dependencies>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

</project>

mvn package コマンドで JAR ファイルを作成する。

$ mvn package

作成した target/sample.jar を展開すると、指定したライブラリの jar ファイルに含まれていたクラスファイルが入っていることがわかる。

$ unzip target/sample.jar
Archive:  target/sample.jar
   creating: META-INF/
  inflating: META-INF/MANIFEST.MF    
   creating: orrery/
   creating: iso/
   creating: org/
   creating: org/jdom/
   creating: org/jdom/xpath/
   creating: org/jdom/input/
   creating: org/jdom/output/
   creating: org/jdom/adapters/
   creating: org/jdom/filter/
   creating: org/jdom/transform/
   creating: ajd4jp/
   creating: ajd4jp/orrery/
   creating: ajd4jp/orrery/tool/
   creating: ajd4jp/iso/
   creating: ajd4jp/util/
   creating: ajd4jp/format/
   creating: format/
   creating: com/
   creating: com/example/
  inflating: orrery/package-info.class  
  inflating: Copyright.txt           
  inflating: iso/package-info.class  
  inflating: org/jdom/IllegalAddException.class  
  inflating: org/jdom/DefaultJDOMFactory.class  
  inflating: org/jdom/EntityRef.class  
(後略)

Maven Assembly Plugin と組み合わせる

Maven Assembly Plugin も導入することで system スコープを指定した JAR ファイルだけでなく、リポジトリにある依存 JAR ファイルも一緒にまとめることができる。

pom.xml ファイルを用意。

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>sample</name>

  <build>
    <finalName>${project.artifactId}</finalName>
    <plugins>
      <!-- Apache Maven Dependency Plugin -->
      <!-- https://maven.apache.org/plugins/maven-dependency-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-dependency-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
          <execution>
            <phase>prepare-package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/classes</outputDirectory>
              <includeArtifactIds>ajd4jp,jdom</includeArtifactIds>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <!-- Apache Maven Assembly Plugin -->
      <!-- http://maven.apache.org/plugins/maven-assembly-plugin/ -->
      <!-- https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-assembly-plugin -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <archive>
            <manifest>
              <mainClass>com.example.App</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
    </plugins>
  </build>

  <dependencies>

    <dependency>
      <groupId>ajd4jp</groupId>
      <artifactId>ajd4jp</artifactId>
      <version>1.4.6.2019</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/ajd4jp-1.4.6.2019.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>jdom</groupId>
      <artifactId>jdom</artifactId>
      <version>1.1.3</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/lib/jdom-1.1.3.jar</systemPath>
    </dependency>

    <dependency>
      <groupId>org.twitter4j</groupId>
      <artifactId>twitter4j-core</artifactId>
      <version>4.0.7</version>
      <scope>compile</scope>
    </dependency>

  </dependencies>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

</project>

mvn package コマンドで JAR ファイルを作成する。

$ mvn package

作成した target/sample-jar-with-dependencies.jar を展開すると、system スコープと compile スコープで指定したライブラリの jar ファイルに含まれるクラスファイルが入っていることがわかる。

$ unzip target/sample-jar-with-dependencies.jar 
Archive:  target/sample-jar-with-dependencies.jar
  inflating: META-INF/MANIFEST.MF    
   creating: twitter4j/
   creating: twitter4j/util/
   creating: twitter4j/util/function/
   creating: twitter4j/auth/
   creating: twitter4j/management/
   creating: twitter4j/json/
   creating: twitter4j/api/
   creating: twitter4j/conf/
   creating: META-INF/maven/
   creating: META-INF/maven/org.twitter4j/
   creating: META-INF/maven/org.twitter4j/twitter4j-core/
   creating: orrery/
   creating: iso/
   creating: org/
   creating: org/jdom/
   creating: org/jdom/xpath/
   creating: org/jdom/input/
   creating: org/jdom/output/
   creating: org/jdom/adapters/
   creating: org/jdom/filter/
   creating: org/jdom/transform/
   creating: ajd4jp/
   creating: ajd4jp/orrery/
   creating: ajd4jp/orrery/tool/
   creating: ajd4jp/iso/
   creating: ajd4jp/util/
   creating: ajd4jp/format/
   creating: format/
   creating: com/
   creating: com/example/
   creating: META-INF/maven/com.example/
   creating: META-INF/maven/com.example/sample/
  inflating: META-INF/LICENSE.txt    
  inflating: twitter4j/JULLoggerFactory.class  
  inflating: twitter4j/SymbolEntity.class  
  inflating: twitter4j/MediaEntity.class  
  inflating: twitter4j/TwitterBase.class  
  inflating: twitter4j/Dispatcher.class  
  inflating: twitter4j/HttpClientBase.class  
(後略)

参考資料

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】MySQLに接続する

概要

MySQL : 5.7
Java : 8.1
Mac
Eclipse

始める前に以下条件をクリアしている

・MySQLで既にtableなどができている。
・ターミナルなどで難なく接続できている

JDBCをダウンロード

MySQLのJDBCをダウンロード
https://dev.mysql.com/downloads/connector/j/

「Platform Independent (Architecture Independent), Compressed TAR Archive」 をダウンロード
スクリーンショット 2019-10-21 17.25.07.png

解凍したファイルにmysql-connector-java-5.1.48-bin.jarがあるから、
Tomcatの/Tomcat/libに入れる
(私の場合、/Users/namari/apache-tomcat-9.0.27/lib

接続してみる

プロジェクトの中に、SqlTest.javaを適当に作ってみる。

SqlTest.java
package chapter14;

import java.io.*;
import java.sql.*;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

/**
 * Servlet implementation class SqlTest
 */
@WebServlet("/SqlTest")
public class SqlTest extends HttpServlet {
    private static final long serialVersionUID = 1L;


    protected void doGet(
        HttpServletRequest request,
        HttpServletResponse response
    ) throws ServletException, IOException {

        // 今回は、localhostにあるbook のデータベース
        String url = "jdbc:mysql://localhost/book";

        try{
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn = DriverManager.getConnection(url, "ユーザー名", "パスワード");

            // データベースに対する処理
            msg = "ok";
        } catch (SQLException | ClassNotFoundException e){
            msg = "NG";

        }
        response.getWriter().println(msg);
    }

}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Java]StringからPath型に変換して、パスを取得する方法

Java8で、ファイルパスを取得する際にPathクラスというものが必要になったのだが、処理中にStringのものも混在していて逐一変換しないといけない状態があったのでメモ書き。

結論から言うと、Pathクラスのresolveメソッドで、引数にStringの文字列を渡してあげればパス全体をPath型として認識させてあげることができる。

参考サイト:Path (Java Platform SE 8 )
https://docs.oracle.com/javase/jp/8/docs/api/java/nio/file/Path.html

resolveメソッドで指定した引数を追加された状態で、ファイルパスの全体を設定することができる。

具体例:Path型で指定したパス→/test/pathTest
Stringで追加したいパス→hoge.txt

結果:resolveメソッドを使用した結果→/test/pathTest/hoge.txt
※区切り文字は「/」と仮定

もし解釈が違っていたとか、もっと楽な方法があるのでしたら教えていただけると幸いです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Jacksonとは?

こんにちは。
ぽんぽこです。

本日はJacksonについてお話しします。

では本編へ。

Jacksonとは?

JacksonはJavaで使えるJSONライブラリです。
JSON形式の文字列をJavaのオブジェクトに直接マッピングしたり、
逆にJavaオブジェクトをJSON文字列に変換できたりします。

HTTPレスポンスをパースしたりオブジェクトをBase64エンコーディングする時などに便利です。

要するにすごーーーく便利な物です!

Jacksonを使うメリット

Jacksonを使えるとJSONを簡単に扱えます。
Jsonを使えるようになると、とても色々なことができるようになり、世界が大きく広がります。
なぜなら、TwitterやFacebook、GoogleなどのWEBサービスとはJSONでやりとりするからです。

つまり、JSONが分かれば、世の中にあるWEBサービスの色々な機能を自分で使えるようになります!!

Jsonの良さについては別の記事で紹介します!

Jacksonの使い方

Jacksonを利用するにはライブラリのダウンロードが必要です。
別の記事で紹介したMavenを利用する場合は以下を依存関係に指定します。

Mavenで利用する場合

<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.2.3</version>

Mavenを利用しない場合は以下のjarをダウンロードします。

jackson-databind-2.9.9-sources.jar
jackson-annotations-2.9.0-sources.jar
jackson-core-2.9.9-sources.jar

上記の方法でJacksonを使用することができるので
みなさんも試してみてください!

では次回、Jsonとは?でお会いしましょう。
では。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

H2 Databaseのコンソールタイムアウト(セッションタイムアウト)を設定する

TL;DR

  • H2 DatabaseのWebコンソールのセッションタイムアウトは、デフォルトで30分
  • これを延長する場合は、システムプロパティh2.consoleTimeoutで秒数を指定する

コンソールタイムアウト

H2 Databaseを起動すると、http://localhost:8082でアクセス可能なWebコンソールが起動します。

これのことですね。

image.png

このセッションタイムアウトは、デフォルトで30分になっています。

人によっては、短いと感じるかもしれません。少し放置する時間があって、タイムアウトするとそれまで書いていたクエリがなくなったりするわけです。

h2.consoleTimeoutを設定する

Webコンソールのタイムアウトを設定するには、CONSOLE_TIMEOUTを設定すればよいみたいです。

SysProperties

CONSOLE_TIMEOUT

デフォルトは1800000で、実際にシステムプロパティとして指定する時はh2.consoleTimeoutを指定します。

https://github.com/h2database/h2database/blob/version-1.4.200/h2/src/main/org/h2/engine/SysProperties.java#L153-L158

SysPropertiesのプロパティのidが、このキーになっていましたね、記事を書いていて気づきました。

https://www.h2database.com/javadoc/org/h2/engine/SysProperties.html#h2.consoleTimeout

これを、H2 Databaseの起動時にシステムプロパティとして指定します。

指定方法は、こちらを参考に。

Settings Read from System Properties

H2 Databaseのバージョン1.4.200で実行しました。

$ java -cp bin/h2-1.4.200.jar -Dh2.consoleTimeout=[秒数] org.h2.tools.Console

以下は、デフォルト値の30分(1800000秒)を明示的に指定した例です。

$ java -cp bin/h2-1.4.200.jar -Dh2.consoleTimeout=1800000 org.h2.tools.Console

これで、コンソールのタイムアウト(セッションタイムアウト)を変更することができるようになります。

確認に使用したJavaのバージョンは、こちらです。

$ java -version
openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1ubuntu1~18.04.1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】フィルターを作成

重複する内容はフィルターを作成してスッキリとしたコードに!!!

EncodingFilter.java
package tool;

import java.io.IOException;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;

@WebFilter(urlPatterns = { "/*" })
public class EncodingFilter implements Filter {
    public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain chain
    ) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");

        System.out.println("フィルター処理前");

        chain.doFilter(request, response);

        System.out.println("フィルター処理後");

    }

    public void init(FilterConfig filterconfig) {}

    public void destory() {
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

StringUtils.isBlank作ってみた

つくってみました

StringUtils.java
package practice;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Utils
 * 
 * @author me
 *
 */
public class Practice {

    /** String list */
    private static final List<String> INTEGER_LIST = Arrays.asList(null, "", " ", "0", "1", "2");

    /**
     * main
     * 
     * @param args
     */
    public static void main(String[] args) {
        try {
            run(INTEGER_LIST);
        } catch (NumberFormatException e) {
            echo.accept("・ω・v");
        }
    }

    /**
     * run
     * 
     * @param list <E> The element type of this list.
     * @throws NumberFormatException if conversion to numeric number is impossible.
     */
    private static void run(List<String> list) throws NumberFormatException {
        echo.accept(list.stream().filter(notBlank).map(Integer::parseInt)
                .collect(Collectors.summingInt(Integer::intValue)));
    }

    /** not null */
    static Predicate<String> notNull = v -> Optional.ofNullable(v).isPresent();
    /** not space */
    static Predicate<String> notSpace = v -> !v.equals(" ");
    /** StringUtils.isBlank */
    static Predicate<String> notBlank = v -> notNull.test(v) && !v.isEmpty()
            && Arrays.asList(v.split("")).stream().anyMatch(notSpace);
    /** out */
    static Consumer<Object> echo = v -> System.out.println(v);

}

結果

3

結論

なんだかんだ自作できてもライブラリ追加した方が早くね問題
けど数行で終わるならいちいち使わなくてもいいですよね
ぶっちゃけもうjava既存のでなんでも解決できそうな気分になってます
最近apache.common.lang全然見ない...

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

java 状態マシン 自動車

目次 ⇒ Javaアルゴリズムライブラリ-Artery-サンプル

Q08_01.java
package jp.avaj.lib.algo;

import jp.avaj.lib.test.ArTest;

/**
ArStateMechine-状態マシン-自動車

・状態マシンのごく簡単なサンプルとして自動車を取り上げる
  ・実際の自動車と比較すれば、簡単すぎるが、次の動作をする
  ・アクセルを踏む⇒エンジンが回転する⇒車輪が回転する
  ・アクセルを離す⇒エンジンが停止する⇒車輪が停止する

・本サンプルではArStateMachineの実装としてArStateMachineDefaultを使用している
・ArStateMachineDefaultは状態マシンが変化した時に、さらにイベントを発生させることができる
・アクセル⇒エンジン⇒車輪のイベント伝達は、この機能を利用している.

 */
public class Q08_01 {

  public static void main(String[] args) {
    // 車輪の状態マシン
    ArStateMachineDefault wheel = new ArStateMachineDefault();
    {
      // 状態遷移マトリックス
      ArStateTransition[] matrix = new ArStateTransition[] {
        // 回転中に停止イベント⇒停止する
        new ArStateTransition(WheelState.ROTATE,WheelEvent.OFF,WheelState.STOP,null),
        // 停止中に動作イベント⇒回転する
        new ArStateTransition(WheelState.STOP,WheelEvent.ON,WheelState.ROTATE,null),
      };
      // 初期設定する,最初は停止状態
      wheel.init(WheelState.STOP, matrix);
    }
    // エンジンの状態マシン
    ArStateMachineDefault engine = new ArStateMachineDefault();
    {
      // 状態遷移マトリックス
      ArStateTransition[] matrix = new ArStateTransition[] {
        // 回転中に停止イベント⇒停止する、WheelEvent.OFFを出す
        new ArStateTransition(EngineState.ROTATE,EngineEvent.OFF,EngineState.STOP,WheelEvent.OFF),
        // 停止中に起動イベント⇒回転する、WheelEvent.OFFを出す
        new ArStateTransition(EngineState.STOP,EngineEvent.ON,EngineState.ROTATE,WheelEvent.ON)
      };
      // 初期設定する、最初は停止状態
      engine.init(EngineState.STOP,matrix);
      // 車輪と結びつける(trueは接続する,falseは接続断する)⇒イベントが送信される
      engine.connect(wheel,true);
    }
    // アクセルの状態マシン
    ArStateMachineDefault accel = new ArStateMachineDefault();
    {
      // 状態遷移マトリックス
      ArStateTransition[] matrix = new ArStateTransition[] {
        // 踏込んだ状態で離すイベント⇒OFFになる,EngineEvent.OFFを出す
        new ArStateTransition(AccelState.ON,AccelEvent.OFF,AccelState.OFF,EngineEvent.OFF),
        // 離した状態で踏込むイベント⇒ONになる,EngineEvent.ONを出す
        new ArStateTransition(AccelState.OFF,AccelEvent.ON,AccelState.ON,EngineEvent.ON)
      };
      // 初期設定する、最初は離した状態
      accel.init(AccelState.OFF,matrix);
      // エンジンと結びつける(trueは接続する,falseは接続断する)⇒イベントが送信される
      accel.connect(engine,true);
    }

    // テストケースを開始する
    ArTest.startTestCase("Q08_01");

    // アクセルを踏み込む
    accel.sendEvent(AccelEvent.ON);
    // エンジンが回転していることを確認する
    ArTest.equals("accel:on","expected",EngineState.ROTATE,"engine",engine.getState());
    // 車輪が回転していることを確認する
    ArTest.equals("accel:on","expecteed",WheelState.ROTATE,"wheel",wheel.getState());

    // アクセルを離す
    accel.sendEvent(AccelEvent.OFF);
    // エンジンが停止していることを確認する
    ArTest.equals("accel:off","expected",EngineState.STOP,"engine",engine.getState());
    // 車輪が停止していることを確認する
    ArTest.equals("accel:off","expecteed",WheelState.STOP,"wheel",wheel.getState());

    // テストケースを終了する
    ArTest.endTestCase();
  }
  /** アクセルの状態. */
  static enum AccelState { ON,OFF; }
  /** アクセルへのイベント. */
  static enum AccelEvent { ON,OFF; }

  /** エンジンの状態. */
  static enum EngineState { ROTATE,STOP; }
  /** エンジンへのイベント. */
  static enum EngineEvent { ON,OFF; }

  /** 車輪の状態. */
  static enum WheelState { ROTATE,STOP; }
  /** 車輪へのイベント. */
  static enum WheelEvent { ON,OFF; }
}


結果は次のとおり。

result.txt
**** Q08_01 start ****
OK accel:on:expected=ROTATE:engine=ROTATE
OK accel:on:expecteed=ROTATE:wheel=ROTATE
OK accel:off:expected=STOP:engine=STOP
OK accel:off:expecteed=STOP:wheel=STOP
**** Q08_01 summary ****
test count = 4
success    = 4

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む