Java/JSON Jacksonを使ってみる マッピング編

Jacksonとは

Jacksonはhttp://jackson.codehaus.org/で開発されている
JSONデータをJavaにマッピングするためのライブラリ。

jackson-databindを利用すればJavaオブジェクトへ直接データをマッピングできる。

jacksonを利用するにあたって、どのようにJavaオブジェクトへマッピングされるのかを検証してみました。

Javaオブジェクトへのマッピング方法

下記のような構文でJavaオブジェクトへマッピングする事ができます。
入力にはString、File、InputStream、Readerなどが、
出力にはString、File、OutputStream、Writerなどが指定可能です。

ObjectMapper mapper = new ObjectMapper();

// 文字列からのデシリアライズ
Person person = mapper.readValue(
	"{\"name\":\"Person1\",\"age\":20}",
	Person.class));
	
// 文字列へのシリアライズ。
System.out.println(
	mapper.writeValueAsString(person));

メソッドについての詳細は割愛。
どのようにマッピングされるかを検証する。

クラスへデータをマッピングする

JSON

{"name":"Person1", "age":20}

Personクラス

package jackson.sample;

import java.math.BigDecimal;

public class Person 
{
	public String name;
	public int age;
}

JavaBeansのプロパティを作成せずとも(getter、setterを作成せずとも)
パブリックなフィールドを同等の物としてマッピングできる。

ネストされたプロパティへデータをマッピングする

JSON

{
	"person1":	{"name":"Person1", "age":0.1},
	"person2":	{"name":"Person2", "age":0.1}
}

PersonPairクラス

package jackson.sample;

public class PersonPair 
{
	public Person person1;
	public Person person2;
}

クラスの配列へデータをマッピングする

クラスの配列へマッピングする例。

JSON

[
	{"name":"Person1", "age":20},
	{"name":"Person2", "age":21}
]

readValueでPerson[].classを指定すればマッピングできる。

Listへデータをマッピングする

プロパティへリストをマッピングする例。

JSON

{
	"persons":	[
		{"name":"Person1", "age":20},
		{"name":"Person2", "age":21}
	]
}

Personsクラス

package jackson.sample;

import java.util.List;

public class Persons2
{
	public List<Person> persons;
}

クラスのプロパティでさえあればList<Person>へマッピングできる。

まとめ

JacksonではネストされたプロパティやクラスのListへのマッピングなど
柔軟に対応できるようになっている。

Java8の新しい日付/時刻処理API JSR310について思ったこと(2)

JSR310のAPI」について。

Javaの新しい日付/時刻処理API JSR310について思ったこと」の続き。

もう遅いんだろうけど・・・

全体的な感想

一般的に紹介されるAPIはまあそれなりにいい感じ。 でも、それ以外がアレ過ぎ。

API汚しすぎと思う。

temporalイラネ

java.time.temporalパッケージとか、この名称でAPIへ入れるの?

この機能不要じゃない?

TemporalやTemporalAmountを継承することでAPIが分け分からない事になってる。

OffsetDateTimeがtemporalパッケージに入っていた時期もあったみたいだし、 反対があった機能を押し込めた様にしか見えないw

PeriodとDurationとTemporalAmount

Framework-level interfaceを見ないとDurationとかPeriodLocalDateに足せるの分からないんですけど・・・

初心者でも理解しやすい構造にしておかないと足引っ張るよ。

また、Periodは1年3ヶ月3日みたいな期間指定ができるクラスみたいだが、 営業日や月末考えなきゃいけないPeriodでは業務系は扱うには足りないし、 システム系ならもっとシンプルに有効日数とかで表現できるでしょ。

APIでのサポートはDurationだけでよかったんじゃない?

ChronoLocalDateイラネ

JapaneseDateとLocalDateの比較なんて要らないから、 LocalDateとJapaneseDateを相互変換する方法を簡単にするべき。

和暦の扱いはJapaneseCalendarにLocalDateセットするんで良いんだって。

たぶん、他のローカライズされた日付クラスも同じ。

ChronoLocalDateTimeChronoZonedDateTimeも同じ理由で要らないと思う。

Java8の新しい日付/時刻処理API JSR310について思ったこと

Java Time API,Java 8で提供」の記事より。 JSR310と言うのを見つけた。 Java 1.8から利用可能になるらしい。 OffsetDateTimeというクラスを使えばW3CDTFの日時表記まで対応できる。

これは今のDate、Calendar、TimeZoneの置き換えと位置付けるよう。 既存APIの問題点もクリアされている。

でも、本当にこのままの名前付けでやるの?ここまでやるの?

既存APIの問題点って下記くらいと思う。

  • java.util.Dateがimmutableでない
  • SimpleDateFormatがW3CDTFに対応できていない
  • 精度がミリ秒と最近の事情を考えると低い

和暦の取り扱い

和暦を扱うJapaneseDateとか日本人的に見ても誰得としか思えない。

JapaneseDate date = JapaneseDate.now();
System.out.println(date.toString());

レビューに日本人いなかったんだろうか・・・

結局はDateTimeとCalendarの2段構成でよかったんじゃないの?

Calendarが使いにくいのはGregorianCalendarクラスを直接newできれば済む話。

リフレクションでJava Genericsで指定された型パラメータを取得する

前置き

List<T>への項目追加時に自動的に型変換する仕組みが作りたかったため、 作る方法がないか調べてみた。 総称型の具象化された型パラメータを扱うためのjava.lang.reflectの機能の説明になる。

JavaのGenericsはObject型をObject型以外の型として 透過的に扱える仕組みであるため、 実行時にオブジェクトから型パラメータを取得できない。(.NETはできる)

しかし、クラスのフィールドやメソッドからは具象化された型パラメータの型情報を取得できる。

総称型にも対応するType型

JDK 1.5以降、Class型に対して総称型を扱うランタイム情報を持つ、Type型が導入されている。 この型を実装するインターフェースは下記となる。

Class               --- Classオブジェクトも継承している。
GenericArrayType    --- 総称配列型 (T)
ParameterizedType   --- 総称型(List<T>等)
WildcardType        --- ワイルドカード(?)

Listの型パラメータの取得はParameterizedTypeのgetActualTypeArguments()を使えばできる。

Type型取得方法

java.lang.reflectでは下記の方法でTypeオブジェクトを取得できる。

Field field = ....;

Type type = field.getGenericType();

Method method = ...;

Type type = method.getGenericReturnType();
Type types = method.getGenericParameterTypes();

型定義と取得されるType型の構造サンプル

下記に各種の型定義に対して、どのようなType型が取得されるかを検証するコードとその実行結果を記載する。

package net.dachicraft.toolkit.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class GenericTest<T> 
{
    public List<String> objs1;
	public Object objs2;
	public List<List<String>> objs3;
	public T objs4;
	public T objs5;
		
	public static void main(String args) throws Exception
	{
		Type type;
		
		Field field1 = GenericTest.class.getField("objs1");
		System.out.println("[objs1]");
		type = field1.getGenericType();
		System.out.println(type + " : " + type.getClass());
		
		ParameterizedType paramType = (ParameterizedType)field1.getGenericType();
		for(Type i : paramType.getActualTypeArguments()) {
			System.out.println(i + " : " + i.getClass());
		}
		
		Field field2 = GenericTest.class.getField("objs2");
		System.out.println("[objs2]");
		type = field2.getGenericType();
		System.out.println(type + " : " + type.getClass());
		
		
		Field field3 = GenericTest.class.getField("objs3");
		System.out.println("[objs3]");
		type = field3.getGenericType();
		System.out.println(type + " : " + type.getClass());
		
		type = ( (ParameterizedType)type).getActualTypeArguments()[0];
		System.out.println(type + " : " + type.getClass());
		type = ( (ParameterizedType)type).getActualTypeArguments()[0];
		System.out.println(type + " : " + type.getClass());
		
		
		Field field4 = GenericTest.class.getField("objs4");
		System.out.println("[objs4]");
		type = field4.getGenericType();
		System.out.println(type + " : " + type.getClass());

		Field field5 = GenericTest.class.getField("objs5");
		System.out.println("[objs5]");
		type = field5.getGenericType();
		System.out.println(type + " : " + type.getClass());

		type = ( (GenericArrayType)type).getGenericComponentType();
		System.out.println(type + " : " + type.getClass());
	}
}

実行結果

[objs1]
java.util.List<java.lang.String> : class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class java.lang.String : class java.lang.Class
[objs2]
class java.lang.Object : class java.lang.Class
[objs3]
java.util.List<java.util.List<java.lang.String>> : class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
java.util.List<java.lang.String> : class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
class java.lang.String : class java.lang.Class
[objs4]
T : class sun.reflect.generics.reflectiveObjects.TypeVariableImpl
[objs5]
T[] : class sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl
T : class sun.reflect.generics.reflectiveObjects.TypeVariableImpl

objs3のList<List<String>>の定義ではParameterizedTypeが入れ子になっているのが分かる。

Apache httpdでSubversionリポジトリをapacheで公開する。

Subversionリポジトリhttpdで公開する方法。 認証はhttpのbasic認証としているが、httpで使用できる全ての認証方式が利用できる。 認証の主体はSubversionではなくhttpとなる。.htpasswdファイルが必用。

httpdSubversionの連携にはmod_dav_svnが必用。

<Location 任意のURLパス>
    DAV svn
    SVNPath Subversion Repositoryパス
    
    Order Deny,Allow 
    Allow from all 

    # 認証にBASIC認証を利用する。
    AuthType Basic 
    AuthName "Repository" 
    AuthUserFile .htpasswdファイルのパス 
    Require valid-user 
</Location>

Apache httpdのName Based Virtual Host設定

自分用メモも兼ねて

指定したポートをVirtualHost化する。 この定義を入れるとメインのWebsiteは利用できなくなる。

NameVirtualHost *:80
NameVirtualHost *:443    # USE SSL

VirtualHostの定義。 ServerNameのホスト名でVirtualHostを作成する。 ServerNameが異なれば幾つでも指定可能。

<VirtualHost *:80>
    SuexecUserGroup XXXX XXXX  # cgiをUser/Groupディレクティブで全体に対して指定したユーザと
                               # 異なるユーザで実行したい場合の定義。
    ServerAdmin admin@example.com
    DocumentRoot 任意のパス
    ServerName Virtual Hostのホスト名
    ErrorLog 任意のパス/error_log
</VirtualHost>

# SSLサイトの定義
<VirtualHost *:443>
    ServerAdmin admin@example.com
    DocumentRoot 任意のパス
    ServerName Virtual Hostのホスト名
    ErrorLog 任意のパス/error_log

SSLEngine on
SSLCertificateFile etc/apache22/ssl.d/証明書ファイル
SSLCertificateKeyFile etc/apache22/ssl.d/証明書秘密鍵
SSLCACertificateFile etc/apache22/ssl.d/dachicraft.net/CA証明書 </VirtualHost>

オブジェクト指向設計の分析方法について整理してみた

どう考えても手段目標分析の説明になってし(ry

オブジェクト指向設計の分析方法について

問題は目的(=ゴール)に従って分析する。 指標としてはオブジェクトの持つべき能力を分析する。

より複雑な問題に対しては問題をシンプルにするために 下記の手段を駆使して分析する。

  • 部分的な目的(=サブゴール)の導出。(手段目標分析)
  • 既知のオブジェクトの連携。
  • 新しいオブジェクトの発明。

人間が同時に思考できる要素の数は「マジックナンバー7±2」という話もあるように限定される。 同時に考えなければならない範囲の複雑さを一定値以下に抑えるように サブゴールを導出し問題の単純化を行う。 どの層のどの部分を見ても一定値以下の複雑さであることが理想的。

サブゴールの導出

手段目標分析の用語だが、 もちろんオブジェクト指向的な考え方で手段と目標を分析する。

構造化分析手法から連なる設計手法の違いは 結局の所、何を基準に細分化するかと言うところによる。

設計手法の違いも分析基準の違いを除けば手段目標分析と言える。

既知のオブジェクトについて

人間の発想にはやはり限界がある 既知のオブジェクトを増やしておくことが、 設計の精度と効率を高めると考えている。

大規模なフレームワークをただチュートリアルに従って使用するだけでなく、 アーキテクチャを理解する事、 また他人のソースコードを読んでみることが、 既知のオブジェクトのバリエーションを増やす事につながると考える。

新しいオブジェクトの発明について

あまり当てにしない方がいい。 まずは既知のオブジェクトで解決できるか考えること。 次によりよい解法を他人が知っている可能性があるのでそれを知ること。