読者です 読者をやめる 読者になる 読者になる

山崎屋の技術メモ

IT業界で働く中で、気になること、メモしておきたいことを書いていきます。

【postgresql】 SQL Shell (psql) でパスワードの入力を不要にする方法

database PostgreSQL

Windowspostgresqlコマンドラインで操作する場合、インストールすると一緒についてくる SQL Shell を使用することがある。そのときサーバー・データベース名・ポート・ユーザ名・クライアントエンコーディングなどを入力する必要がある。

こんな感じ。

f:id:yyama1556:20161127145521p:plain

ただし、デフォルト表示されている内容で問題なければ Enter キーを押下していくだけで良い。

デフォルトの値を変更する方法は以下の記事を参考に。

yyama1556.hateblo.jp



下図の場合、 Enter を押せば、赤線で示した内容を入力したことになる。

f:id:yyama1556:20161127145946p:plain

だけど、最後の「ユーザ xx のパスワード:」と表示されている部分で、パスワードだけは入力しないといけない。これがメンドイ。

パスワードを入力しなくてすむように設定する

ソフトウェアのバージョンは次のとおり。

OS : Windows7
Postgresql : 9.5.3

一言で言えば「パスワードファイル」を作成して、所定の場所に置いておくだけだ。

このサイトの内容をわかりやすくまとめたい。

https://www.postgresql.jp/document/9.4/html/libpq-pgpass.html

パスワードファイルを置く場所

先ほどのサイトから引用。

Microsoft Windowsでは、このファイルの名前は%APPDATA%\postgresql\pgpass.conf(ここで%APPDATA%はユーザのプロファイル内のアプリケーションデータディレクトリ)です。

[%APPDATA%]ってどこ?って人は、コマンドプロンプトで [ set APPDATA ] と打ってみる。

f:id:yyama1556:20161127151547p:plain

私の場合、[ C:\Users\yyama\AppData\Roaming ]がそのフォルダにあたる。この下に[ postgresql ]というフォルダを作成する。

パスワードファイルの名前

さきほどの引用にもあるが Windows の場合、[ pgpass.conf ]というファイル名になる。 Linux の場合は「ユーザのホームディレクトリの.pgpassまたはPGPASSFILEで設定されるファイル」となっている。

ファイルの内容

ホスト名・ポート・データベース名・ユーザ名・パスワードをコロンで区切って書き込んでおく。

こんな感じ。最初に#がある行は、コメントとして無視される。

#hostname:port:database:username:password
localhost:5432:postgres:postgres:postgres

実際に試してみる

実際にファイルを作成してから、 SQL Shell を起動してみると、パスワードの入力が不要になっていることを確認できた。

f:id:yyama1556:20161127152801p:plain

複数ユーザのパスワードも管理する

パスワードファイルには複数行書き込むことができる。他のユーザや、postgresql内のほかのデータベースのパスワードも管理できる。

まずは[ new_user ]というユーザを作った。

f:id:yyama1556:20161127154510p:plain

そして、[ pgpass.conf ]ファイルに1行追記し、以下のように修正した。

#hostname:port:database:username:password
localhost:5432:postgres:postgres:postgres
localhost:5432:postgres:new_user:pass1

そうすると[ new_user ]でログインする際にも、パスワードの入力は不要になった。

f:id:yyama1556:20161127154804p:plain

ワイルドカードも使えるよ!

例えば、先ほど追加したユーザ[ new_user ]のパスワードがユーザ[ postgres ]と同じ[ postgres ]だったとする。その場合、ユーザにかかわらずパスワードは[ postgres ]で良いことになる。

その際には、[ pgpass.conf ]ファイルのユーザ名のところに[ * ]をセットすれば、1行で書いても OK だ。

#hostname:port:database:username:password
localhost:5432:postgres:*:postgres


以上、開発時、パスワード入力のひと手間を不要にする方法をメモした。当たり前だが、本番環境でこのような設定を行ってはいけません!

内部構造から学ぶPostgreSQL 設計・運用計画の鉄則 (Software Design plus)

内部構造から学ぶPostgreSQL 設計・運用計画の鉄則 (Software Design plus)

PostgreSQL全機能バイブル

PostgreSQL全機能バイブル

PostgreSQL徹底入門 第3版

PostgreSQL徹底入門 第3版

【java】DTO のテストコードを自動生成への道②

java


前回の記事はこちら。

yyama1556.hateblo.jp


とりあえず動くものを作った。

github.com

DtoTestGenerator と命名した。

今のところ対応している型は int, long, Integer, Long, String のみ。

テスト対象にできるクラスは 1 個 で、クラス名もハードコードとなっている。(今後、機能追加していく)

生成されるテストコード

次のような DTO があるとする。

package org.some.dto;

import java.io.Serializable;

public class SomeDto implements Serializable {

	private static final long serialVersionUID = 1399332442638064271L;

	private int age;
	private String firstName;
	private String secondName;
	private int height;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getSecondName() {
		return secondName;
	}

	public void setSecondName(String secondName) {
		this.secondName = secondName;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	@Override
	public String toString() {
		return "SomeDto [age=" + age + ", firstName=" + firstName + ", secondName=" + secondName + ", height=" + height
				+ "]";
	}

}

DtoTestGenerator の main メソッドを実行すると、out フォルダに次のようなテストコードが生成される。実際の出力では、ソースのインデントを考慮していないが、整えた形で掲載する。

package org.some.dto;

import static org.junit.Assert.*;

import org.junit.Test;

public class SomeDtoTest {

	@Test
	public void setAgeでセットした値がgetAgeで取得できること() {

		// Setup
		SomeDto dto = new SomeDto();

		// Exercise
		dto.setAge(0);
		Integer act = dto.getAge();

		// Verify
		assertEquals(Integer.valueOf(0), act);

	}

	@Test
	public void setFirstNameでセットした値がgetFirstNameで取得できること() {

		// Setup
		SomeDto dto = new SomeDto();

		// Exercise
		dto.setFirstName("a");
		String act = dto.getFirstName();

		// Verify
		assertEquals("a", act);

	}

	@Test
	public void setSecondNameでセットした値がgetSecondNameで取得できること() {

		// Setup
		SomeDto dto = new SomeDto();

		// Exercise
		dto.setSecondName("b");
		String act = dto.getSecondName();

		// Verify
		assertEquals("b", act);

	}

	@Test
	public void setHeightでセットした値がgetHeightで取得できること() {

		// Setup
		SomeDto dto = new SomeDto();

		// Exercise
		dto.setHeight(1);
		Integer act = dto.getHeight();

		// Verify
		assertEquals(Integer.valueOf(1), act);

	}

	@Test
	public void toStringでdtoの情報が表示されること() {

		// Setup
		SomeDto dto = new SomeDto();
		dto.setAge(0);
		dto.setFirstName("a");
		dto.setSecondName("b");
		dto.setHeight(1);

		// Exercise
		String act = dto.toString();

		// Verify
		assertEquals("SomeDto [age=0, firstName=a, secondName=b, height=1]", act);

	}

}

getter, setter および toString のテストコードが自動で生成されていることがわかる。

また、工夫した箇所としては、String 型のプロパティが複数ある場合、setter でセットする値は a → b → c ・・・ のように変わっていく。同様に int では 1 → 2 → 3・・・のように変わっていく。

プロジェクトの構成

プロジェクトの構成を簡単に説明する。

ファイルやフォルダの構成は次のようになっている。

f:id:yyama1556:20160924130739p:plain

org.yyama.DtoGenerator がこのプロジェクトの本体であり、main メソッドを実装している。

org.yyama.type 配下に型ごとにクラスを追加していく。DtoTestGenType は abstract なクラスとなっていて、Integer, Long, String の各 Type はこれを継承している。

例えば Date 型に対応したければ DtoTestGenType を継承した DateType を作成する(クラス名は自由)。

プロジェクト直下の out フォルダは生成されたテストコードが格納される場所なのであらかじめ作っておく必要がある。

使い方

例えば以下のように SomeDto プロジェクト配下の SomeDto.java のテストケースを生成したい場合、

f:id:yyama1556:20160924131712p:plain

SomeDto プロジェクトの src フォルダをビルドパスに加える必要がある。

DtoTestGenerator プロジェクトを右クリック→ Properties を選択し、プロパティ画面を表示し、Java Build Path を選択する。

Add Class Folder を選択する。

f:id:yyama1556:20160924132034p:plain

SomeDto プロジェクトの bin フォルダをチェックして OK を押す。

f:id:yyama1556:20160924132332p:plain

あとは対象のクラス名が、DtoTestGenerator.java にベタ書きされているので、必要に応じ修正して main() を実行するだけ。

		// Classを取得
		Class<SomeDto> clazz = SomeDto.class;  // ← テスト対象クラスに応じてここを修正
		String cName = clazz.getSimpleName();

今後実装したい機能

  • 複数 Dto のテストコードを一気に生成
  • パッケージ配下のクラスを自動検索し、XxxDto.java ファイルを見つけて一気に生成
  • Date 型に対応
  • 配列型に対応
  • List型に対応


今日はここまで。でわ。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

java パッケージ配下のクラス一覧を取得 外部ライブラリは使用しない

eclipse java

外部ライブラリを使用せずにパッケージ配下のクラス一覧を取得する方法を調査した。

DIコンテナなどは、「パッケージを指定して、その配下のクラスをコンテナに登録する」というのが一般的だと思うが、その仕組みを理解するのに役に立つ。

あと、個人的な課題としてDTOクラスのテストコードを自動生成したいと思っていて、リフレクションを使用したクラス一覧の取得方法を確立しておく必要があった。

参考にしたページ。
package 配下のクラス一覧を取得する方法いろいろ - A Memorandum
Javaで特定のパッケージ配下のクラスを検索する - CLOVER

参考にしたページのやり方をそのままでもいいが、私の場合、jar ファイルに対応する必要がないので、もうちょっとすっきり書けそうだったので、自分で作ってみた。

ひとまず、ソース全文

package org.yyama.autotest;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

public class GetClassList {
	private static final String PK_NAME = "org.some.classes";

	public static void main(String... args) throws Exception {
		String packageName = PK_NAME;
		List<Class<?>> classes = getClasses(packageName);
		for (Class<?> class1 : classes) {
			System.out.println(class1.getName());
		}
	}

	/**
	 * パッケージ名を文字列で取得し、パッケージ直下のクラスをリストに詰めて返します。
	 * 
	 * @param packageName
	 *            パッケージ名
	 * @return クラスのリスト
	 * @throws IOException
	 * @throws URISyntaxException
	 * @throws ClassNotFoundException
	 */
	private static List<Class<?>> getClasses(String packageName)
			throws IOException, URISyntaxException, ClassNotFoundException {
		// クラスローダを取得
		ClassLoader cl = Thread.currentThread().getContextClassLoader();

		// パッケージ配下のリソースを取得(複数の場合あり)
		Enumeration<URL> e = cl.getResources(packageName.replace(".", "/"));

		// 返却用のリストを宣言
		List<Class<?>> classes = new ArrayList<>();

		// パッケージ配下のリソースの数だけループ
		for (; e.hasMoreElements();) {

			// リソースのURLを取得
			URL url = e.nextElement();

			// URLをファイルオブジェクトに変換
			File dir = new File(url.getPath());

			// ディレクトリ配下のファイル数分ループ
			for (String path : dir.list()) {

				// ".class"で終わるファイルのみ返却用のリストに追加
				if (path.endsWith(".class")) {
					classes.add(Class.forName(packageName + "." + path.substring(0, path.length() - 6)));
				}
			}
		}
		return classes;
	}
}

処理の大体の流れはコメントに記載した。

参考にしたページでは、

		// パッケージ配下のリソースを取得(複数の場合あり)
		Enumeration<URL> e = cl.getResources(packageName.replace(".", "/"));

の部分を、以下のように書いていた。

        URL url = classLoader.getResource(resourceName);

getResource と getResources の違いがある。あまり気にする必要はないと思うが、同じパッケージ名が複数のプロジェクトで使用されていた場合 getResource だと対応できないので getResources を使用している。

以下のパッケージを指定している箇所は、適宜変更して欲しい。パッケージ名は引数で渡す方法に変更してもいいかも知れない。Eclipse で使用する場合、引数の指定が面倒くさいので、ハードコードとしている。

	private static final String PK_NAME = "org.some.classes";

実行方法

クラス一覧を作成したいプロジェクトをビルドパスに加える。

方法は以下のとおり。

GetClassList クラスを含むプロジェクトを右クリックして properties を選択し、プロジェクトのプロパティ画面を表示する。左側のツリーから Java Build Path を選択する。

f:id:yyama1556:20160918145108p:plain

[ Add Class Folder ... ] を選択する。

f:id:yyama1556:20160918145216p:plain

フォルダ選択画面が表示されるので、クラス一覧を作成したいパッケージが置いてあるフォルダを選択する。下図の例では Classes プロジェクトの bin フォルダを選択している。

f:id:yyama1556:20160918145438p:plain

Classes プロジェクトの構成は以下のとおり。

f:id:yyama1556:20160918144101p:plain

クラス名を取得するのが目的なのでクラスの中身は空っぽ。

そして、実行結果がこちら。

org.some.classes.A
org.some.classes.B
org.some.classes.C

パッケージ配下のクラスがすべて取得できた。

おしまい。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

【Spring MVC】簡単なアンケートアプリで学習する。その一

java spring mvc eclipse spring

Spring MVC でいろいろ勉強していきたいので、ベースとなるアプリを作った。

一応動くが、まだ実装は不十分である。今後、少しずつ不足している箇所を実装していきたい。

アプリの動き

3 画面でできている。

トップ画面はアンケートの入力画面。

f:id:yyama1556:20160910145136p:plain

ユーザに「年齢」と「知ったきっかけ」を入力してもらう。以降「入力画面」と呼ぶ。

「確認画面へ」ボタンをクリックすると、入力内容が確認できる画面に遷移する。

f:id:yyama1556:20160910145501p:plain

ユーザは自分が入力した内容を確認し、「完了画面へ」ボタンを押下する。「入力画面へ戻る」ボタンはまだ実装していない。今はブラウザの戻るボタンで戻ってもらうしかない。これくらいの小さなアプリではあまり気にすることはないが、一般的なWEBアプリでは戻るボタンを使用した操作をすべての画面で想定することはほぼ不可能である(操作パターンが多くなりすぎるため)。ちゃんと「戻る」ボタンを実装しておくのがセオリーだ。

この画面を以降「確認画面」と呼ぶ。

完了画面ではお礼のメッセージと入力画面に戻るリンクを提供している。

f:id:yyama1556:20160910150244p:plain

以降「完了画面」と呼ぶ。

フォルダ構成

フォルダ構成は次のとおり。

f:id:yyama1556:20160910150424p:plain

次の記事を参考にして Eclipse で Spring MVC プロジェクトを作成し、いくつかのファイルを追加する。

yyama1556.hateblo.jp

ルートパス"/"で入力画面に遷移できるように、コンテキストルートを修正した。

プロジェクトを右クリックして「Properties」を選択し、「Web Project Settings」の「Context root」を"/"に修正する。

f:id:yyama1556:20160910151331p:plain

各ファイルの内容

SampleController は自作のコントローラである。

package org.yyama.sample.cntrl;

import static org.springframework.web.bind.annotation.RequestMethod.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.yyama.sample.form.UserForm;

@Controller
public class SampleController {

	@RequestMapping(value = "/", method = GET)
	public String input(UserForm userForm, Model model) {
		model.addAttribute("ageList", getAgeList());
		model.addAttribute("triggerMap", getTriggerCheckbox());
		return "input";
	}

	@RequestMapping(value = "/confirm", method = POST)
	public String confirm(UserForm userForm) {
		return "confirm";
	}

	@RequestMapping(value = "/send", method = POST)
	public String send() {
		return "completion";
	}

	/**
	 * 年齢セレクトボックス用のリストを作成し返す
	 */
	private List<Integer> getAgeList() {
		List<Integer> list = new ArrayList<>();
		for (int i = 18; i < 100; i++) {
			list.add(i);
		}
		return list;
	}

	/**
	 * きっかけチェックボックス用のマップを作成し返す。
	 */
	private Map<Integer, String> getTriggerCheckbox() {
		Map<Integer, String> map = new HashMap<>();
		map.put(1, "チラシを見て");
		map.put(2, "CM を見て");
		map.put(3, "友人に進められて");
		map.put(4, "ググったら出たから");
		map.put(5, "その他");
		return map;
	}

}

@RequestMapping がついているメソッドでリクエストを受け付ける。詳細は次の記事を参照して欲しい。

yyama1556.hateblo.jp

UserForm はユーザが入力した内容を保持するためのフォームクラスだ。これも自作。

package org.yyama.sample.form;

public class UserForm {

	/** 年齢 */
	private String age;

	/** サイトを知ったきっかけ */
	private String[] trigger;

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}

	public String[] getTrigger() {
		return trigger;
	}

	public void setTrigger(String[] trigger) {
		this.trigger = trigger;
	}
}

次に JSP 3種類を紹介する。難しいことはしていないので、不明な記述があったら Google で調べればすぐに出てくるだろう。

入力画面の input.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
td, th {
	padding: 20px;
}
</style>
<title>入力画面</title>
</head>
<body>
	<h1>サンプルアンケート</h1>
	<form:form action="confirm" modelAttribute="userForm">
		<table cellpadding="3">
			<tr>
				<th valign="top" align="right">年齢:</th>
				<td><form:select path="age" items="${ageList}" /></td>
			</tr>
			<tr>
				<th valign="top" align="right">知ったきっかけ(複数選択可):</th>
				<td><form:checkboxes path="trigger" items="${triggerMap}"
						delimiter="<br />" /></td>
			</tr>
			<tr >
				<td colspan="2" align="center"><input type="submit" value="確認画面へ" /></td>
			</tr>
		</table>
		<p></p>
	</form:form>
</body>
</html>

確認画面の confirm.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
td, th {
	padding: 20px;
}
</style>
<title>確認画面</title>
</head>
<body>
	<h1>サンプルアンケート</h1>
	<form:form action="/send" modelAttribute="userForm">
		<table cellpadding="3">
			<tr>
				<th valign="top" align="right">年齢:</th>
				<td><c:out value="${userForm.age}" /></td>
			</tr>
			<tr>
				<th valign="top" align="right">知ったきっかけ(複数選択可):</th>
				<td>
				<c:forEach items="${userForm.trigger}" var="t">
				<c:out value="${t}" /><br />
				</c:forEach>
			</tr>
			<tr >
				<td colspan="2" align="center"><input type="submit" value="完了画面へ" /></td>
			</tr>
		</table>
		<p></p>
	</form:form>
</body>
</html>

完了画面の completion.jsp

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<%@ page contentType="text/html;charset=UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<title>完了画面</title>
</head>
<body>
	<h1>ご協力ありがとうございました。</h1>
</body>
<a href="/">top画面へ</a>
</html>

servlet-context.xml はデフォルトのものを使用するが、わかりやすくコメントを変更した。

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

	<!-- アノテーションでBeanを定義する -->
	<annotation-driven />

	<!-- org.yyama.sample パッケージ配下で Spring のアノテーション( @Controller など )が 、-->
	<!-- 付けられたクラスを Bean 定義する -->
	<context:component-scan base-package="org.yyama.sample" />
	
	<!-- jspの設定 -->
	<beans:bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<beans:property name="prefix" value="/WEB-INF/views/" />
		<beans:property name="suffix" value=".jsp" />
	</beans:bean>

</beans:beans>

そのほか、 log4j.xml 、 root-context.xml 、 web.xmlEclipse でプロジェクトを作成したときのまま修正していない。

最後に、pom.xml 。ライブラリのバージョンだけを変更している。

<?xml version="1.0" encoding="UTF-8"?>
<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>org.yyama</groupId>
	<artifactId>sample</artifactId>
	<name>Sample</name>
	<packaging>war</packaging>
	<version>1.0.0-BUILD-SNAPSHOT</version>
	<properties>
		<java-version>1.8</java-version>
		<org.springframework-version>4.3.2.RELEASE</org.springframework-version>
		<org.aspectj-version>1.8.9</org.aspectj-version>
		<org.slf4j-version>1.7.21</org.slf4j-version>
	</properties>
	<dependencies>
		<!-- Spring -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${org.springframework-version}</version>
			<exclusions>
				<!-- Exclude Commons Logging in favor of SLF4j -->
				<exclusion>
					<groupId>commons-logging</groupId>
					<artifactId>commons-logging</artifactId>
				 </exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${org.springframework-version}</version>
		</dependency>
				
		<!-- AspectJ -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjrt</artifactId>
			<version>${org.aspectj-version}</version>
		</dependency>	
		
		<!-- Logging -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>${org.slf4j-version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>jcl-over-slf4j</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>${org.slf4j-version}</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.15</version>
			<exclusions>
				<exclusion>
					<groupId>javax.mail</groupId>
					<artifactId>mail</artifactId>
				</exclusion>
				<exclusion>
					<groupId>javax.jms</groupId>
					<artifactId>jms</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jdmk</groupId>
					<artifactId>jmxtools</artifactId>
				</exclusion>
				<exclusion>
					<groupId>com.sun.jmx</groupId>
					<artifactId>jmxri</artifactId>
				</exclusion>
			</exclusions>
			<scope>runtime</scope>
		</dependency>

		<!-- @Inject -->
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
				
		<!-- Servlet -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.5</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet.jsp</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.1</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
	
		<!-- Test -->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.7</version>
			<scope>test</scope>
		</dependency>        
	</dependencies>
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-eclipse-plugin</artifactId>
                <version>2.9</version>
                <configuration>
                    <additionalProjectnatures>
                        <projectnature>org.springframework.ide.eclipse.core.springnature</projectnature>
                    </additionalProjectnatures>
                    <additionalBuildcommands>
                        <buildcommand>org.springframework.ide.eclipse.core.springbuilder</buildcommand>
                    </additionalBuildcommands>
                    <downloadSources>true</downloadSources>
                    <downloadJavadocs>true</downloadJavadocs>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.5.1</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                    <compilerArgument>-Xlint:all</compilerArgument>
                    <showWarnings>true</showWarnings>
                    <showDeprecation>true</showDeprecation>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>1.2.1</version>
                <configuration>
                    <mainClass>org.test.int1.Main</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

今後、このアプリをベースに実装を追加していく。私の説明不足などで動かない場合、コメントしていただけると大変ありがたい。

今日はここまで。


Spring 関連記事へのリンク集つくりました。


java のいろいろな型の型名を文字列で出力させてみる

java

DTO のテストコードを自動生成したくて、前回リフレクションの復習をした。

型の判別をするために、テスト対象となるクラスのプライベート変数の型を取得しているが、どの型がどんな文字列で表現されるのか気になったので調べてみた。

次のようなクラスを用いて、 SomeDtoクラスのプライベート変数の名前と型を表示してみる。

package org.yyama;

import java.lang.reflect.Field;

public class Main {
	public static void main(String... args) throws Exception {

		// 対象のクラスを取得
		Class<SomeDto> clazz = SomeDto.class;

		// フィールドをすべて取得する。 getFields() というメソッドもあるが、
		// それでは private メソッドを取得できない。
		Field[] fields = clazz.getDeclaredFields();

		for (Field field : fields) {
			// Field#getName() で変数名、
			// Field#getType() で型名を取得できる。
			System.out.println(field.getName() + " : " + field.getType());
		}
	}
}

基本型(プリミティブ型)

まず、基本型について確認する。

SomeDto を次のようにする。

package org.yyama;

public class SomeDto {
	private boolean vBoolean;
	private char vChar;
	private byte vByte;
	private short vShort;
	private int vInt;
	private long vLong;
	private float vFloat;
	private double vDouble;
}

そして Main クラスの main メソッドを実行した結果がこちら。

vBoolean : boolean
vChar : char
vByte : byte
vShort : short
vInt : int
vLong : long
vFloat : float
vDouble : double

完全にそのまんま表示される。

参照型(要はクラス)

次にいくつかのクラスを試してみる。 SomeDto は次のとおり。

package org.yyama;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class SomeDto {
	private Integer vInteger;
	private Character vCharacter;
	private String vString;
	private Map<String, String> vMap;
	private List<String> vList;
	private Date vUtilDate;
	private java.sql.Date vSqlDate;
}

変数名と型名を取得した結果がこちら

vInteger : class java.lang.Integer
vCharacter : class java.lang.Character
vString : class java.lang.String
vMap : interface java.util.Map
vList : interface java.util.List
vUtilDate : class java.util.Date
vSqlDate : class java.sql.Date

型の前に class や interface が出力される。そしてクラス名はパッケージ付きで表示されれるため、 java.util.Date と java.sql.Date の区別もつく。

基本型の配列

では、基本型の配列を見てみる。

SomeDto。

package org.yyama;

public class SomeDto {
	private boolean[] vArrBoolean;
	private char[] vArrChar;
	private byte[] vArrByte;
	private short[] vArrShort;
	private int[] vArrInt;
	private long[] vArrLong;
	private float[] vArrFloat;
	private double[] vArrDouble;
}

main の実行結果がこちら。

vArrBoolean : class [Z
vArrChar : class [C
vArrByte : class [B
vArrShort : class [S
vArrInt : class [I
vArrLong : class [J
vArrFloat : class [F
vArrDouble : class [D

最初に class と表示されていることから、もはや基本型ではない。そして片括弧の次に大文字アルファベットが表示されている。だいたいは型の先頭 1 文字を大文字にしたものだが double は J で boolean は、なんと Z だ。

参照型の配列

最後に参照型の配列。

SomeDto。

package org.yyama;

import java.util.Date;
import java.util.List;
import java.util.Map;

public class SomeDto {
	private Integer[] vArrInteger;
	private Character[] vArrCharacter;
	private String[] vArrString;
	private Map<String, String>[] vArrMap;
	private List<String>[] vArrList;
	private Date[] vArrUtilDate;
	private java.sql.Date[] vArrSqlDate;
}

main の実行結果

vArrInteger : class [Ljava.lang.Integer;
vArrCharacter : class [Ljava.lang.Character;
vArrString : class [Ljava.lang.String;
vArrMap : class [Ljava.util.Map;
vArrList : class [Ljava.util.List;
vArrUtilDate : class [Ljava.util.Date;
vArrSqlDate : class [Ljava.sql.Date;

配列ではない場合と同じく、最初は class から始まる。interface と表示されていた Map や List も配列にすると class となる。そして片括弧の次には大文字の L (何の略だ?)。その後、パッケージ付きのクラス名が続き、最後になぜかセミコロンで終わる。

まとめ

java の型がどのような文字列で表現されるのか整理できた。

おしまい。

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)