0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

UNOをJavaで書くのは煩雑だよ(lojのすすめ)

0
Posted at

LibreOfficeをJava帳票開発に使う(lojの紹介)

を書きました。

この記事では、いかにUNOをJavaで書くのは煩雑かを示し、lojの使用をおすすめします。

lojはこちらです。

ns2j/loj

UNOは高機能だけどJavaから使うと大変

LibreOfficeにはUNO(Universal Network Objects)という非常に強力なAPIがあります。

Calcのセル操作、書式設定、シート操作、グラフ、印刷、PDF出力など、LibreOfficeのさまざまな機能をJavaから操作できます。

しかし、JavaからUNOを直接利用すると、ちょっとした操作でも複数のUNOインターフェースを扱う必要があります。

例えば、UNOでは取得したObjectをそのまま目的の型として扱うのではなく、

XSomething xSomething =
    UnoRuntime.queryInterface(
        XSomething.class,
        object
    );

のように、目的のUNOインターフェースを取得してから操作するコードが頻繁に登場します。

処理が複雑になってくると、

Object
  ↓
XSpreadsheetDocument
  ↓
XSpreadsheets
  ↓
XSpreadsheet
  ↓
XCellRange
  ↓
XPropertySet

のように、目的の操作をするために次々とインターフェースを取得することになります。

UNOの仕組みとしては合理的なのですが、帳票を作りたい側からすると、

A1セルに値を入れたいだけなんだけど……

となります。

プロパティ設定も長い

LibreOfficeでは書式などの多くがPropertyとして公開されています。

そのため、例えば背景色を設定する場合にも、対象オブジェクトからXPropertySetを取得して、

XPropertySet props =
    UnoRuntime.queryInterface(
        XPropertySet.class,
        object
    );

props.setPropertyValue(
    "CellBackColor",
    0xAAAAAA
);

のようなコードを書くことになります。

背景色を設定するという処理そのものは単純なのですが、

UNO Objectを取得
       ↓
XPropertySetを取得
       ↓
プロパティ名を指定
       ↓
値を設定

という手順が必要になります。

帳票ではセルの背景色、罫線、フォント、表示形式など、多数のプロパティを設定するため、このようなコードが大量に出てきます。

loj-proxyでUNOをラップする

そこでlojでは、UNOインターフェースをJava Reflectionで解析して、Javaのラッパークラスを自動生成します。

UNOインターフェース
        ↓
     Reflection
        ↓
     loj-proxy
        ↓
P_Doc
P_Sheet
P_Range
P_Cell
...

例えば、生成されたP_*クラス内部で必要なUNOインターフェースへの変換を行うため、アプリケーション側で毎回UnoRuntime.queryInterface()を書く必要を減らせます。

さらにXPropertySetを持つオブジェクトでは、lojはprop()を利用できます。

range
    .prop("CellBackColor", 0xAAAAAA)
    .prop("CellStyle", "My Style");

UNOを直接使う場合に繰り返し登場する処理を、生成されたラッパー側へ押し込んでいます。

さらに高水準APIを作る

ただし、UNO APIをラップしただけでは、まだ帳票を書くには低水準です。

そこでlojでは、自動生成されたP_*クラスの上に、

Doc
Sheet
Range
Cell

という手書きの高水準APIを用意しています。

構造としては、

アプリケーション
       ↓
Doc / Sheet / Range / Cell
       ↓
自動生成された P_* クラス
       ↓
LibreOffice UNO API
       ↓
LibreOffice

となります。

例えば、セルに値を設定しながら右へ移動する処理なら、

Cell c = sheet.getCell("A1");

c.set("JAN")
 .right().set("FEB")
 .right().set("MAR");

と書けます。

帳票を作っている側から見れば、

UNOのインターフェースを取得する

より、

セルに値を入れる
右へ移動する
次の値を入れる

と書けた方が、やりたいことがそのままコードに現れます。

全部を高水準APIにする必要はない

ここで重要なのは、lojがUNOを隠してしまうライブラリではないことです。

P_*クラスからgetProxy()を使えば、元のUNO Objectを取得できます。

つまり、

普段の帳票処理
      ↓
Doc / Sheet / Range / Cell
      ↓
     P_*

特殊な処理
      ↓
  getProxy()
      ↓
UNO APIを直接使用

という使い分けができます。

高水準APIに存在しないLibreOfficeの機能を使うために、すべてをloj側で実装する必要はありません。

必要なところだけUNOへ降りることができます。

なぜP_*を自動生成するのか

LibreOffice UNO APIは非常に巨大です。

これをすべて手書きのJavaラッパーとして実装して保守するのは大変です。

そこでlojでは、

機械的に作れる部分
        ↓
loj-proxyで自動生成

帳票として使いやすくする部分
        ↓
人間がDoc / Sheet / Range / Cellを書く

と役割を分けています。

LibreOfficeのバージョンを変更した場合も、UNOインターフェースからP_*クラスを再生成できます。

つまり、

機械に書けるコードは機械に書かせる

という方針です。

loj.myはサンプル

Doc、Sheet、Range、Cellなどはloj-sb-sampleのloj.myパッケージに入っています。

これは完成された高水準APIを固定的に提供するというより、利用者がコピーして、自分の帳票システムに合わせて育てていくことを想定しています。

例えば、

cell.set(...);

だけではなく、

cell.right();
cell.down();

のような、自分の帳票で頻繁に使う操作を追加していくことができます。

したがってlojは、

UNO
 ↓
自動生成された汎用ラッパー
 ↓
自分の用途に合った高水準API
 ↓
帳票プログラム

という構造になります。

サーバーで使うならloj-util

UNOをJavaから使う場合、API操作だけでなくLibreOfficeへの接続も考える必要があります。

loj-utilには、

  • LibreOfficeプロセスの起動・接続
  • Socket / Named Pipe接続
  • 接続プール
  • Java StreamとUNO Streamの変換
  • 一時ユーザーディレクトリ

など、サーバーアプリケーションからLibreOfficeを利用するための仕組みを用意しています。

そのためSpring Bootなどから、

リクエスト
   ↓
Java / Spring Boot
   ↓
loj
   ↓
LibreOffice
   ↓
ODS / PDF / Printer

という帳票処理を構築できます。

まとめ

UNOは非常に強力です。

しかしJavaから直接利用すると、

UNO Object
   ↓
queryInterface()
   ↓
XSomething
   ↓
queryInterface()
   ↓
XPropertySet
   ↓
setPropertyValue()

といったコードが多くなり、帳票本来の処理がUNOの定型コードに埋もれやすくなります。

lojでは、

UNO API
   ↓
loj-proxyによる自動生成
   ↓
P_*クラス
   ↓
Doc / Sheet / Range / Cell
   ↓
帳票処理

という層を作ることで、UNOの煩雑な部分をできるだけ下の層へ追い出します。

それでも必要になったらgetProxy()からUNOへ戻れます。

UNOは強力なので使いたい。

でも、

UNOを毎回そのままJavaで書くのはつらい。

そんなときにlojを使ってみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?