takayukisの日記 このページをアンテナに追加 RSSフィード

2016.05.23(月)

[]MySQLで日本語の文字が入ったレコードが検索できない時 (JDBC)

JDBC URLに次のプロパティを追加する。

jdbc:mysql://address:3306/dbname?useUnicode=true&characterEncoding=UTF-8

XMLに書くときは、 & を & に。

ツールにはしっかり設定していたのに、サーバの設定ファイルに付け忘れてた。意味不明の結果にしばらく悩んだ(恥)。

[]関連レコード件数で一括update (MySQL)

テーブルAとテーブルBが1対多の関係にあって、最適化か何かのためにAにBの件数を保持するような列があるとすると、以下のような書き方で一括設定できる。

UPDATE
    A, (SELECT count(*) as C, id FROM B) B2
SET
    A.count_cache = B2.C
WHERE
    A.id = B2.id

こんな書き方できるのかっていう。

2016.05.18(水)

[]子とすべての先祖の組み合わせを列挙

下のような複数の親と複数の子を持つことができる構造のデータで、子とすべての先祖の組み合わせを列挙してみます。

A→       →D
    B →C
E→       →F

子→親 とします。

public class Pair {
	public String key;
	public String val;
	public Pair(String key, String val) {
		this.key = key;
		this.val = val;
	}
}
public class FlowNetNode {
	public String name;
	public List<FlowNetNode> parents = new ArrayList<>();
	public FlowNetNode(String name) {
		this.name = name;
	}
	public boolean isAncestorName(String name) {
		for (FlowNetNode node : parents) {
			if (node.name.equals(name)) {
				return true;
			}
			if (node.isAncestorName(name)) {
				return true;
			}
		}
		return false;
	}
	public void addPairs(String key, List<Pair> pairs) {
		pairs.add(new Pair(key, name));
		for (FlowNetNode node : parents) {
			node.addPairs(key, pairs);
		}
	}
}
public class FlowNet {
	public Map<String, FlowNetNode> nodeMap = new HashMap<>();
	public void addFlow(String... nameList) {
		List<String> list = Arrays.asList(nameList);
		addFlow(list);
	}
	public void addFlow(List<String> nameList) {
		FlowNetNode parent = null;
		for (int i = nameList.size() - 1; i >= 0; i--) {
			String name = nameList.get(i);
			FlowNetNode node = nodeMap.get(name);
			if (node == null) {
				node = new FlowNetNode(name);
				nodeMap.put(name, node);
			}
			if (parent != null) {
				if (parent.isAncestorName(name)) {
					throw new RuntimeException("Duplication:" + name);
				}
				node.parents.add(parent);
			}
			parent = node;
		}
	}
	public List<Pair> makePair() {
		List<Pair> result = new ArrayList<>();
		for (Entry<String, FlowNetNode> entry : nodeMap.entrySet()) {
			FlowNetNode node = entry.getValue();
			node.addPairs(node.name, result);
		}
		return result;
	}
	public static void main(String[] args) {
		FlowNet net = new FlowNet();
		net.addFlow("A", "B", "C", "D");
		net.addFlow("B", "E");
		net.addFlow("G", "H", "I", "J");
		net.addFlow("H", "K");
		net.addFlow("L", "H");
		List<Pair> pairs = net.makePair();
		for (Pair pair : pairs) {
			System.out.println(pair.key + "=" + pair.val);
		}
	}
}

2016.04.27(水)

[]Gradleの謎文法(2) タスクの定義

Gradleにおいて、タスクは次のように定義します。

task hello {
    println 'Hello'
}

hello って識別子の宣言っぽいですよね。じゃあ task はメソッド hello の戻り値の型なんですか?

でもGroovyってトップレベルにメソッドを定義できるんでしたっけ?

もう一つ見てみましょう。フォルダをコピーするタスクです。

task myCopy(type: Copy) {
    from 'src'
    into 'dst'
}

どう見てもメソッドみたいな形をしていますが、そこにはメソッドは書けないんです。Groovy的には。

これはめちゃめちゃ混乱させられたんですが、実はGradleは、素のGroovyではなく、Groovyの文法をAST変換を使用して拡張しています。GradleはGroovyの上位互換言語だったんですね。


正解

task は暗黙の project のメソッドで、上記の hello や myCopy は引数の一つになります。

type: Copy は Map 型の引数、その後ろの中括弧 {...} は Closure 型の引数です。

projectの実装:

/src/core/org/gradle/api/internal/project/AbstractProject.java

public Task task(Map options, String task, Closure configureClosure)

public Task task(Map options, Object task, Closure configureClosure)

taskメソッド引数の順番が違うのですが、たぶんこれで合っていると思います。

タスク定義構文のAST変換の実装:

/src/core/org/gradle/groovy/scripts/internal/TaskDefinitionScriptTransformer.java

AST変換の実装を見ても、引数の順番が違う件についてすぐに理解できなかったのでスルーで。


Gradleについての所感

AST変換を行っている箇所は、ドキュメントでは当然の構文として登場するのでGroovy的に理解しようとするとはまります。タスク定義だけでなく、他にもあるらしいです。存在するのか知りませんがGroovyエディタが使えないし、軟弱者にはつらいです。AST変換までしてDSLを充実させる利点はあるんでしょうか。

Antの職人的スクリプト批判してGradleを持ち上げる文章を度々目にしたのですが、Gradleは完全なプログラミング言語ですし、ツールによる支援も今のところ無いので、もっと酷い事になり得るのではないかと思います。

あと、実行速度が遅い。

とは言え、Gradleはこれからのもはや主流。こっちに移行していこうと思っています。

2016.04.21(木)

[]Gradleの謎文法 tasks.withType(JavaCompile) {options.encoding = 'UTF-8'}について

JavaソースコードエンコーディングUTF-8としてコンパイルさせる設定は以下のように書ける。

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

変数 tasks のメソッド withType を呼び出しているが、その後ろに Closure と思われるブロックが続いている。GroovyのドキュメントのLanguage Specificationには、こんな書き方出てこなかったような。

変数 tasks は TaskContainer であるとDSLドキュメントにあるので参照してみる。

withTypeは3種類が継承されており、 Closure を引数に持つメソッドは DomainObjectCollection から継承されている。

<S extends T> DomainObjectCollection<S> withType(Class<S> type,
                                               Closure configureClosure)

DomainObjectCollection (Gradle API 2.12) withType(java.lang.Class,%20groovy.lang.Closure)

おそらく、呼び出されているメソッドはこれ。

試しに書き方を変えて同じ結果が得られるかを確認してみる。

tasks.withType(JavaCompile){println '(1)it=' + it}

tasks.withType JavaCompile, {println '(2)it=' + it}

// エラー
//tasks.withType (JavaCompile), {println '(3)it=' + it}

tasks.withType (JavaCompile)
{println '(4)it=' + it}

tasks.withType JavaCompile, {
    println '(5)it=' + it
}
tasks.withType(JavaCompile, {
    println '(6)it=' + it
})
tasks.withType (JavaCompile) {println '(7)it=' + it}

// おまけ
tasks.withType(JavaCompile).each({println '(8)it=' + it})
tasks.withType(JavaCompile).each {println '(9)it=' + it}
def xx = tasks.withType(JavaCompile)
xx.each({println '(10)it=' + it})
// xx {println 'it=' + it}

メソッド名を省略する文法は無いはずなので、意味合いが異なるが、おまけのeachを使っている書き方も含め、実行結果は同じになった。

件のコードを改めて見てみる。

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

ぱっと見、Groovyのドキュメントには記述を見つけることはできなかったが、末尾のClosureは引数の括弧に含める必要が無いとか。

試しに以下のコードを実行してみる。

class Hoge {
	void m1(String a, Closure cl) {
		cl.call()
	}
	void m2(String a, String b, Closure cl) {
		cl.call()
	}
	void m3(Closure cl1, Closure cl2) {
		cl1.call()
		cl2.call()
	}
	void m4(String a, Closure cl1, Closure cl2) {
		cl1.call()
		cl2.call()
	}
}

def hoge = new Hoge()
hoge.m1('a') {println 'm1.'}
hoge.m2('a', 'b') {println 'm2.'}
hoge.m3 {println 'm3-1.'} {println 'm3-2.'}
hoge.m3() {println 'm3-3.'} {println 'm3-4.'}
hoge.m4('a') {println 'm4-1.'} {println 'm4-2.'}

実行結果

m1.
m2.
m3-1.
m3-2.
m3-3.
m3-4.
m4-1.
m4-2.

シンタックスエラーにはならず、予想通りに動くので、ドキュメント化されていない仕様だったりするのかな。

2016.03.30(水)

[]品質フィードバックをいただきました

いつも便利に使わせていただいています。

私の環境では、IP Messenger相手にファイルを送信しても、

相手側で受信する事が出来ません。

("ファイル転送準備中..."のまま進まない)

相手OSIP Messengerのバージョンはさまざまです。

原因として考えられる事をお教えいただけると助かります。

以上、よろしくお願いいたします。

PetacloneのIP Messengerコンポーネントの実装はほとんど変わっていないので、通信先のIP Messengerもいろいろとなると、ファイアウォールルータなどを確認してみると良いかもしれません。

ファイアウォールに関しては、petaclone.exeに許可を与えるか、UDPTCPの2425番ポートの受信を許可してください。

ウイルス対策ソフトを導入していると、Windowsファイアウォールの代わりにウイルス対策ソフトのファイアウォール機能が使われている場合があります。