tag:blogger.com,1999:blog-1527264912601427002024-03-13T23:50:06.352+09:00GDD BlogGDDとは「Gut's Driven Development」の略です。簡単にいうとガッツ駆動方式のシステム開発です。
<br>えぇまぁ、私の開発スタイルです。このBlogでは、そんなシステム開発の作業で発見したことを記録していきます。
(Google Developer Daysとはなんの関係ありません。)GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.comBlogger429125tag:blogger.com,1999:blog-152726491260142700.post-65540348384570136592022-03-08T19:54:00.003+09:002022-03-08T19:57:35.688+09:00[Android]Android Studio(2021.1.1 Patch2)でFirebase Cloud Firestoreを使う その2さすがに、カンで終わらすのは。と思い、前回の続き。<br>
android studioで<br>
ツール(T)→Firebase<br>
と押すと、下の画像のようなViewが出てくる。<br>
ここで②のところ(すでにやっちゃってますが)を押すと、build.gradleに必要な設定が入ってくれる!<br>
何てことだろう。。。みんなコレやってるんだよね。きっと。
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiCjcbdbsOBEjsoEAp5bWpqZVip-yY01NTrpvMw_ezZi1Da4MFXw4YoYMD9IR2hW33B5h-961XsCvqEk7UMscBJmWft3HLRFC5tvsGs64b1f3PEWeQxbjoPeTeao4AgTthC2UVUBHcuYWCm6038PZdvIExDk-YzuHmiVJOu3grsvgG-PgkVlgCobxru=s1328" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="763" data-original-width="1328" src="https://blogger.googleusercontent.com/img/a/AVvXsEiCjcbdbsOBEjsoEAp5bWpqZVip-yY01NTrpvMw_ezZi1Da4MFXw4YoYMD9IR2hW33B5h-961XsCvqEk7UMscBJmWft3HLRFC5tvsGs64b1f3PEWeQxbjoPeTeao4AgTthC2UVUBHcuYWCm6038PZdvIExDk-YzuHmiVJOu3grsvgG-PgkVlgCobxru=s320"/></a></div>
カンでやったのとは、一味違いますね。参考にするならこっちでお願いします。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-80297137746175092032022-03-08T19:16:00.001+09:002022-03-08T19:56:21.395+09:00[Android]Android Studio(2021.1.1 Patch2)でFirebase Cloud Firestoreを使うちょっと古めのAndroidStudioを使っていて、ま、Firestoreを使うならアレね。というのは覚えた。血反吐を吐きながら。<br>
時は流れ、AndroidStudioのバージョン新しめにして、同じことをやってみる。っという感じでbuild.gradleを編集。<br>
ということで、build.gradle(プロジェクト)を開いてみる
<pre><code>plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
</code></pre>
・・・ずいぶんシンプルになったなぁ。と思いつつ、いつも通りのアレを追加してみる。
<pre><code>plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
}
// 追加
buildscript {
repositories {
// Check that you have the following line (if not, add it):
google() // Google's Maven repository
}
dependencies {
...
// Add this line
classpath 'com.google.gms:google-services:4.3.10'
}
}
// 追加
task clean(type: Delete) {
delete rootProject.buildDir
}
</code></pre>
で、syncnowを押してみる。いつも通りいけるかなぁ。。。と甘くはない。公式サイトの「Firebase SDK の追加」の手順なんだけどね。<br>
ということで、直感を信じて適当に直してみる。
<pre><code>plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
// 追加
id 'com.google.gms.google-services' version '4.3.10' apply false
}
task clean(type: Delete) {
delete rootProject.buildDir
}
</code></pre>
こんなんでいいはずないしー。と思いつつsyncnowを押してみると、正常終了。<br>
で、build.gradle(モジュール)のほう。こちらもいつも通り、依存を追加してみる。
<pre><code>dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
//追加した記憶がない...
implementation 'com.google.firebase:firebase-firestore:23.0.2'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//追加
implementation platform('com.google.firebase:firebase-bom:29.1.0')
}
</code></pre>
こんな適当でうまくいくなら苦労はないわー。と思いつつサンプルを実装。<br><br><br>
お、コンパイルった。じゃあ、ランタイムエラーかな?と思ったらコイツ動くぞ。<br>
ということで、理屈はわかりませんが、firestoreでbuild.gradleに困ったら参考にしてください。
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-42391287989690439742021-08-13T17:43:00.003+09:002021-08-13T17:43:34.091+09:00[JavaScript]Mapを使う(連想配列)JavaScriptは、ちょっとくらい変な実装をしてもそれっぽく動くことがあります。<br>
コンパイルする形式の言語である、C#やJavaに慣れていると、むずがゆくなることがあります。<br>
<br>
ということで、間違えから偶然見つけて、調べてみると普通に連想配列だった話。<br>
JavaScriptでMapを使うには、以下のようにする。そう、何も考える必要はないのです。なぜならば、objectに連想配列の機能が混ぜ込まれているからです。<br>
コードはこんな感じ。
<pre><code>let map ={};
map["aaa"] = "aaa";
console.log(map["aaa"]);
//"aaa"と表示される
//ちなみに↓のようにもアクセスができる
console.log(map.aaa); // aaaと出力される
//メンバ変数のように代入もできる
map.bbb = "bbb"
console.log(map.bbb); // bbbと出力される
</code></pre>
JSONをオブジェクト化するとこもこんな感じでやってるんだろうね。<br>
・・・mapというか、属性を動的に増やす。という考え方。
ちなみに、objectなら何でもOK。こんなこともできる。
<pre><code>let list =[1,2,3];
list.bbb = "bbb";
console.log(list.bbb);// bbbと出力される
console.log(list);(3) [1, 2, 3, bbb: "bbb"]と出力される
</code></pre>
JavaScript。。。何でもありですね。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-2619913336223415242021-08-13T17:26:00.003+09:002021-08-13T17:43:56.261+09:00[JavaScript]変数宣言の仕方(var let const)JavaScriptの変数宣言。書き方いろいろある。制限(コーディング規約等)がないならlet使えというのが結論。<div>理由は、letを使っておけば、動作時に変数宣言の上書きに気が付けるから。です。</div><div>あと、定数はconstを使うのが結論。値を書き換えることができないからね。 </div><div><br /></div><div> 以下、それぞれ組合せでの検証結果。</div><div><br /></div>
■varとletの組合せ
<table border="1">
<tr>
<th></th>
<th>var</th>
<th>let</th>
</tr>
<tr>
<th>var</th>
<td>var a="a";<br>var a="b";<br>aの値は"b"になる!</td>
<td>var a="a";<br>let a="b";<br>実行時エラー</td>
</tr>
<tr>
<th>let</th>
<td>let a="a";<br>var a="b";<br>実行時エラー</td>
<td>let a="a";<br>let a="b";<br>実行時エラー</td>
</tr>
</table>
<br>
constもletと同じ特性。consutは、値の更新もできない。↓のような場合エラーになる。
<pre><code>const b = "b";
b="B"; //エラー
let c ="c";
c = "C";// こっちはOK。というか普通の使い方。
</code></pre>
<br>
ちなみに、varの上書きパターンこういうのが正常終了しちゃう。意味の分からない障害が出そう。
<pre><code>var aaa = "aaa";
var aaa = 100;
</code></pre>
ということでletがおすすめ。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-35688723120971427472021-08-13T12:12:00.007+09:002021-08-13T17:08:25.747+09:00[JavaScript]Listを使う(動的に要素を増やすことのできる配列)C#やJavaはクラスライブラリで様々な機能が提供されているけど、JavaScriptで同じようなことをしようとすると、外部のライブラリをインクルードする感じで使うのが一般的かな。と思います。<br>
と、前置きが長くなりましたが、Listを使いたかったのです。<br>
C#でいうと、↓のような感じ。<br>
<pre><code>var list = new List<string>();
</code></pre>
で調べてみたら、JavaScriptでは、[](Arrayというクラス)を使う。使い方は以下の通り。<br>
JavaScriptの型については、闇が深そうなので、今日は割愛。
<pre><code>let list = [1,2,3];
//初期値不要なら
//let list = [];
//要素の追加
list.push(4);
console.log(list);
//(4) [1, 2, 3, 4] と表示される
</code></pre>
つまるところ、変数に[]を代入すると、そいつは、Listになる。ってことですね。そしてなんでも入れれてしまいます。
<pre><code>let list = [1,2,3];
//要素の追加
list.push("あ");
console.log(list);
//(4) [1, 2, 3, "あ"] と表示される
list.push({name:"hoge"});
console.log(list);
//(5) [1, 2, 3, "あ", {…}] と表示される
</code></pre>
genericsがなかったころのjavaを思い出します。。。
ちなみに、pushがあるならpopもあるだろと。そうあるんです。さっきの続き。
<pre><code>list.pop()
//戻り値→{name: "hoge"}
console.log(list);
// (4) [1, 2, 3, "あ"] 最後に突っ込んだ要素がなくなっている。
list.pop()
//戻り値→"あ"
console.log(list);
// (3) [1, 2, 3] その前の要素がなくなっている
</code></pre>
スタックがあるならキューもあるだろーと。そうあるんです。さらに続き。
<pre><code>list.shift()
//戻り値→1
console.log(list);
// (2) [2, 3] 先頭の要素がなくなっている
</code></pre>
JavaScriptなんでもありっすね。
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-64675748467646040672021-08-13T11:40:00.001+09:002021-08-13T11:40:34.675+09:00[JavaScript]confirmやalertをオーバーライドするsliniumun等を使って、Webサイトの自動操作をすることがあります。んーあんまりないか。<div>自動操作しない場合でも、デバッグの時は、alertを出し、本番環境では、ログ出力。みたいなことをしたいことがあります。んーあんまりないか。console.log使うもんね。</div><div>ということで、強制的にalertやconfirmを何とかする方法ないかな。と思って調べてみると、alertやconfirmを上書き(オーバライド?)する方法がありました。</div><div>実装は↓のような感じ。以下は、chromeのconsoleで実行しているけど、htmlに入れれば、そのまま実現できる</div>
<pre><code>window.confirm = (text) => { console.log(text); return true; }
</code></pre>
常に「はい」ボタンを押した状態と同じになっちゃいますが、自動運転中に入力不要になりいい感じ。<div><br /></div><div>ちなみに、alertも同じように、window.alert = function(text){}でOK。</div>
<br /><div>で、chromeのconsoleで確認してみると、↓みたいになっている。</div>
<pre><code>//chromeのconsoleで↓を入力
> window.confirm</code></pre>
<pre><code>//こんなのが表示された。edgeでは表示されなかった。。。
ƒ (text) {
recordedConfirmation = text
if (document.body.hasAttribute('setConfirm')) {
document.body.removeAttribute('setConfirm')
return nextConfirmationResult
} else {
l…
</code></pre>
よくわからないけど、prompt.jsというソースにたどり着き、中身が見れる。
プラグインがいろいろ入っているからかもしれないけどね。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-27574469839322199022021-01-09T22:35:00.021+09:002021-01-10T02:07:15.466+09:00[Other]コードのシンタックスハイライトコードをハイライトするために、SyntaxHighlighterを使っていたんですがリンク切れで遅くなていました。<br />
で、とりあえずスタイルやJSのリンクを消したものの、コードのサンプル表示がかっこ悪かったので、これを機に修正しました。<br />
で、使ったのが、「highlight.js」です。<br />SyntaxHighlighterとくらべ軽量で言語の対応も多いらしいです。
ということで使い方。<br />↓のコードを<head>に埋め込めばOK<br />
<pre><code><link rel="stylesheet"
href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</code></pre>
サポートしている言語は、<a href="https://github.com/highlightjs/highlight.js/blob/master/SUPPORTED_LANGUAGES.md">GitHub</a>のほうを参照で。<br/>
使い方は<a href="https://highlightjs.org/usage/">https://highlightjs.org/usage/</a>を参照。<br/>
<br />
<br />当サイトは、VisualSutudio風のデザインを使っていますが、このデザイン枠がなんです。<div>ということで、スタイルの一部を改変。現状はこのスタイル(.hljs)が必ずセットされるので、それをチョット改変。</div><pre><code><style type='text/css'>
.hljs {
display:block;
border:1px solid #ffa500;
}
</style>
</code></pre>
<br />
<a href="https://highlightjs.org/static/demo/">デモサイト</a>があり、こっちも便利。分かりやすい。参考になる。<br />
<br />
<br />
取り合えず、チョットやな感じで何とかしたいこと。
<div>
<ul style="text-align: left;">
<li>1行目の空行<pre><code>の後ろに改行入れると、改行されちゃう</li>
<li><と>。コードをそのまま貼り付けれない。1行に1個までなら何とかなるっぽいけど、理由がわからない。js内に変換してそうなコードはあるんだけど。。。うまく動いていないのだろうか</li>
</ul>
</div>
・・・こいつら何とかしたい。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-69985239944558195262021-01-06T17:48:00.025+09:002021-01-10T02:16:48.319+09:00[Android]非推奨になったAsyncTaskの代わりに、ExecutorServiceとLiveDataを使うAndroid11(APIレベル30)がリリースされてからしばらくたちます。
<div>その中でも困りそうなのが、AsyncTaskが非推奨になったことです。</div>
<div>
AsyncTaskを使うと、AndroidStudioに取り消し線がつくのが気に入らないので、今のうちにイイ感じの実装方法を覚えていおたほうがいいかな。と思います。
</div>
<br />
<div>AsyncTaskを機能分割すると、流れ的に大きく3つ。</div>
<div>
<ol style="text-align: left;">
<li>doInBackground(Params... params) バックグラウンド処理</li>
<li>onProgressUpdate(Progress... values) 進捗状況をUIで表現</li>
<li>
onPostExecute(Result
result) 1.の結果を処理する(成功したらDBに登録とか)<br />
</li>
</ol>
<div>このうち、1,3は必須。2は場合によってって感じかな。と思います。</div>
</div>
<div><br /></div>
<div>で、よさげな実装案は、次の通り。</div>
<div>
<ol>
<li>java.util.concurrent.ExecutorServiceでバックグラウンド処理</li>
<li>JetPackのLiveDataで進捗状況をUIで表現</li>
<li>JetPackのLiveDataで1.の結果を処理する</li>
</ol>
</div>
<div>
<div>
1,3はイイ感じかなと思います。2はちょっとダサいけどできなくはない。じゃあ実際にどうするか。というと、
</div>
<div>
<ol style="text-align: left;">
<li>JetPack LiveDataの利用準備</li>
<li>LiveData用モデルの作成</li>
<li>LiveDataの更新コールバックを受け取るリスナーの設定</li>
<li>ExecutorServiceを使った非同期処理の実行</li>
</ol>
<div>という感じかな。と思います。じゃあ、実装例。</div>
</div>
<div><br /></div>
</div>
1.JetPack LiveDataの利用準備
<div>app/build.gradleに以下追記。ADDってなっている部分。</div>
<pre><code>dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.navigation:navigation-fragment:2.2.2'
implementation 'androidx.navigation:navigation-ui:2.2.2'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//<<ADD
def lifecycle_version = "2.2.0"
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
annotationProcessor "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
//>>ADD
}
</code></pre>
2.LiveData用モデルの作成(クラスの用意)
<div>
↓のような感じのクラスを作る。
<pre><code>public class MyViewModel extends ViewModel {
private MutableLiveData<String> currentName = new MutableLiveData<String>();
public MutableLiveData<String> getCurrentValue() {
return currentName;
}
}
</code></pre>
3.LiveDataの更新コールバックを受け取るリスナーの設定<br />
4.ExecutorServiceを使った非同期処理の実行
<pre><code>public class FirstFragment extends Fragment {
//2.LiveData用モデルの作成(変数定義)
private MyViewModel model;
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//2.LiveData用モデルの作成(インスタンス生成)
model = new ViewModelProvider(this).get(MyViewModel.class);
//3.LiveDataの更新コールバックを受け取るリスナーの設定
final Observer<String> nameObserver = new Observer<String>() {
@Override
public void onChanged(@Nullable final String newValue) {
// 画面の更新
TextView textView = view.findViewById(R.id.textview);
textView.setText(newValue);
}
};
model.getCurrentValue().observe(this, nameObserver);
view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//4.ExecutorServiceを使った非同期処理の実行
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(new Runnable() {
@Override
public void run() {
//10秒経過後、ワーカースレッドより、モデルの値を更新
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
String anotherName = "3秒経過 " + new Date();
//他のスレッドから情報更新する場合、postValueで値をセットする必要がある
model.getCurrentValue().postValue(anotherName);
}
});
}
});
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_first, container, false);
}
}
</code></pre>
<div><br /></div>
LiveDataを使うことでObserverパターンを実現しています。
<div>また、postValueを使うことで、スレッドを意識する必要がなくなります。</div>
<div>
Handlerを使えば、同じことはできますが、スレッドの入れ替えを隠蔽することで、コードがわかりやすくなりますね(個人的な感覚)。
</div>
<div>
また、値の取り回しが複数になる場合、面倒なので、更新通知用のフィールドを設けるのもありかなと思います。
</div>
<div>
<br />
<div>
「2.JetPackのLiveDataを使う」は、ちょっとダサいですけど、MyViewModelに進捗状況を表す数字を持たせ、postValueすればできるかな。と思います。
<div>・・・でもダサいですね。</div>
</div>
</div>
</div>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-20595441401567998102021-01-03T00:33:00.017+09:002021-01-09T21:26:49.537+09:00[PHP]Windows × xampp × Visual Studio CodeでPHPをデバッグ(Step実行)するどのプログラム言語でも、デバッグするには変数など内部データを見る必要があります。<br/>
変数を簡単に見るには、ステップ実行するのが一番の近道かなと思います。<br/>
<br/>
今回、PHPの開発に携わる機会があり、xampp環境でステップ実行するための環境を作ったんですが、うまくいかない。。。。<br/>
何がうまくいかないか。というと「ブレークポイントを設定しても止まらない」です。<br/>
<br/>
<br/>
環境は、以下の通りです。<br/>
・PHP Version 8.0.0<br/>
・Xdebug 3.0.1<br/>
・Visual Studio Code 1.52.1<br/>
・PHP Debug 1.14.5(Visual Studio Code のデバッグ用プラグイン)<br/>
<br/>
環境により違いはあると思いますが、この環境においての原因は以下の2点でした。<br/>
・Xdebug v3.0.0系より、php.iniに書く設定が変わった<br/>
・デバッグ用のポート番号が変わった<br/>
<br/>
対策は以下の2つ。<br/>
1.PHP.iniの設定<br/>
2.lunch.jsonの設定<br/>
<br/>
<br/>
1.PHP.iniの設定<br/>
<code><pre>
[XDebug]
xdebug.mode=debug
xdebug.start_with_request=yes
zend_extension = C:\xampp\php\ext\php_xdebug-3.0.1-8.0-vs16-x86_64.dll
</code></pre>
うまくいっている場合、↓のURLで確認ができる。<br>
http://localhost/dashboard/phpinfo.php<br>
xdebugの「Step Debugger」が「enabled」になっていたらOK。<br/>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKZxVD0xJTkgbRQfFdpzrKVMNg0XWsS9WHcdcLaZXuYEnvD8IHdff9ldaDJdFQx1BhseMDf7lfaglUosA7dx-y5Ivjv09ccGAMbo7ysbceSgHbNcZP_moGJCfpj6bY7IhXLKZUBqKfr5Y/s1171/%25E7%2584%25A1%25E9%25A1%258C.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="458" data-original-width="1171" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjKZxVD0xJTkgbRQfFdpzrKVMNg0XWsS9WHcdcLaZXuYEnvD8IHdff9ldaDJdFQx1BhseMDf7lfaglUosA7dx-y5Ivjv09ccGAMbo7ysbceSgHbNcZP_moGJCfpj6bY7IhXLKZUBqKfr5Y/s320/%25E7%2584%25A1%25E9%25A1%258C.png"/></a></div>
<br>
zend_extensionはバージョンによって異なる。コイツの導き出し方は、他のサイトを探してみてください。<br/>
<br>
<br>
2.lunch.jsonの設定<br/>
ポート番号が変わったらしい。その設定を合わせる。
9001→9003
<pre><code>
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
'version': '0.2.0',
'configurations': [
{
'name': 'Listen for XDebug',
'type': 'php',
'request': 'launch',
<b>'port': 9003,</b>
'runtimeExecutable': 'C:\\xampp\\php\\php.exe'
},
{
'name': 'Launch currently open script',
'type': 'php',
'request': 'launch',
'stopOnEntry': true,
'program': '${file}',
'cwd': '${fileDirname}',
<b>'port': 9003,</b>
'runtimeExecutable': 'C:\\xampp\\php\\php.exe'
}
]
}
</code></pre>
設定の変更は、Visual Studio Codeのメニュー「実行(R)」→「構成を開く」で編集できます。
<br>
<br>
Lunch Currently open Scriptを選択し、F5でデバッグスタート。<br>
ブレークポイントを設定しておくと、そこで止まるようになりました。<br>
<div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhln6OrQWCs1Hm6J0yt0OFN2YtkxBLfM51e23YvMw1DsFfQwLMGKAAb_44sRnSEeg078J8QLeKJhnqTzcISdAXI7c4QvfOC_mcBkpxW0FDBNdxa3AS-SgNCSXYL7UW2DviqgU_gW-OrGGo/s659/%25E7%2584%25A1%25E9%25A1%258C.png" style="display: block; padding: 1em 0; text-align: center; "><img alt="" border="0" width="320" data-original-height="246" data-original-width="659" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhln6OrQWCs1Hm6J0yt0OFN2YtkxBLfM51e23YvMw1DsFfQwLMGKAAb_44sRnSEeg078J8QLeKJhnqTzcISdAXI7c4QvfOC_mcBkpxW0FDBNdxa3AS-SgNCSXYL7UW2DviqgU_gW-OrGGo/s320/%25E7%2584%25A1%25E9%25A1%258C.png"/></a></div>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-70268110599839724622020-07-13T01:51:00.004+09:002021-01-03T00:08:47.677+09:00[他]更新が滞って約5年仕事が忙しく、しばらく更新できていませんでした。いろんな事情があり、仕事のスタイルを変えることにしました。<br />
今は、システム開発がメインではなくなりましたが、日々いろんな発見があることに変わりはありません。<br />
ということで、また、システム開発の作業で発見したことを記録していきます。<br />
<br />
しばらく放置していたせいか、コードハイライトのためのスクリプトを提供しててもらっていたサイトがなくなったり、ページカウンタがなくなったりしていたせいで、表示がすごーく遅くなっていました。<br />
そのあたりの不具合を修正しました。
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-25522372870718309362015-04-02T00:10:00.001+09:002015-04-02T00:10:09.115+09:00[他]広告費を寄付しましたこのブログの収益金が振り込まれました(今回も微々たるものですが。。。)Unisefに募金しました。
最近、まったくこのブログもほとんど更新できていません。時間を作る努力が必要そうですね。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-80703700149279242922014-10-01T23:57:00.002+09:002021-01-07T13:21:44.586+09:00[他]複数のWebサーバからログをコピーする負荷分散などでWebサーバが複数台あるシステムがあります。で、トラブル発生→ログ収集だ。となった時、いちいちファイルログファイルをコピーするのは非常に面倒です。ということで、Windowsマシンなら大体動作するVBScriptで、複数のサーバからログをコピーするスクリプトを作ってみました。
ログのコピーと言っても、大量になっちゃうので、当日を含む過去4日に更新されたタイムスタンプのもの。という縛りをつけてみました。
<pre><code>
'-------------------------------------------------
' c:\temp\>cscript logcopy.vbs
'-------------------------------------------------
Option Explicit
'-------------------------------------------------
'ログ保存場所
Const COPY_DIR = ".\logs\"
'過去何日分か(過去3日分)
Dim TARGET_DATE: TARGET_DATE = DateAdd("d", -3, Date)
'-------------------------------------------------
'対象
'-------------------------------------------------
Dim WEB_SERVERS: WEB_SERVERS = Array( _
"192.168.1.1", _
"192.168.1.2", _
"192.168.1.3", _
"192.168.1.4", _
"192.168.1.5", _
"192.168.1.6")
Dim LOG_PATH: LOG_PATH = "\d$\mysystem\WebLog"
'-------------------------------------------------
'処理
'-------------------------------------------------
Call InitDir(COPY_DIR)
Dim server
' V5サーバのログコピー
For Each server In WEB_SERVERS
Call CopyFiles(server, COPY_DIR & server, LOG_PATH)
Next
'-----------------
'ファイルコピー
'指定ディレクトリのファイルをコピーする
'-----------------
Sub CopyFiles(server, dest, targetPath)
Dim path: path = "\\" & server & targetPath
WScript.Echo "CopyFiles path= " & path
Call InitDir(dest)
Dim objFso:Set objFso = CreateObject("Scripting.FileSystemObject")
Dim objShell: Set objShell = CreateObject("Shell.Application")
Dim objFolder : Set objFolder = objShell.Namespace(path)
Dim objFolderItems: Set objFolderItems = objFolder.Items()
Dim objItem
Dim idx
For idx = 0 To objFolderItems.Count - 1
Set objItem = objFolderItems.Item(idx)
If objItem.IsFolder = True Then
Call CopyFiles(server, objFso.BuildPath(dest, objItem.Name), objFso.BuildPath(targetPath, objItem.Name))
Else
If IsCopyFile(objItem) = True Then
Call objFso.CopyFile(objItem.path, objFso.BuildPath(dest, objItem.Name))
End If
End If
Next
End Sub
'-----------------
'ファイルコピー判定
'過去N日分のファイルをコピーする
'-----------------
Function IsCopyFile(fileObj)
If fileObj.ModifyDate >= TARGET_DATE Then
IsCopyFile = True
Else
IsCopyFile = False
End If
End Function
'-----------------
'ディレクトリがなければ作成
'-----------------
Sub InitDir(target)
Dim objFso:Set objFso = CreateObject("Scripting.FileSystemObject")
If objFso.FolderExists(target) = False Then
objFso.Createfolder (target)
End If
End Sub
</code></pre>GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-70335630509491361532014-06-22T23:47:00.002+09:002014-06-22T23:52:17.324+09:00[他]広告費を寄付しました以前作ったAndroidアプリの広告費がPaypalへ振り込まれました。<br />
<div>
ドル払いっていうのも一つの理由ですが、セルビアの話を聞いてそのまま振り込みました。</div>
<div>
<br /></div>
<div>
今回の広告費も微々たるものですが、また収益が上がったら寄付する予定です。<br />
最近忙しくて更新が滞っています。また落ち着いた日々の疑問や発見を記録したいものです。<br />
<br /></div>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-30243429190664448332014-05-24T02:47:00.005+09:002021-01-07T13:24:48.206+09:00[他]WebAPIを疎通する今どきのWebAPIは、Rest形式でかつGETで動作するため、ブラウザで簡単に疎通確認できます。<br />
しかし、SOAPなどPOST形式のI/Fもあります。これを、疎通するためにアプリケーションが必要になる場合があります。 また、テスト用のHTMLを置けないケースもあるでしょう。<br />
Windows環境において、インタフェースまでの通信経路に問題がないかを確認するためには、
VBスクリプトを使うのが気軽でよいです。でコードはこんな感じ。<br />
<pre><code class="vb">Dim objXML
Dim intRet
Dim strURL
Dim strKey
strURL = "http://jlp.yahooapis.jp"
strKey = "sentence=%e7%a9%ba%e5%89%8d%e7%b5%b6%e5%be%8c"
MsgBox ("url=" & strURL)
MsgBox (strKey)
Set objXML = CreateObject("MSXML2.ServerXMLHTTP")
objXML.Open "POST", strURL, False
objXML.setRequestHeader "Content-Type", " application/x-www-form-urlencoded"
objXML.setRequestHeader "Content-Length", "length"
objXML.send strKey
intRet = objXML.Status
MsgBox ("stat=" & intRet)
MsgBox (objXML.responseText)
</code></pre>
まぁ今どきはPS(パワーシェル)を使うんでしょうけど。。。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-82523264959784620672014-04-20T19:01:00.000+09:002014-04-20T20:46:10.135+09:00[他]windows8.1にADBドライバをインストールするWindows8.1にadbドライバをインストールしようとすると、<br />
<br />
「指定されたカタログファイルにファイルのハッシュがありません。ファイルが壊れているか、改ざんされた可能性があります。」<br />
<br />
って出てきてドライバを設定することができません。<br />
<br />
で、これを回避するためには、「ドライバー署名の強制を無効化」なる手続きをする必要があります。この手順がたいへんかったるいというか、google先生に聞いてもバージョンによって微妙に手順が異なり、簡単にはたどり着けません。<br />
<br />
でも、世の中には面倒なことを2度としたくない人たちがいます。その面倒な処理をワンクリックで行ける用にしてくれるつーるがこちら。<br />
<br />
<a href="http://forum.xda-developers.com/showthread.php?t=2588979">15 seconds ADB Installer </a><br />
<br />
私のマシンでは15秒かかりませんでした。。。<br />
唯一気になるのが、どこに何がインストールされたかよくわからない点。<br />
<br />
とはいえ、XDAの人たち。すごいですねぇ。<br />
<br />
<br />GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-85061660853409501042014-01-24T00:37:00.001+09:002014-01-24T00:42:21.838+09:00[他]広告費を寄付しましたこのページにある、広告(Google AdSense)の広告費が今日振り込まれました。<br />
<div>
収益が支払可能になるまで約一年かかりました。</div>
<div>
もらった広告費は、そのままユニセフに寄付しました。</div>
<div>
<br /></div>
<div>
広告費と言っても微々たるものですが、また収益が上がったら寄付する予定です。</div>
<div>
ということで、安心して広告をクリックして下さい。</div>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-58756830216687142752013-08-23T22:41:00.001+09:002013-09-05T00:58:13.770+09:00[Java]google gsonのはまりポイントJSONをアノテーションでPOJOにバインディングするgsonは、JSONObjectでパースする原始的な処理?より、はるかに楽ができます。 最初使ったときは感動しましたね。こういうライブライがつかえないプロジェクトでは、同様の処理を実現するためにリフレクションであれして。。。なんていう残念な結末が目に浮かびます。<br />
<br />
しかし、そのgsonにも、これはないんじゃない?的な結果になることがいくつかあります。<br />
そのいくつかはこんな感じ。<br />
<ol>
<li><T> T Gson#fromJson(String json, Type typeOfT) で第一引数にnull渡すと結果がnull</li>
<li><T> T Gson#fromJson(String json, Type typeOfT) で第一引数にから文字渡すと結果がnull</li>
<li><T> T Gson#fromJson(Reader json, Class<T> classOfT) で第一引数がのReaderが即EOFになると結果がnull</li>
</ol>
<div>
そうなんです。解析できない系のインプットが入ると、結果がnullになっちゃうんです。</div>
<div>
1は、妥当だと思いますが、2,3は例外はくかデフォルトで生成したオブジェクト返せよ!って感じがします。</div>
<div>
ということで結果のnullチェックが必要になるという残念な感じになっています。</div>
<div>
これ気に入らないなら、<a href="https://sites.google.com/site/gson/gson-user-guide#TOC-Null-Object-Support">Null Object Support</a>を使えよって話ですね。しかしこれではインプットがnullだからそうなっているのか、空文字系("")だからそうなるのかわかりません。</div>
<div>
個人的な考えでは、前者はバグで後者はデータ不正ですね。</div>
<div>
<br /></div>
<br />
ここまでは気を付けるよの話なんですが、問題は<br />
<br />
<ul>
<li>JSON構文エラーの際に発生する構文エラーがRuntime系の例外</li>
</ul>
<div>
<br /></div>
<div>
です。そうなんです。コンパイラーでのチェックができないという残念な結果になります。</div>
<div>
・・・外部からインプットするJSONの構文チェックは当然すべきであり、これがランタイムになるというのはちょっと理解できないです。</div>
<div>
みなさん、こういうのってどうしてるんでしょうか。</div>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-52795716675803088982013-07-25T00:25:00.002+09:002021-01-07T13:45:47.062+09:00[Java]数値のラッパー型をintに変換する引数で何らかの数値ラッパー型がObjectで引き渡される。それをintとして利用したい的なことありませんか?
ありませんね。<br />
でも、汎用的な変換ライブラリなどではそんなことあるかもしれませんね。
instanceofを全部の数値ラッパー型に適応して。。。涙が出そうになります。ということで調べてみるとNumberというインタフェースがあり、これが使えることがわかりました。
IntegerやDoubleのリファレンスを見るとわかるとおり、ラッパー型のクラスはみんな<a href="http://docs.oracle.com/javase/jp/7/api/java/lang/Number.html">Number</a>を継承しているんです。
コードはこんな感じ。
<pre><code>
public static void main(String[] args) {
Object d = Double.valueOf(3.5d);
System.out.println("3.5d=" + toInt(d));
Object f = Float.valueOf(2.5f);
System.out.println("2.5f=" + toInt(f));
Object l = Long.valueOf(20l);
System.out.println("20l=" + toInt(l));
Object b = Byte.valueOf((byte) 20);
System.out.println("20b=" + toInt(b));
Object s = Short.valueOf((short) 20);
System.out.println("20s=" + toInt(s));
Object bd = new BigDecimal(4.5);
System.out.println("4.5bd=" + toInt(bd));
Object al = new AtomicLong(21);
System.out.println("21al=" + toInt(al));
}
/**
* int変換.
*
* 数値ラッパーをintに変換する。
*
* @param obj
* @return 変換した数値
*/
public static int toInt(Object obj) {
if (!(obj instanceof Number)) {
throw new IllegalArgumentException("not number!!");
}
return ((Number) obj).intValue();
}
</code></pre>
実行結果はこんな感じ。
<pre><code>
3.5d=3
2.5f=2
20l=20
20b=20
20s=20
4.5bd=4
21al=21
</code></pre>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-73984901470126009652013-07-23T01:13:00.012+09:002021-01-09T22:15:22.686+09:00[Java]JSONをPOJOにバインドするとき、オリジナルの変換を行うJSONからPOJO(Bean)に変換する処理はめんどくさいです。たとえば、
<ul>
<li>JSONは文字列で、Java側はEnum</li>
</ul>
このケースでは、文字列=Enumの定義名という式が成り立てば、自動で変換されます。下のstep1がそれに該当します。しかし文字列がenumと一致しない場合、正しく変換されません。おそらく初期値になってしまうでしょう。以下の例ではnullになってしまっています(enumはnullを許容するんです)。
<br />
次に、
<br />
<ul>
<li>JSON上は数値なんだけど、Java上はEnum</li>
</ul>
この場合、自動的な変換では明らかに無理です。こういう場合、JsonDeserializer<T>を使います。
以下の例では、数値をenumにしています。こちらも存在しない値の場合、nullを返却しています。
実装した例はこんな感じ。
<pre><code>
public class GsonEnum {
public static void main(String[] args) {
Gson gson = new Gson();
// タイプを取り出す(List)
Type type = new TypeToken<List<Signal>>() {
}.getType();
// JSON->List<Signal>
List<Signal> signal = gson.fromJson(new InputStreamReader(
GsonMap.class.getResourceAsStream("signal2.json")), type);
System.out.println("---step1---");
System.out.println(signal);
// JSON->List<Signal>
// #1 TypeAdapterを設定したGsonを生成する
Gson gson2 = new GsonBuilder().registerTypeAdapter(SignalStat.class,
new SignalStatDeserializer()).create();
List<Signal> signal2 = gson2.fromJson(new InputStreamReader(
GsonMap.class.getResourceAsStream("signal3.json")), type);
System.out.println("---step2---");
System.out.println(signal2);
}
/**
* 解析結果を受け取るクラス
*/
static class Signal {
private SignalStat stat;
private String message;
private SignalStat next;
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
sb.append("stat=").append(stat);
sb.append(" message=").append(message);
sb.append(" next=").append(next);
sb.append("]");
return new String(sb);
}
}
/**
* ステータスの表現.
*/
enum SignalStat {
Red, Yellow, Blue;
// #2 変換用のMAP(int -> SignalStat)
static Map<Integer, SignalStat> CONVERTER = new HashMap<Integer, SignalStat>();
static {
for (SignalStat stat : SignalStat.values()) {
CONVERTER.put(stat.ordinal(), stat);
}
}
}
/**
* SignalStat用Deserializer.
*/
static private class SignalStatDeserializer implements
JsonDeserializer<SignalStat> {
@Override
public SignalStat deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context) throws JsonParseException {
// #3 int -> SignalStat
return SignalStat.CONVERTER.get(json.getAsInt());
}
}
}</code></pre>
ポイントは以下の通り
<ul>
<li>#1:TypeAdapterを設定したGsonを生成するためにGsonBuilderをnewしregisterTypeAdapterでDeserializerを指定する</li>
<li>#2:enumの中に、変換用Mapを用意しておく。staticでOKです</li>
<li>#3:JsonDeserializerを実装する。#2の変換用Mapを使ってint->enumを実現している</li>
</ul>
入力データはこんな感じ(signal2.json)
<pre><code>
[
{
"stat": "Red",
"message": "とまれ",
"next": "Blue"
},
{
"stat": "Yellow",
"message": "とまっとけ",
"next": "Red"
},
{
"stat": "Invalid",
"message": "すすんでもいいよ",
"next": "Yellow"
}
]
</code></pre>
入力ry (signal3.json)
<pre><code>
[
{
"stat": 0,
"message": "とまれ",
"next": 2
},
{
"stat": 1,
"message": "とまっとけ",
"next": 0
},
{
"stat": 100,
"message": "すすんでもいいよ",
"next": 1
}
]
</code></pre>
出力結果はこんな感じ<br/>
step1ではInvalidは存在しないのでnullとなり、step2では100は存在しないのでnullになっています。
<pre><code>
---step1---
[[stat=Red message=とまれ next=Blue], [stat=Yellow message=とまっとけ next=Red], [stat=null message=すすんでもいいよ next=Yellow]]
---step2---
[[stat=Red message=とまれ next=Blue], [stat=Yellow message=とまっとけ next=Red], [stat=null message=すすんでもいいよ next=Yellow]]
</code></pre>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-25547720321722179202013-07-22T23:37:00.000+09:002013-07-22T23:37:53.299+09:00[Android]透明なアクティビティテーマ設定で透明なアクティビティが作れます。えぇまぁ AndroidManifest.xmlに書くだけです。<br />
<br />
<div class="cscode">
<<span class="keyword">activity</span> <span class="src_attributename">android:name</span>=<span class="literal">"com.hoge.TransparentActivity"</span><br />
<span class="src_attributename"> android:theme</span>=<span class="literal">"@android:style/Theme.Translucent"</span><br />
<span class="src_attributename"> android:label</span>=<span class="literal">"Transparent"</span>/></div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-32979161673038151612013-07-21T02:30:00.002+09:002021-01-07T13:54:57.066+09:00[Java]JSONをJsonObject/JsonArrayにバインドするJSONからPOJO(Bean)に変換するんだけど、一部分だけJsonObjectに落としたい。そんな時はありませんか?<br />
どんなデータが入ってくるのか決まっていない。けどキーは同じみたいな。結果的に汎用型で受け付けたい。そんなケースです。<br />
いろいろ調べたんだけど方法があわからず。でしたが、実は普通にJsonObjectやJsonArrayつかえば良い。ということがわかりました。
配列の場合だけ気を付けないとダメ。という残念なことになっています。<br />
コードはこんな感じ。<br />
<br />
<pre><code>
public class GsonObject {
public static void main(String[] args) {
Gson gson = new Gson();
// JSON->JsonObject(Map)
JsonObject his = gson.fromJson(new InputStreamReader(GsonList.class
.getResourceAsStream("history_map.json")), JsonObject.class);
System.out.println("---step1 Map---");
System.out.println(his);
// JSON->JsonArray(List)JsonArrayじゃないとキャストに失敗する。。。
JsonArray his2 = gson.fromJson(new InputStreamReader(GsonList.class
.getResourceAsStream("history_list.json")), JsonArray.class);
System.out.println("---step2 List---");
System.out.println(his2);
// JSON->JsonObject(POJO)
JsonObject his3 = gson.fromJson(new InputStreamReader(GsonList.class
.getResourceAsStream("history.json")), JsonObject.class);
System.out.println("---step3 Object---");
System.out.println(his3);
}
/**
* 解析結果を受け取るクラス
*/
static class History {
private int key;
private String message;
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
sb.append("key=").append(key);
sb.append(" message=").append(message);
sb.append("]");
return new String(sb);
}
}
}</code></pre>
出力結果はこんな感じ。
<pre><code>
---step1 Map---
{"kentousi":{"key":894,"message":"遣唐使"},"kamakura1":{"key":1192,"message":"鎌倉幕府"},"kamakura2":{"key":1185,"message":"鎌倉幕府"}}
---step2 List---
[{"key":894,"message":"遣唐使"},{"key":1192,"message":"鎌倉幕府"},{"key":1185,"message":"鎌倉幕府"}]
---step3 Object---
{"key":894,"message":"遣唐使"}
</code></pre>
インプットしたデータは省略。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-63173456765569872922013-07-21T02:13:00.002+09:002021-01-07T13:57:32.298+09:00[Java]JSONをPOJOにバインドする(List,[])JSONからPOJO(Bean)に変換する処理はめんどくさいです。
Google社製のGSONでは、データ形式にListや配列としてバインドすることができます。
で、コードはこんな感じ。
<pre><code>
class GsonList {
public static void main(String[] args) {
Gson gson = new Gson();
// List<History>.classと書けないので、TypeTokenを使ってTypeを取り出す
Type type = new TypeToken<List<History>>() {}.getType();
// JSON->List<POJO>
List<History> his = gson.fromJson(new InputStreamReader(
GsonList.class.getResourceAsStream("history_list.json")), type);
System.out.println("---step1 List---");
System.out.println(his);
// JSON->POJO[]
History[] his2 = gson.fromJson(new InputStreamReader(
GsonList.class.getResourceAsStream("history_list.json")), History[].class);
System.out.println("---step2 []---");
System.out.println(Arrays.toString(his2));
}
/**
* 解析結果を受け取るクラス
*/
static class History {
private int key;
private String message;
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
sb.append("key=").append(key);
sb.append(" message=").append(message);
sb.append("]");
return new String(sb);
}
}
}
</code></pre>
出力結果は次の通り。
<pre><code>
---step1 List---
[[key=894 message=遣唐使], [key=1192 message=鎌倉幕府], [key=1185 message=鎌倉幕府]]
---step2 []---
[[key=894 message=遣唐使], [key=1192 message=鎌倉幕府], [key=1185 message=鎌倉幕府]]
</code></pre>
インプットしたJSONは次の通り。
<pre><code>
[
{
"key": 894,
"message": "遣唐使"
},
{
"key": 1192,
"message": "鎌倉幕府"
},
{
"key": 1185,
"message": "鎌倉幕府"
}
]
</code></pre>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-30418381913050026182013-07-21T02:05:00.004+09:002021-01-07T14:09:14.478+09:00[Java]JSONをPOJOにバインドする(Map)JSONからPOJO(Bean)に変換する処理はめんどくさいです。<br />
Google社製のGSONでは、データ形式にMapとしてバインドすることができます。
残念なことに、Map形式では順序を維持できないという課題があります。<br />
しかしこれはJSONの仕様であり、GSONとしてはその仕様に準じているだけ。といえますね。
<br />
<br />
コードはこんな感じ。
<br />
<pre><code>
public class GsonMap {
public static void main(String[] args) {
Gson gson = new Gson();
// Map<String, History>.classと書けないので、TypeTokenを使ってTypeを取り出す
Type type = new TypeToken<Map<String, History>>() {
}.getType();
// JSON->Map<String,POJO>
Map<String, History> his = gson.fromJson(new InputStreamReader(
GsonMap.class.getResourceAsStream("history_map.json")), type);
System.out.println(his);
}
/**
* 解析結果を受け取るクラス
*/
static class History {
private int key;
private String message;
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
sb.append("key=").append(key);
sb.append(" message=").append(message);
sb.append("]");
return new String(sb);
}
}
}
</code></pre>
実行結果はこんな感じ
<br />
<pre><code>
{
"kentousi"=["key"=894 "message"="遣唐使"],
"kamakura1"=["key"=1192 "message"="鎌倉幕府"],
"kamakura2"=["key"=1185 "message"="鎌倉幕府"]
}
</code></pre>
インプットに使ったJSONはこんな感じ
<br />
<pre><code>
{
"kentousi": {
"key": 894,
"message": "遣唐使"
},
"kamakura1": {
"key": 1192,
"message": "鎌倉幕府"
},
"kamakura2": {
"key": 1185,
"message": "鎌倉幕府"
}
}
</code></pre>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-88430946489561773142013-07-21T01:46:00.003+09:002021-01-07T14:18:58.943+09:00[Java]JSONをPOJOにバインドするJSONからPOJO(Bean)に変換する処理はめんどくさいです。リフレクションでルールを決めて変換。というのもめんどくさいですね。
そこで、JSONを解析するライブラリを利用します。
JSON系のライブラリはいくつかありますが、今回はGoogle社製のGSONを使ってみました。コードはこんな感じ。
よく紹介されているレベルのコードと変わりませんが、以下のようなポイントがあります。
<br />
<ul>
<li>private static final の変数に値を突っ込んでいる</li>
<li>内部クラス(staticですが)を利用する</li>
<li>変数名と異なる項目をバインドしている</li>
</ul>
この辺を気にする人には参考になると思います。
<br />
<pre><code>
public class GsonBasic {
public static void main(String[] args) {
Gson gson = new Gson();
//JSON->POJO(1)
History his = gson.fromJson(
new InputStreamReader(GsonBasic.class
.getResourceAsStream("history.json")), History.class);
System.out.println("---step1---");
System.out.println(his);
//JSON->POJO(1)
History2 his2 = gson.fromJson(
new InputStreamReader(GsonBasic.class
.getResourceAsStream("history.json")), History2.class);
System.out.println("---step2---");
System.out.println(his2);
}
// 内部クラスにする場合、staticにしないと面倒が起る
/**
* 解析結果を受け取るクラス(1)
*/
static class History {
// final にすることもできる
private final int key;
private final String message;
// コンストラクタで初期化することで、GSONでもセットできる
public History() {
key = 0;
message = null;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("key=").append(key);
sb.append(" message=").append(message);
return new String(sb);
}
}
/**
* 解析結果を受け取るクラス(2)
*/
static class History2 {
// JSONのキー名と変数名が異なる場合、@SerializedNameを使う
@SerializedName("key")
private int mKey = 0;
@SerializedName("message")
private String mMessage = "";
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("key=").append(mKey);
sb.append(" message=").append(mMessage);
return new String(sb);
}
}
}
</code></pre>
出力結果は次の通り。
<pre><code>
---step1---
key=894 message=遣唐使
---step2---
key=894 message=遣唐使
</code></pre>
インプットしたJSONは次の通り。<br />
<pre><code>
{
"key": 894,
"message": "遣唐使"
}
</code></pre>
GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0tag:blogger.com,1999:blog-152726491260142700.post-59758969742327043502013-07-06T17:15:00.001+09:002021-01-07T14:17:53.029+09:00[.NET]Dictionaryを素直?にJSONで出力する.NET系でJSONを出力する場合、DataContractJsonSerializerというクラスがあり、これを使えばそれっぽく出力されます。<br />
しかし、Dictionaryで持っている値を出力すると、なんかkeyとvalueの配列という残念な形式にシリアライズされてしまいます。<br />
他にいい方法ないかなぁと思って調査してみたところ、.NET4.0以降では、もう一種類JSONのシリアライザがあるのがわかり、<br />
試したところ、期待するような形式で出てきました。ということでコードはこんな感じ。<br />
<br />
<pre><code>
private void button1_Click(object sender, EventArgs e)
{
// using System.Web.Script.Serialization;
var json = new JsonData();
json.item_key = "歴史";
json.label_position["kentousi"] = new { key = 894, Message = "遣唐使" };
json.label_position["kamakura1"] = new { key = 1192, Message = "鎌倉幕府" };
json.label_position["kamakura2"] = new { key = 1185, Message = "鎌倉幕府" };
json.label_position["gomi"] = new { key = "string", Message = new string[]{"array1","array2"} };
var sel = new JavaScriptSerializer();
System.Diagnostics.Debug.WriteLine(sel.Serialize(json));
}
</code></pre>
<pre><code>
class JsonData
{
public string item_key;
public Dictionary<string, Object> label_position = new Dictionary<string, Object>();
}
</code></pre>
出力結果はこんな感じ。
<pre><code>
{
"item_key": "歴史",
"label_position": {
"kentousi": {
"key": 894,
"Message": "遣唐使"
},
"kamakura1": {
"key": 1192,
"Message": "鎌倉幕府"
},
"kamakura2": {
"key": 1185,
"Message": "鎌倉幕府"
},
"gomi": {
"key": "string",
"Message": [
"array1",
"array2"
]
}
}
}
</code></pre>
<br />
<br />
DataContractJsonSerializerでは、匿名型をサポートしていないのに対して、JavaScriptSerializerはイケる。という特徴もありました。ということで、組み合わせの異なる型をガラガラとシリアライズする必要のあるサーバ機能的な物を作る場合、というか4以降ならJavaScriptSerializerがおすすめ。GENZ0http://www.blogger.com/profile/09649386523239366694noreply@blogger.com0