Help us understand the problem. What is going on with this article?

あなたとジャバ、今すぐダウンロード

More than 5 years have passed since last update.

 やっはろー。これは、D言語 Advent Calendar 2012の24日目の記事です。D言語から Java のライブラリを使ってみた、という話をします。

 ごく一部の人から Java に似ていると評判の D言語ですが、実際その評判に違わず Java のクラスを扱うことができます。こんな感じに。

void main() {
    auto arguments = JavaVMInitArgs();
    arguments.version_ = 0x00010006; // JNI_VERSION_1_6
    arguments.nOptions = 0;
    arguments.ignoreUnrecognized = true;

    JavaVM* javavm = null;
    JNIEnv* jnienv = null;
    JNI_CreateJavaVM(&javavm, cast(void**)&jnienv, &arguments);
    scope (exit) javavm.DestroyJavaVM();

    auto Integer = jnienv.FindClass("java/lang/Integer");
    auto ctor = jnienv.GetMethodID(Integer, "<init>", "(I)V");
    auto intValue = jnienv.GetMethodID(Integer, "intValue", "()I");

    auto integer = jnienv.NewObject(Integer, ctor, 42);
    auto n = jnienv.CallIntMethod(integer, intValue);

    writeln(n);
}

 Java には Java Native Interface (JNI) というのがあって、Java のコードとネイティブのコードを互いに呼び出すことができるようになっています。つまり、そういうことです。

 Java のライブラリも使えそうだということで、日本語形態素解析ライブラリである Kuromoji でワードカウントをしてみました。次の記事を参考にしています。

Clojure/kuromoji でテキストマイニング入門 ~形態素解析からワードカウントまで~ - あんちべ!

// dmd 2.063.2

import core.stdc.stdarg;
import std.array, std.algorithm, std.ascii, std.conv, std.file, std.format, std.range, std.stdio, std.string;

extern (C) {
    alias jboolean = bool;
    alias jint = int;

    struct _jobject;
    alias jobject = _jobject*;

    struct _jclass;
    alias jclass = _jclass*;

    struct _jmethodID;
    alias jmethodID = _jmethodID*;

    alias jstring = jobject;

    struct JNIInvokeInterface {
        void*[3] dummy0;
        jint function(JavaVM* vm) DestroyJavaVM;
    }

    struct JavaVM {
        const JNIInvokeInterface* functions;

        jint DestroyJavaVM() {
            return functions.DestroyJavaVM(&this);
        }
    }

    struct JNINativeInterface {
        void*[4] dummy0;
        void function()[ 2] dummy1;
        jclass function(JNIEnv*, const(char)*) FindClass;
        void function()[22] dummy2;
        jobject function(JNIEnv*, jclass, jmethodID, va_list) NewObjectV;
        void function()[ 3] dummy3;
        jmethodID  function(JNIEnv*, jclass, const(char)*, const(char)*) GetMethodID;
        void function()[ 1] dummy4;
        jobject function(JNIEnv*, jobject, jmethodID, va_list) CallObjectMethodV;
        void function()[14] dummy5;
        jint function(JNIEnv*, jobject, jmethodID, va_list) CallIntMethodV;
        void function()[62] dummy6;
        jmethodID function(JNIEnv*, jclass, const(char)*, const(char)*) GetStaticMethodID;
        void function()[ 1] dummy7;
        jobject function(JNIEnv*, jclass, jmethodID, va_list) CallStaticObjectMethodV;
        void function()[51] dummy8;
        jstring function(JNIEnv*, const(char)*) NewStringUTF;
        void function()[ 1] dummy9;
        const(char)* function(JNIEnv*, jstring, jboolean*) GetStringUTFChars;
        void function(JNIEnv*, jstring, const(char)*) ReleaseStringUTFChars;
    }

    struct JNIEnv {
        const JNINativeInterface* functions;

        jclass FindClass(string name) {
            return functions.FindClass(&this, name.toStringz);
        }

        jobject NewObject(jclass clazz, jmethodID methodID, ...) {
            va_list args;
            va_start(args, __va_argsave);
            auto result = functions.NewObjectV(&this, clazz, methodID, args);
            va_end(args);
            return result;
        }

        jmethodID GetMethodID(jclass clazz, string name, string sig) {
            return functions.GetMethodID(&this, clazz, name.toStringz, sig.toStringz);
        }

        jobject CallObjectMethod(jobject obj, jmethodID methodID, ...) {
            va_list args;
            va_start(args, __va_argsave);
            auto result = functions.CallObjectMethodV(&this, obj, methodID, args);
            va_end(args);
            return result;
        }

        jint CallIntMethod(jobject obj, jmethodID methodID, ...) {
            va_list args;
            va_start(args, __va_argsave);
            auto result = functions.CallIntMethodV(&this, obj, methodID, args);
            va_end(args);
            return result;
        }

        jmethodID GetStaticMethodID(jclass clazz, string name, string sig) {
            return functions.GetStaticMethodID(&this, clazz, name.toStringz, sig.toStringz);
        }

        jobject CallStaticObjectMethod(jclass clazz, jmethodID methodID, ...) {
            va_list args;
            va_start(args, __va_argsave);
            auto result = functions.CallStaticObjectMethodV(&this, clazz, methodID, args);
            va_end(args);
            return result;
        }

        jstring NewStringUTF(string utf) {
            return functions.NewStringUTF(&this, utf.toStringz);
        }

        string GetStringUTFChars(jstring str) {
            auto dst = functions.GetStringUTFChars(&this, str, null);
            scope (exit) functions.ReleaseStringUTFChars(&this, str, dst);

            return dst.to!string;
        }
    }

    struct JavaVMOption {
        char* optionString;
        void* extraInfo;
    }

    struct JavaVMInitArgs {
        jint version_;

        jint nOptions;
        JavaVMOption* options;
        jboolean ignoreUnrecognized;
    }

    jint JNI_CreateJavaVM(JavaVM** pvm, void** penv, void* args);
}

void main(string[] args) {
    auto option = JavaVMOption();
    option.optionString = cast(char*)("-Djava.class.path=./kuromoji-0.7.7.jar".toStringz);

    auto arguments = JavaVMInitArgs();
    arguments.version_ = 0x00010006; // JNI_VERSION_1_6
    arguments.nOptions = 1;
    arguments.options = &option;
    arguments.ignoreUnrecognized = true;

    JavaVM* javavm = null;
    JNIEnv* jnienv = null;
    JNI_CreateJavaVM(&javavm, cast(void**)&jnienv, &arguments);
    scope (exit) javavm.DestroyJavaVM();

    auto Tokenizer = jnienv.FindClass("org/atilika/kuromoji/Tokenizer");
    auto builder = jnienv.GetStaticMethodID(Tokenizer, "builder", "()Lorg/atilika/kuromoji/Tokenizer$Builder;");
    auto tokenize = jnienv.GetMethodID(Tokenizer, "tokenize", "(Ljava/lang/String;)Ljava/util/List;");

    auto Builder = jnienv.FindClass("org/atilika/kuromoji/Tokenizer$Builder");
    auto build = jnienv.GetMethodID(Builder, "build", "()Lorg/atilika/kuromoji/Tokenizer;");

    auto Token = jnienv.FindClass("org/atilika/kuromoji/Token");
    auto getSurfaceForm = jnienv.GetMethodID(Token, "getSurfaceForm", "()Ljava/lang/String;");
    auto getPartOfSpeech = jnienv.GetMethodID(Token, "getPartOfSpeech", "()Ljava/lang/String;");

    auto List = jnienv.FindClass("java/util/List");
    auto size = jnienv.GetMethodID(List, "size", "()I");
    auto get = jnienv.GetMethodID(List, "get", "(I)Ljava/lang/Object;");

    auto source = jnienv.NewStringUTF(cast(string)read(args[1]));
    auto tokenizer = jnienv.CallObjectMethod(jnienv.CallStaticObjectMethod(Tokenizer, builder), build);

    auto token_list = jnienv.CallObjectMethod(tokenizer, tokenize, source);
    auto word_list =
        iota(jnienv.CallIntMethod(token_list, size))
        .map!(n =>
            jnienv.CallObjectMethod(token_list, get, n))
        .filter!(x =>
            jnienv.GetStringUTFChars(jnienv.CallObjectMethod(x, getPartOfSpeech)).startsWith("名詞"))
        .map!(x =>
            jnienv.GetStringUTFChars(jnienv.CallObjectMethod(x, getSurfaceForm)));

    foreach (x; word_list.array.sort.group.array.sort!"a[1]>b[1]") {
        writeln(format("%4d: %s", x[1], x[0]));
    }
}
# Mac
$ dmd fujiyama.d -L-framework -LJavaVM

# Windows(どこかにある jvm.lib とリンクして jvm.dll にパスを通せばいける、と思う)
$ dmd fujiyama.d jvm.lib

とてもつらい。主に、バインディングを書くところと、std.algorithm.sortMapResultGroup も受け取ってくれないところがつらい。

 菊池寛訳の奇巌城で実行した結果です。

 264: の
 245: ボートルレ
 221: こと
 210: ルパン
 180: 少年
 178: 人
 138: それ
 123: 一
 123: よう
 122: 二
 108: 君
 108: 中
 108: 判事
  96: 何
  89: 時
  83: ん
  81: レイモンド
  63: 僕
  62: 十
  59: 男
  59: もの
  55: 前
  55: 伯爵
  51: 嬢
  51: 私
  50: これ
  50: 方
  50: 男爵
  45: 俺
  45: エイギュイユ
...

30億のデバイスで走るジャバは、D言語の上でも走るっぽいです。あなたとジャバ、今すぐダウンロード。

 遅くなりました! 言い訳すると途中まで書いた原稿はあったけどボツにしたので間に合いませんでした! すみません! 次の25日目は、@repeatedly さんです! ほんとすみません!

JNI で JavaVM 起動 - torutkの日記

C/C++ から Java のライブラリを呼ぶ with JNI - #define NO_MONEY 0

Java SE 7 Java Native Interface-related APIs and Developer Guides - ORACLE

Monnoroch/DJni - GitHub (試していないけど使えそう)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした