manholeのおきらくごくらく日記
SPAM対策中です。コメントが反映されない方はリンク先をご覧ください。
[
Maven2
| Maven
| Axis2
| testing
]
オススメ:
xUnit Test Patterns
| JUnit Recipes
| パターン指向リファクタリング入門
| Ant第2版
2012-01-25 (水)
[長年日記]
■ java.beans.XMLEncoderでTimestampを扱う
XMLEncoder#setPersistenceDelegateへjava.sql.Timestamp.classのPersistenceDelegateをセットする。
(セットしないと例外になります)
final XMLEncoder encoder = open(); encoder.setPersistenceDelegate(Timestamp.class, TimestampPersistenceDelegate.getInstance()); encoder.writeObject(obj); close(encoder);
PersistenceDelegate実装はこんなふう。
private static class TimestampPersistenceDelegate extends PersistenceDelegate {
private static PersistenceDelegate INSTANCE = new TimestampPersistenceDelegate();
public static PersistenceDelegate getInstance() {
return INSTANCE;
}
@Override
protected Expression instantiate(final Object oldInstance, final Encoder out) {
final String s = oldInstance.toString();
// Timestamp.valueOf(String s) を示す
return new Expression(oldInstance, oldInstance.getClass(), "valueOf", new Object[] { s });
}
}
出力されるxmlはこのようになります。
<?xml version="1.0" encoding="UTF-8"?> <java version="1.5.0_09" class="java.beans.XMLDecoder"> <object class="java.sql.Timestamp" method="valueOf"> <string>2012-01-24 11:22:33.456789</string> </object> </java>
この対策をしない場合の動作
<その1>
そもそも encoder.setPersistenceDelegate(Timestamp.class, xxxx); をしない場合は、java.lang.InstantiationExceptionになります。
Timestampがデフォルトコンストラクタを持たないためでしょう。
java.lang.InstantiationException: java.sql.Timestamp
at java.lang.Class.newInstance0(Class.java:335)
at java.lang.Class.newInstance(Class.java:303)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:239)
at java.beans.Statement.invoke(Statement.java:215)
at java.beans.Expression.getValue(Expression.java:98)
at java.beans.Encoder.getValue(Encoder.java:85)
at java.beans.Encoder.get(Encoder.java:180)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:94)
at java.beans.Encoder.writeObject(Encoder.java:54)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:254)
at java.beans.Encoder.writeExpression(Encoder.java:259)
at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:369)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:97)
at java.beans.Encoder.writeObject(Encoder.java:54)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:254)
at java.beans.Encoder.writeObject1(Encoder.java:186)
at java.beans.Encoder.cloneStatement(Encoder.java:199)
at java.beans.Encoder.writeStatement(Encoder.java:230)
at java.beans.XMLEncoder.writeStatement(XMLEncoder.java:328)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:257)
...
<その2>
java.util.Dateに設定されているPersistenceDelegateを使用する場合。
final PersistenceDelegate pd = encoder.getPersistenceDelegate(Date.class); encoder.setPersistenceDelegate(Timestamp.class, pd);
Timestampがnano部分を持つ場合に無限ループしてStackOverflowErrorになります。
ミリ秒部分までなら問題なく動作します。
java.lang.StackOverflowError
at jp.co.hitachi_kenki.XmlObjectCodec$1.exceptionThrown(XmlObjectCodec.java:25)
at java.beans.Encoder.getValue(Encoder.java:88)
at java.beans.Encoder.get(Encoder.java:180)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:94)
at java.beans.Encoder.writeObject(Encoder.java:54)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:254)
at java.beans.Encoder.writeExpression(Encoder.java:259)
at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:369)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:97)
at java.beans.Encoder.writeObject(Encoder.java:54)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:254)
at java.beans.Encoder.writeObject1(Encoder.java:186)
at java.beans.Encoder.cloneStatement(Encoder.java:199)
at java.beans.Encoder.writeExpression(Encoder.java:258)
at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:369)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:97)
at java.beans.Encoder.writeObject(Encoder.java:54)
at java.beans.XMLEncoder.writeObject(XMLEncoder.java:254)
at java.beans.Encoder.writeExpression(Encoder.java:259)
at java.beans.XMLEncoder.writeExpression(XMLEncoder.java:369)
at java.beans.PersistenceDelegate.writeObject(PersistenceDelegate.java:97)
...
2011-12-15 (木)
[長年日記]
■ [git] svn間のマージにgit svnを利用する
svnを2つ用意。
(svnレポジトリ) $ mkdir -p "/home/manhole/svnrepo/" $ svnadmin create "/home/manhole/svnrepo/repo1" $ svnadmin create "/home/manhole/svnrepo/repo2" (svn work) $ mkdir -p "/home/manhole/svnwork/work1" $ mkdir -p "/home/manhole/svnwork/work2" (workへそれぞれチェックアウトして、) $ svn checkout "file:///home/manhole/svnrepo/repo1" "/home/manhole/svnwork/work1" Checked out revision 0. $ svn checkout "file:///home/manhole/svnrepo/repo2" "/home/manhole/svnwork/work2" Checked out revision 0. (それぞれのworkへ初期コミット。※コミットがないとgit svnで取得できない) $ cd /home/manhole/svnwork/work1 $ touch readme.txt $ svn add readme.txt A readme.txt $ svn commit -m "initial work1" Adding readme.txt Transmitting file data . Committed revision 1. cd /home/manhole/svnwork/work2 touch readme.txt $ svn add readme.txt A readme.txt $ svn commit -m "initial work2" Adding readme.txt Transmitting file data . Committed revision 1.
両方を同期するための作業用gitを用意
$ mkdir -p /home/manhole/gitwork
$ cd /home/manhole/gitwork
(-Rと--prefixがキモ)
$ git svn init -R svn1 --prefix svn1/ "file:///home/manhole/svnrepo/repo1"
Initialized empty Git repository in /home/manhole/gitwork/.git/
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[svn-remote "svn1"]
url = file:///home/manhole/svnrepo/repo1
fetch = :refs/remotes/svn1/git-svn
(1つ目とは異なる-Rと--prefixを指定する)
$ git svn init -R svn2 --prefix svn2/ "file:///home/manhole/svnrepo/repo2"
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
[svn-remote "svn1"]
url = file:///home/manhole/svnrepo/repo1
fetch = :refs/remotes/svn1/git-svn
[svn-remote "svn2"]
url = file:///home/manhole/svnrepo/repo2
fetch = :refs/remotes/svn2/git-svn
それぞれのsvnからfetchする。
$ cd /home/manhole/gitwork
$ git svn fetch svn1
A readme.txt
r1 = 4b125ddaa2608230293af3296e7bce21f22e5b02 (refs/remotes/svn1/git-svn)
Checked out HEAD:
file:///home/manhole/svnrepo/repo1 r1
$ git svn fetch svn2
A readme.txt
r1 = ff7d3a46dddfedf20abf8bb4b8b1f543d37f4e67 (refs/remotes/svn2/git-svn)
$ git branch -a
* master
remotes/svn1/git-svn
remotes/svn2/git-svn
fetchしたsvnを、手元のbranchにそれぞれ持つ。
$ git checkout -b svn1 svn1/git-svn Switched to a new branch 'svn1' $ git checkout -b svn2 svn2/git-svn Switched to a new branch 'svn2' $ git branch -a master svn1 * svn2 remotes/svn1/git-svn remotes/svn2/git-svn
これで、2つのsvnレポジトリと、それぞれを手元で作業するためのworkができた。
svn1レポジトリ側へ色々変更が入ったとして...
cd /home/manhole/svnwork/work1 echo "aaa" > file1.txt $ svn add file1.txt A file1.txt $ svn commit -m "file1.txtを追加" Adding file1.txt Transmitting file data . Committed revision 2. $ echo "bbb" > file2.txt $ svn add file2.txt A file2.txt $ svn commit -m "file2.txtを追加" Adding file2.txt Transmitting file data . Committed revision 3.
svn1側の変更をsvn2へ反映するため、gitへ取得する。
$ cd /home/manhole/gitwork
$ git checkout svn1
Switched to branch 'svn1'
$ git svn rebase
A file1.txt
r2 = 7c5288c257c8565495dfc3b78cc6aec97886e154 (refs/remotes/svn1/git-svn)
A file2.txt
r3 = 79b5fb01fb74585a507d941c6b270a2d8a8d4dad (refs/remotes/svn1/git-svn)
First, rewinding head to replay your work on top of it...
Fast-forwarded svn1 to refs/remotes/svn1/git-svn.
svn1側の変更をsvn2ブランチへmergeする。
※コミットを1つにまとめたくない場合は、svn mergeではなくコミットを1つずつ適用する手段にすること。
$ git checkout svn2 Switched to branch 'svn2' $ git merge svn1 Merge made by recursive. file1.txt | 1 + file2.txt | 1 + 2 files changed, 2 insertions(+), 0 deletions(-) create mode 100644 file1.txt create mode 100644 file2.txt
svn2側をsvnレポジトリへcommitする。
(svn2ブランチにいる状態で)
$ git svn dcommit
Committing to file:///home/manhole/svnrepo/repo2 ...
A file1.txt
A file2.txt
Committed r2
A file2.txt
A file1.txt
r2 = d5ac5e543e1f0fac9a809c62b13c69f6c45c8d1b (refs/remotes/svn2/git-svn)
No changes between current HEAD and refs/remotes/svn2/git-svn
Resetting to the latest refs/remotes/svn2/git-svn
この時点でのgitの状態は...
(alias.graph=log --graph --date-order -C -M --pretty=format:"<%h> %ad [%an] %Cgreen%d%Creset %s" --all --date=short) $ git graph * <d5ac5e5> 2011-12-16 [manhole] (HEAD, svn2/git-svn, svn2) Merge branch 'svn1' into svn2 |\ | * <79b5fb0> 2011-12-16 [manhole] (svn1/git-svn, svn1) file2.txtを追加 | * <7c5288c> 2011-12-16 [manhole] file1.txtを追加 * | <ff7d3a4> 2011-12-16 [manhole] initial work2 / * <4b125dd> 2011-12-16 [manhole] (master) initial work1 $ git diff svn1 svn2 $ (差分なし)
これをsvn2レポジトリへ反映する。
$ cd /home/manhole/svnwork/work2 $ $ svn update Updating '.': A file2.txt A file1.txt Updated to revision 2. $ svn log ------------------------------------------------------------------------ r2 | manhole | 2011-12-16 14:58:34 +0900 (Fri, 16 Dec 2011) | 1 line Merge branch 'svn1' into svn2 ------------------------------------------------------------------------ r1 | manhole | 2011-12-16 14:42:43 +0900 (Fri, 16 Dec 2011) | 1 line initial work2 ------------------------------------------------------------------------
2011-12-07 (水)
[長年日記]
■ [Java]サロゲートペアを含むStringでのsubstring
メモ。
public static String substring(final String str, final int beginIndex, final int endIndex) {
final int actualBegin = str.offsetByCodePoints(0, beginIndex);
final int actualEnd = str.offsetByCodePoints(0, endIndex);
final String s = str.substring(actualBegin, actualEnd);
return s;
}
参照:
2011-10-06 (木)
[長年日記]
■ [groovy] ".svn"ディレクトリだけが存在するディレクトリを削除する
import java.io.File;
// closure
deleteClosure = { dir ->
//println dir
if (dir.name == ".svn") {
return;
}
dir.eachDir(deleteClosure)
def files = dir.listFiles();
if (files.length == 1 && files[0].directory && files[0].name == ".svn") {
println "削除します : ${dir}"
dir.deleteDir();
} else {
println "削除しません: ${dir}"
}
}
if (args.length != 1) {
println "対象ディレクトリを指定してください"
return
}
println Arrays.asList(args)
deleteClosure(new File(args[0]))
バージョン1.7.5で確認。
D:\project\groovy-script\src\main\groovy\file>groovy -v Groovy Version: 1.7.5 JVM: 1.6.0_20

