2015/08/17

Node.js と MongoDB の開発環境構築メモ

最近流行りの Node.js と MongoDB の組み合わせで開発環境を作ったメモ。

DLとインストール

Node.js

Node.js の本体。

  • https://nodejs.org/download/
    • Installer を選択
    • Binary は Node.exe だけで npm が無い

インストールはインストーラに従えばOK。

Eclipse プラグイン

nodeclips という プラグインをインストールする。
express というフレームワークも一緒に入る。

  • http://dl.bintray.com/nodeclipse/nodeclipse/
    • とりあえず配下全部

プラグイン、インストール後に環境設定が必要。

注:node.exe以外はデフォルトの設定を使うこと。

MongoDB

MongoDB 本体はDLしてインストールするだけ。 起動方法法は後述。

  • https://www.mongodb.org/downloads
    • OS は 2008 R2+ にした

MongoDB の教本(通称:薄い本)のPDFをDLして一読しておく。

プロジェクトの作成

素の Node.js プロジェクトと Expless フレームワークのプロジェクトが作れるが今回は Express プロジェクトを作成する。
Express は Node.js を HTTP サーバとするためのフレームワーク。

  • メニューから 「新規 > プロジェクト > その他 > ノード > Node Express Project」 を選択。
  • テンプレートエンジンは好きなほうを選択
    • jade はHTML省略記法、ejs はJSPライクな感じ

作成されたプロジェクトの構成は以下

  • public/** : 静的なHTMLファイル
  • routes/** : JSのロジック
  • views/** : テンプレート
  • app.js : アプリのメイン
  • package.json : アプリの定義ファイル

app.js のメニューから 「実行 > Node Application」 でアプリが起動する。
ブラウザから http://localhost:3000 にアクセスして Welcom ページが表示されればOK。

Node.js と MongoDB の接続

MongoDB サーバの起動

mongod.exe を実行するだけでサーバは起動するが WindowsだとDBフォルダのドライブ指定を明示したほうが良いので起動バッチを作成する。 MongoDBのインストールフォルダに置いておく。

boot-mongod.bat: サーバ起動用

set BASEDIR=%~dp0
cd /d %BASEDIR%
%BASEDIR%\Server\3.1\bin\mongod.exe --dbpath %BASEDIR%\DB

clinet-mongo.bat: シェル起動用

set BASEDIR=%~dp0
cd /d %BASEDIR%
%BASEDIR%\Server\3.1\bin\mongo.exe

クライアントのシェルを起動して繋がればOK。

ドライバの準備

ドライバは Node.js のモジュール 'mongodb' を使用する。
'mongoose' とかも有るようだけどとりあえず標準を使う。

package.json の dependencies に "mongodb" を追加する。

{
  "name": "node-ex-test",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.2.6",
    "jade": "*",
    "mongodb": "*"     <--これ追加
  }
}

変更後にメニューから「実行 > npm install」を行うとmongodbのドライバがDLされる。
他のモジュールも同じように追加できる。

ドライバのAPIは以下を参照。

接続サンプルコード

MongoDBにコレクション accounts を作成しユーザ登録と認証を行う簡単なサンプル。
POSTのパラメータに user,pass が設定されるAPIとしている。

簡単な仕様:

メソッドURLリクエスト本文レスポンス
登録POST/accounts/registeruser={ユーザ名}&pass={パスワード}200 or 500
認証POST/accounts/loginuser={ユーザ名}&pass={パスワード}200 or 401

routes/accounts.js:

var MASTER_PASSWD = "ce39325bc505e74089f7e176a380370f";
var mongodb = require('mongodb');
var crypto = require('crypto');
var accounts;

mongodb.MongoClient.connect("mongodb://localhost:27017/test", function(err, database) {
    if (err != null) console.error(err);
    accounts = database.collection("accounts");
});

function pass2hash(pass, solt) {
    var hash = crypto.createHash('sha1');
    hash.update(MASTER_PASSWD).update(pass).update(solt);
    return hash.digest('base64');
}

exports.register = function register(req, res) {
    var solt = crypto.createHash('sha1').update(""+ new Date()).digest('base64');
    var hash = pass2hash( req.body.pass, solt);
    accounts.update({name: req.body.name},
        {name: req.body.name, hash: hash, solt:solt},
        {upsert: true},
        function(err, result) {
            if (err == null && result.result.n == 1) {
                console.log(item);
                res.send("OK");
            } else {
                console.error(err);
                res.statusCode = 500;
                res.send("NG");
            }
        }
    );
}

exports.login = function login(req, res) {
    accounts.findOne({name:{$eq: req.body.name}}, function(err,doc){
        if (err != null) console.error(err);
        var isLoginOk = false;
        if (doc != null) {
            var hash = pass2hash(req.body.pass, doc.solt);
            isLoginOk = (hash == doc.hash);
        }
        if (isLoginOk) {
            res.send("OK");
        } else {
            res.statusCode = 401;
            res.send("NG");
        }
    });
}

apps.js:

var express = require('express');
var http = require('http');
var path = require('path');

var app = express();

// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));

// development only
if ('development' == app.get('env')) {
    app.use(express.errorHandler());
}

// サンプルのマッピング設定
var accounts = require('./routes/accounts');
app.post("/accounts/register", accounts.register);
app.post("/accounts/login", accounts.login);

http.createServer(app).listen(app.get('port'), function() {
    console.log('Express server listening on port ' + app.get('port'));
});

実行結果

ユーザ登録を行ってMongoDBのシェルからDBにデータが登録された事を確認する。

> db.accounts.find();
{ "_id" : ObjectId("55cd9b6e8ca01a0a50ecd707"), "name" : "abc", "hash" : "+1j0H0OdNH/HFGXspXi+hx6mtS8=", "solt" : "RzB+u5FvnOvHRXvtZi85iX9URno=" }
{ "_id" : ObjectId("55d011f4ba68640523bd0271"), "name" : "xxx", "hash" : "wsB0iPj/2BtLHGXWmSFqeGjqwn4=", "solt" : "1o2QK3qqdWSgw1cFQgbIj4DnpBA=" }
{ "_id" : ObjectId("55d0126cba68640523bd0272"), "name" : "yyyy", "hash" : "lHj8Xu6HNrrpjn9w6i9FnWYUwdI=", "solt" : "BI8xyULlX/CAj19/3VonYxehG/o=" }
{ "_id" : ObjectId("55d012bbba68640523bd0273"), "name" : "zzz", "hash" : "xeJTRfFbVaKSI2m6QePMv9laB4E=", "solt" : "NG42owW9EC7Ntu8FAp6NWXLwbBs=" }

つでに name に Index を作成しておく。

> db.accounts.ensureIndex({name:1},{unique:true});
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 2,
        "ok" : 1
}
> db.accounts.getIndexes()
[
        {
                "v" : 1,
                "key" : { "_id" : 1 },
                "name" : "_id_",
                "ns" : "test.accounts"
        },
        {
                "v" : 1,
                "unique" : true,
                "key" : { "name" : 1 },
                "name" : "name_1",
                "ns" : "test.accounts"
        }
]

MongoDBはスキーマレスなのでこういう設定をするタイミングはよくわからない。
_id の役割を完全に理解してないが name の代わりに PKEY として使っても良いのかもしれない。

まとめ

Node.js と MongoDB どちらも JavaScript に慣れている人なら違和感なく入れると思う。
思いの他、学習コストは低いのではないだろうか。
Eclipse でデバッグ実行までできるので開発もしやすそう。

MongoDB の「トランザクションが無い」とか「正規化しない」などの特徴は慣れるまでは難しそうだ。


2015/08/05

Android Studio のカスタマイズ

ADT 終了のお知らせが Google から出たので仕方なく Android Studio を使ってみている。
いろいろ操作に戸惑うのでカスタマイズをメモ。

お勧めのエラー対処方の表示

Eclipseではマウスオーバーだが Studio では ALT+Enter。
マウスオーバーはキーバインドできないので中ボタンに割り当てる。

  1. Settings の Keymap へ移動
  2. 「Show Intention Actions」を検索
  3. 鉛筆のメニューから「Add Mouse shortcut」を選択して設定ダイアログ
  4. マウスアイコンの上で中ボタンをクリック

エディタ設定

行番号と空白の表示

デフォルトで行番号も空白も表示されないのは Eclipse と同じ。
改行の表示方法が不明。

  1. Settings の Editor > General > Apprearaaance へ移動
  2. 「Show line numers」と「Show white space」をチェック

フォントの変更

スキーマを作らないと変更できない?
Windows10 だと Source code pro が選択できたので設定しておいた。

  1. Settings の Editor > Colors&Fonts > Font へ移動
  2. 「Save As...」ボタンで新しいスキーマを作る。
  3. 「Show only monospaced fonts」をチェックしてフォントを選ぶ。
  4. 「Line Spaceng」はフォントにより 0.8~0.9 くらいが良い

コンテキストメニュー

エディタの右クリックメニューによく使う機能だけを割り当てた。
メニューの編集機能が恐ろしく使いずらい。

  1. Settings の Appearance & Behavior > Menus and Toolbars へ移動
  2. 「Editor Popup Menu」を開いて内容を右側のボタンで編集

作ったメニュー

Declaration
Call hierarchy
Super Method
Implements
---
Generate
Toggle Case
Rename
---
Cut
Copy
Peast

削除した項目の「Column Selection mode」は Toolar の Paste の後ろに追加する。

参考、機能一覧:http://gihyo.jp/dev/serial/01/android_studio/0022

ツールバーのアイコン

ツールバーをカスタマイズすると 16x16 のアイコンが必要になる。 指定しないと意味不明なデフォルトアイコンが設定されてしまう。

おすすめのフリーのアイコンセット。16x16 で500種類以上ある。

フラットではないので若干違和感あるけど編集アプリ向けのアイコンが充実している。。

コード・フォーマッタ

Eclipse Code Formatter プラグインを入れて Eclipse の設定を流用する。
移行プロジェクトだと差分出ちゃうから必須。

  1. settings の Plugins へ移動。
  2. 「Browse repositories」ボタンをクリック
  3. 「Eclipse Code Formatter」を検索してインストール
  4. settings の Other Settings > Eclipse Code Formatter へ移動
  5. 「Use the Eclipse code fomtter」をチェック
  6. 「Eclipse Java formatter config file」にエクスポートした定義ファイルを設定する。

GitHub

  1. git.exe をインストールしてパスを設定する。
  2. gitbub のユーザとパスワードを設定する。
  3. メニューから「Create git repository」「Share project on github」の順に実行する。

その他

使ってると色々出てくるから都度追加。

雑感

途中で気が付いたのでが Studio って Android 以外のプロジェクトって作れないのね。
GAE のサポートはあるみたいだけど Tomcat は結局 Eclipse が必要。
IntelliJ も無料版はサーバ開発できないみたいだし。

Eclipse+Gradle ではダメだったんだろうか?


2015/04/10

Android-x86-4.4r2 の設定メモ

Android-x86とVirtualBoxを使った開発用の環境の設定方法メモです。
以前 4.0 で作ったのですが 4.4 になったらだいぶ変わっていたので備忘録として残します。

画面のバランスこんな感じです。 (モニタは 1920x1200/22inch、端末は6inchくらいに見えます。)

標準のエミュレータと同じように使えますがこちらは実機並にサクサク動きます。

VirtualBox

ダウンロード

インストール

  • 普通に .exe 叩くだけ。
  • Extension Pack は VirtualBox にリモートデスクトップ接続するときに必要。
    • 「ファイル」->「環境設定」->「拡張機能」 からインストールする。

Android-x86

ダウンロード

インストール

  • VirtualBox で仮想マシンを作る。
    • OSは Other Linux(32bit)
    • HDDは最低2G
    • メモリは512M~1G
    • ネットワークはブリッジ
    • リモートディスプレイを有効
  • android-x86-4.4-r2.iso をCDにマウントして起動。
    • インストーラでインストール。

ネットワーク設定

固定IPを Android-x86 に設定する。

  • Android-x86 をデバックモードで起動
  • /system/etc/init.sh の最後に以下を追加。
    • 最後といっても return 0 の行の前。
ifconfig eth0 {ip-addr} netmask {netmask}
route add default gw {gateway-ip-addr} dev eth0
setprop net.eth0.dns1 {dns-ip-addr}
  • プロキシが必要な場合の設定
sqlite3 /data/data/com.android.providers.settings/databases/settings.db
INSERT INTO system VALUES(99, 'http_proxy', ':');

縦画面モード設定

開発時に適当なサイズとなる 270x480 ピクセルを設定。

  • VirtualBox に画面モード追加
C:> VBoxManage.exe setextradata {VM name} CustomVideoMode1 270x480x16
  • Android をデバックモードで起動
    • /mnt/grub/menu.lst を編集して kernel のオプションに以下を追加
video=-16 UVESA_MODE=240x480
  • DPIを120に設定
C:> adb connect {ip-addr}
C:> adb shell wm density 120

Eclipse との接続

  • VM 起動後に以下のコマンドを実行
C:> adb disconnect {ip-addr}
C:> adb connect {ip-addr}
  • DDMS が自動的に認識してくれる。

その他

  • Android-x86 は VirtualBox のマウス統合が使えないので結構不便。
  • リモートデスクトップ接続すると解消される。
    • 但し、描画は遅くなる。

2014/11/23

Androidの画像選択で嵌ったのでメモ

Android 5.0(lolipop)がリリースされたのでインストールしてみた。
体感速度で倍ぐらいになってビビったよ。
で、自作の付箋アプリの動作を確認していたら画像選択で落ちやがったのでその対応メモ。

とりあえず、ログを見るとこれで落ちてた。

android.content.ActivityNotFoundException: No Activity found to handle Intent 
{ act=android.intent.action.PICK typ=image/* }

Intent.ACTION_PICK image/* はシステムの画像選択を呼び出すはずだけど無くなったのか?
ググったら KitKat からは Intent.ACTION_OPEN_DOCUMENT に変わったらしい。
でも KitKat 以前は Intent.ACTION_PICK のままである必要がある。うへ

とりあえず、これでどっちでも画像選択が起動するようになったよ。

@TargetApi(Build.VERSION_CODES.KITKAT)
public static void startChoosePicture(Activity context, int code) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
        intent.addCategory(Intent.CATEGORY_OPENABLE);
        intent.setType("image/*");
        context.startActivityForResult(intent, code);
    } else {
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setAction(Intent.ACTION_GET_CONTENT);
        intent.setType("image/*");
        context.startActivityForResult(intent, code);
    }
}

これでOKかと思ったら甘かったね。
OSを再起動すると選択した画像が表示されない。 ログを見たらこんなエラーが出てた。

java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider 
from ProcessRecord{2787cc3a 22044:org.kotemaru.android.postit/u0a109} (pid=22044, uid=10109) 
requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

単純に MANAGE_DOCUMENTS をパーミッションに加えても解決しない。
ググったら見つかったよ。

takePersistableUriPermission()で永続的パーミッションを得ないと再起動したら見えなくなるのか。
そんなの見落とすよ、API考えろよGoogle。

画像URI取得にこれをはさんだらうまく行った。

@TargetApi(Build.VERSION_CODES.KITKAT)
public static Uri getResultChoosePictureUri(Context context, int requestCode, int resultCode, Intent returnedIntent) {
    if (resultCode != Activity.RESULT_OK) return null;
    Uri uri = returnedIntent.getData();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final int takeFlags = returnedIntent.getFlags() & Intent.FLAG_GRANT_READ_URI_PERMISSION;
        context.getContentResolver().takePersistableUriPermission(uri, takeFlags);
    }
    return uri;
}

Androidはバージョン間差異が細かすぎるよ。


2014/11/09

Android SDKでjavadoc生成

Android の開発環境で eclipse から javadoc を生成しようとすると例外が出たり文字化けしたりでうまく行かない。

単純に eclipse のメニューから実行するとこうなる。

java.lang.ClassCastException: com.sun.tools.javadoc.ClassDocImpl cannot be cast to com.sun.javadoc.AnnotationTypeDoc

android.jar を bootclasspath に入れたりする必要が有り結局、 専用の build.xml 作って ant で動かすのが一番面倒が無さそう。

忘れると思うのでメモっとく。

build-javadoc.xml:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project default="javadoc">
    <property file="local.properties" />
    <property file="project.properties" />

    <target name="javadoc">
        <javadoc access="private" 
            additionalparam="-encoding UTF-8 -charset UTF-8 "
            bootclasspath="${sdk.dir}/platforms/${target}/android.jar" 
            classpath="libs/android-support-v4.jar"
            destdir="doc" 
            source="1.6" 
            sourcepath="src" >
            <packageset dir="src" defaultexcludes="yes">
                <include name="{パッケージパス}/**" />
            </packageset>
            <link href="file:/${sdk.dir}/docs/reference" />
        </javadoc>
    </target>
</project>

local.properties:

sdk.dir={android-sdksのパス}

project.properties:

target=android-{APIレベル}

2014/04/02

Android NDK の環境構築

Android の NDK を試そうと開発環境を作ろうとしたら参考サイトのどれも古くて現状と合わないので とりあえず自分でメモ。 現状はEclipseのプラグインが全部やってくれるようです。 と言ってもこれもすぐ古くなっちゃうんだろうな。

前提条件

  • 2014年4月時点です。
  • Eclipse 4.2 の pleiades です。
  • Android-SDK は設定済みです。
  • OSは Windows7/64 です。

NDK のインストール

以下のサイトから環境に合う NDK をダウンロードして任意の場所に展開します。

この時点のバージョンは r9d でした。

Eclipse のプラグインのインストール

C/C++ の開発環境

「ヘルプ」->「新規ソフトウェアのインストール」から以下の3つをインストールする。

  • URL: http://download.eclipse.org/releases/juno/
    • ▽ プログラミング言語
      • ■ C/C++ 開発ツール
      • ■ C/C++ 開発ツール SDK
      • ■ ライブラリ API ドキュメンテーション~

NDK プラグイン

「ヘルプ」->「新規ソフトウェアのインストール」から以下の1つをインストールする。

  • URL: https://dl-ssl.google.com/android/eclipse/
    • ▽ NDK プラグイン
      • ■ Android ネイティブ開発ツール

Eclipse 再起動後、「ウィンドウ」->「設定」から「Android」->「NDK」を選んで NDK Location に展開した NDK のフォルダを設定する。

サンプルプロジェクト

新規プロジェクトで「既存コードからのAndroidプロジェクト」を選びます。

展開した NDK のフォルダの samples フォルダからプロジェクトを選択します。

プロジェクトのメニューから「Androidツール」->「Add Native Support」を選択します。

jni フォルダが認識されます。

JNI は「自動的にビルド」は効かないので手動でプロジェクトのメニューから「プロジェクトをビルド」を選択します。

正常にコンパイルされると各CPUアーキテクチャ用の .so ファイルが生成されます。

この状態で apk を作成すると .so を含んだ形で生成されます。

感想

Eclipseのプラグインが全部やってくれるのでかなり簡単です。

古い NDK の環境設定の解説にはコマンド操作が書いて有ったりしてかえって混乱するので注意してください。


2013/05/06

antでファイル一覧を生成する。

JavaScriptで1クラス=1ファイルでコードを書いていると .js ファイルが沢山できる。

これを一々、<script> タグにして HTML に埋め込むのが以外に面倒くさい。

で、ant の fileset で何とかならないかと思って調べてみたらこうなった。

<taskdef resource="net/sf/antcontrib/antcontrib.properties">
  <classpath>
    <pathelement location="${project.root}/lib/ant-contrib-1.0b3.jar"/>
  </classpath>
</taskdef>

<target name="main">
    <antcall target="makeListFile">
        <param name="includes" value="**/*.js"/>
        <param name="file" value="html.txt"/>
        <param name="prefix" value="&lt;script src='"/>
        <param name="suffix" value="'/>"/>
    </antcall>
</target>

<target name="makeListFile">
    <fileset id="fileset" dir=".">
        <include name="${includes}" />
    </fileset>

    <pathconvert property="files" refid="fileset" pathsep=";" dirsep="/" >
        <map from="${basedir}/" to="" />
    </pathconvert>

    <echo file="${file}"></echo>
    <foreach target="addLine" param="name" inheritall="true"
        list="${files}" delimiter=";"
    >
   </foreach>
</target>
<target name="addLine">
        <echo append="true" file="${file}">${prefix}${name}${suffix}
</echo>
</target>

面倒くせー。 そもそも contrib ずっとベータだし。

次に script タグを試して見ようと思って見付けたのがこちらのサンプル。

scriptタスクのマニュアル より

<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="MyProject" basedir="." default="main">

  <property name="fs.dir" value="src"/>
  <property name="fs.includes" value="**/*.txt"/>
  <property name="fs.excludes" value="**/*.tmp"/>

  <target name="main">
    <script language="javascript"> <![CDATA[

      // import statements
      // importPackage(java.io);
      importClass(java.io.File);

      // Access to Ant-Properties by their names
      dir      = project.getProperty("fs.dir");
      includes = MyProject.getProperty("fs.includes");
      excludes = self.getProject()  .getProperty("fs.excludes");

      // Create a <fileset dir="" includes=""/>
      fs = project.createDataType("fileset");
      fs.setDir( new File(dir) );
      fs.setIncludes(includes);
      fs.setExcludes(excludes);

      // Get the files (array) of that fileset
      ds = fs.getDirectoryScanner(project);
      srcFiles = ds.getIncludedFiles();

      // iterate over that array
      for (i=0; i<srcFiles.length; i++) {

        // get the values via Java API
        var basedir  = fs.getDir(project);
        var filename = srcFiles[i];
        var file = new File(basedir, filename);
        var size = file.length();

        // create and use a Task via Ant API
        echo = MyProject.createTask("echo");
        echo.setMessage(filename + ": " + size + " byte");
        echo.perform();
      }
    ]]></script>
  </target>
</project>

もっと面倒くせー orz

結局、自前でスクリプトを呼ぶTask書くのが早いんじゃね、と思って作ったのがこれ。

package jstask;

import java.io.File;
import java.util.*;
import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;
import org.apache.tools.ant.types.resources.FileResource;
import org.mozilla.javascript.*;

public class JsTask extends Task  {
    private List<ResourceCollection> rclist = new ArrayList<ResourceCollection>();
    private List<Parameter> params = new ArrayList<Parameter>();
    private String text;

    public void add(ResourceCollection rc) {
        rclist.add(rc);
    }
    public void addParam(Parameter param) {
        params.add(param);
    }
    public void addText(String str) {
        text = str;
    }

    @Override
    public void execute() throws BuildException {
        Context cx = Context.enter();
        try {
            Scriptable scope = cx.initStandardObjects();
            scope.put("task", scope, this);
            scope.put("fileset", scope, toFileList(rclist));
            for (Parameter param : params) {
                scope.put(param.getName(), scope, param.getValue());
            }
            cx.evaluateString(scope, text, "ant.js", 0, null);
        } finally {
            Context.exit();
        }
    }   

    private List<File> toFileList(List<ResourceCollection> rclist) {
        List<File> filelist = new ArrayList<File>(); 
        for (ResourceCollection rc : rclist) {
            for (Iterator<?> ite = rc.iterator(); ite.hasNext();) {
                Resource resource = (Resource) ite.next();
                if (resource instanceof FileResource) {
                    File file = ((FileResource) resource).getFile();
                    filelist.add(file);
                }
            }
        }
        return filelist;
    }
}

使用例:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="test" name="test">
    <taskdef name="js"
        classname="jstask.JsTask"
        classpath="lib/jstask.js;lib/js.jar"
    />
    <target name="test">
        <js>
            <fileset dir="src" includes="**/*.js" />
            <param name="prefix" value="^${basedir}/" />
            <param name="outfile" value="html.txt" />

            <![CDATA[
            var out = new java.io.FileWriter(outfile);
            var ite = fileset.iterator();
            while (ite.hasNext()) {
                var reg = new RegExp(prefix);
                var fname = (""+ite.next()).replace(reg,"");
                out.write("<script src='"+fname+"'></script>\n");
            }
            out.close();
            ]]>
        </js>
    </target>   
</project>

結局これが一番簡単だった...


2013/04/21

Javaで動的に配列を生成するメモ

Javaで任意の型の配列を動的に作る方法を知らない事に気が付いた。

大概は Object[ ] で対処できるので今まで調べたことが無かったっぽい。

結論から言うとこうする。

int[] ary = (int[])java.lang.reflect.Array.newInstance(int.class, 10);

言語仕様上は静的にしか配列の型は決められないので reflect で生成するようになっている。

まぁ、普通使わないよなこんなの...


プロフィール
20年勤めた会社がリーマンショックで消滅、紆余曲折を経て現在はフリーランスのSE。 失業をきっかけにこのブログを始める。

サイト内検索

登録
RSS/2.0

カテゴリ

最近の投稿【メモ】

リンク

アーカイブ