TD;TR maven-shade-plugin がハマりどころ 結構新しい問題だった AIも使いよう 何が起きたのか? 久し振りに、 AWS Lambda を触ったんです。 AWS EventBridge と組み合わせて、簡易なバッチとして動かそうと。
で、実際に Lambda Function を FatJARにしてデプロイしたら、あれ? log4j2.xml のパースに失敗して、起動できない??? ローカルでは動くのに…。
まず、 pom.xml に log4j2 の BOM を設定
<dependencyManagement> <dependencies> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-bom</artifactId> <version>2.23.1</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> 依存関係に log4j-slf4j2-impl と aws-lambda-java-log4j2 を足す。
<!-- Logging--> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-log4j2</artifactId> <version>1.6.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j2-impl</artifactId> </dependency> log4j2.xml は、公式にある、一番シンプルなもの1 を置く。
そうすれば slf4j → aws-lambda-java-log4j2 → log4j2 で行けるよね?? って思ってたら、上記の如く、起動しないのです。
結局のところ これは、自分で検索したりしてもダメっぽいな…、と思ったので、Windows11付属のAIアシスタント、Copilotに質問したのですが、要領を得ない解答で少々困ってしまって。 ハレーションを起こさなかっただけマシかもですが。
https://github.com/halflite/batch-daggar-example 作りました。 単に標準出力にログを出すだけですが…。
実は「Daggerでバッチプログラム」って全然サンプルないんですよ。 Daggerって、Android用のフレームワークだと思われているのかもしれませんが…。
依存ライブラリ Maven設定 DaggerとJakarta EE 結局のところ 依存ライブラリ mvn dependency:tree [INFO] Scanning for projects... [INFO] [INFO] ---------------------< batch.daggar.example:batch >--------------------- [INFO] Building batch 1.0.0 [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- dependency:3.6.1:tree (default-cli) @ batch --- [INFO] batch.daggar.example:batch:jar:1.0.0 [INFO] +- com.google.dagger:dagger:jar:2.52:compile [INFO] | +- jakarta.inject:jakarta.inject-api:jar:2.0.1:compile [INFO] | \- javax.inject:javax.inject:jar:1:compile [INFO] +- org.apache.geronimo.config:geronimo-config-impl:jar:1.2.3:compile [INFO] | \- org.eclipse.microprofile.config:microprofile-config-api:jar:1.4:compile [INFO] +- org.apache.logging.log4j:log4j-slf4j2-impl:jar:2.23.1:compile [INFO] | +- org.apache.logging.log4j:log4j-api:jar:2.23.1:compile [INFO] | +- org.
前回、2021年6月 Javaプログラミングで “Hello World” を出したいだけだった の続き。 と言うか、自分で何かしらの結果を出したいですしね。
開発環境は、 VSCode と Rancher Desktop だけでやってみます。
自分で作ってみた 結構面倒くさいポイントその1 Guice-Servlet初期化 結構面倒くさいポイントその2 FreemarkerServlet のパッケージ 結構面倒くさいポイントその3 FreemarkerServlet の設定値 結構面倒くさいポイントその4 java.util.logging(jul) 〆の感想 自分で作ってみた halflite/guice-freemarker-servlet: Guice / Freemarker / Servlet で、自分で作ってみました。結構面倒くさい!
これに関しては、幾つかの縛りがあります。 例えば「“Hello World"を出せるくらいの小さいアプリを…」と言われた時、大抵下記のような前提が言外にあると思っても良いでしょう。
コンパイル&ビルドに迷いたくないよね 立ち上げるのには、それなりの速さが欲しいよね 当然、仮想化が前提にあるよね それなりにDI出来るコンテナ欲しいよね 設定値をDI出来る仕組み欲しいよね HTMLテンプレートも欲しいよね APIとして使うことを考えてJSONも出力して欲しいよね ログを統一的に出す機構が欲しいよね (所謂) The Twelve-Factor App ですよね。 そこら辺を踏まえた上での、自分が考えるアーキテクチャは以下です。
コンパイル&ビルドは Maven サーバーは Jetty Embedded DIは Guice/Guice-Servletに従う 設定値の取得は Apache Geronimo/MicroProfile Config HTMLテンプレートは(多分)一番シンプルな FreeMarker JSON出力は、一番軽量で早い Gson ログは Slf4j/Log4j2 JavaでWebアプリケーションで避けて通れないのが、Java EE -> Jakarta EE への移行でしょう。 あれ、単にパッケージを変えただけでも大概OKなんですが、それでもソース書き換えて再ビルドは、相当きついかもですよ。
前回の修正版です public void doSomething() { try { Path tempFilePath = Files.createTempFile("id", ".tmp"); try (Writer writer = Files.newBufferedWriter(tempFilePath)) { // do something. // 終わった後に一時ファイルを削除したい } } catch (IOException e) { // ログとか出したり、または、別の例外再スロー } } 前回書いた Files.newBufferedWriter(tempFilePath, StandardOpenOption.DELETE_ON_CLOSE) って、OSや権限で効かない場合もある、って知りました。 って言うか、自分で地雷を踏んでしまったんですけどね。
で、簡易的な解決だと、以下のようにしたら良いと思います。
public void doSomething() { try { Path tempFilePath = Files.createTempFile("id", ".tmp"); try (Closeable closeable = () -> Files.deleteIfExists(tempFilePath); Writer writer = Files.newBufferedWriter(tempFilePath)) { // do something. } } catch (IOException e) { // ログとか出したり、または、別の例外再スロー } } Closeable の匿名クラスを作って、try-with-resources 構文の中で、一時ファイルを削除する、と言う処理ですね。 Java 17 で書きましたが、 Java SE 8 でも動くと思います。
前回、2024年 Javaベースのバッチを作るなら その1 環境と初期設定 の続き。
開発環境は、 VSCode と Rancher Desktop だけでやってみます。
プロジェクトを作る 依存ライブラリを追加 実行クラス プロジェクトを作る まずバージョン確認
> mvn --version Apache Maven 3.9.6 (bc0240f3c744dd6b6ec2920b3cd08dcc295161ae) Maven home: /usr/share/maven Java version: 21.0.3, vendor: Amazon.com Inc., runtime: /usr/lib/jvm/java-21-amazon-corretto Default locale: en_US, platform encoding: UTF-8 OS name: "linux", version: "5.15.146.1-microsoft-standard-wsl2", arch: "amd64", family: "unix" 初期プロジェクト作成 1
mvn archetype:generate \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false \ -DartifactId=csvbatch \ -DgroupId=app \ -Dpackage=csvbatch.app このようなプロジェクトが作られます。
. |-- LICENSE |-- README.md `-- csvbatch |-- pom.
前回、2020年 Javaベースのバッチを作るなら の続き。
Windows11での開発だと、これが今のところ、自分なりに、まぁまぁ良い手順かな、と言うのを書きます。
要件として、「DBから昨日のデータ取ってきて、CSVに変換、メールで管理者に送信」を想定しています。
Rancher Desktop をインストール、起動 1 Visual Studio Code と その拡張 Remote Container をインストール リモートの Git で新規リポジトリを作成 チェックアウト 2 Visual Studio Codeでフォルダーを開く .devcontainer と言うフォルダーを作る 配下に3ファイル作る Dockerfile devcontainer.json docker-compose.yml . |-- .devcontainer | |-- Dockerfile | |-- devcontainer.json | `-- docker-compose.yml |-- .gitignore |-- LICENSE `-- README.md .devcontainer/Dockerfile 3
# Amazon Corretto with Java 21 / Debian 12 FROM maven:3.9-amazoncorretto-21-debian-bookworm RUN apt update && apt -y install git && \ unlink /etc/localtime && \ ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime .
Eclipseの設定を pom.xml に記述します。 Java17 / Maven 3.9.6 を想定しています。 文字コードはUTF-8、改行コードはLFになるように設定しています。 外部のライブラリのソースとJavadocも、ローカルにダウンロードするように設定しています。 <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <version>2.10</version> <configuration> <downloadSources>true</downloadSources> <downloadJavadocs>true</downloadJavadocs> <additionalConfig> <file> <name>.settings/org.eclipse.core.resources.prefs</name> <content> <![CDATA[eclipse.preferences.version=1${line.separator}encoding/<project>=${project.build.sourceEncoding}${line.separator}]]> </content> </file> <file> <name>.settings/org.eclipse.core.runtime.prefs</name> <content> <![CDATA[eclipse.preferences.version=1${line.separator}line.separator=\n${line.separator}]]> </content> </file> </additionalConfig> </configuration> </plugin> </plugins> </build> 上記を pom.xml を書き足して、以下のようにコマンドでEclipse設定ファイルを作り直します。
mvn eclipse:clean eclipse:eclipse 大抵のEclipseの設定にはm2eが入っているでしょうし、m2eでEclipse設定ファイルを更新するのもありでしょう。
まだまだ現役なEclipseとMaven、ついつい設定忘れがちなので、書き残してみました。1
2020/05/04 MavenでEclipseプロジェクトを更新した際に、ソースコードの文字コードをUTF-8にする に、加筆修正して、再度公開しました。 ↩︎
単に、自分の備忘録です。
ローカル開発環境は Windows11 / WSL2 / VSCode / RancherDesktop です。
リポジトリ作成 初期プロジェクト作成 pom.xmlを何かする コンパルのJavaバージョン FatJar/UberJar 作成設定 リポジトリ作成 GitHub や BitBUcket にリポジトリを作る VSCode でチェックアウト devcontainerの設定を作る。1 初期プロジェクト作成 mvn archetype:generate \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false \ -DgroupId=web_app_example \ -DartifactId=app \ -Dpackage=app cd app mvn clean compile 単にバッチや単独ウェブアプリなら、パッケージは浅いほうが良いでしょうね。
pom.xmlを何かする pom.xml に諸々を追加することになります。
初期はこんなものが自動生成されます
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>web_app_example</groupId> <artifactId>app</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>app</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project> ここからライブラリを足していくと、手組みで作っているなぁ!と言う感じになります。2
コンパルのJavaバージョン <properties> <maven.
永遠の課題?なのですけど、「JavaでJSONを扱う時」ライブラリをどうするかですよね。
Jackson Gson Jax-B 第一に、Jacksonですよね。 いろんなライブラリに依存で入るので、もし入ってるなら、それに従ったほうが良いでしょうか。 ただ、機能過多な気がしなくもないです。
Gson。 処理早い(体感)1 APIも、出来ることが充分だけど、少々少ない。 逆に言うと、迷うことも少ないでしょう。
Jax-B 参照実装の jaxb-runtime でやってみると、シンプルで良いですね。 あと、Eclipse EE/MichroProfile標準だし。
上記で結論出しちゃったんですけど、自分の中ではこうです
使っているライブラリで、依存で入っているのなら Jackson しがらみなく技術選定できるなら Gson 一応Java/Eclipse EE標準と言う縛りがあるなら Jax-B 処理速度とか機能面は全然問題ないのですが、実装参照のJARは Gson に比べて少々大きいです でしょうか。
よくある、速度計測とか、あんまり意味はないんですよね。 ケースによって全然違う結果になるし。 ↩︎
TL;DR Quarkus - Start coding with code.quarkus.redhat.com で、雛形を作ります。 camel-quarkus-sjms2 / quarkus-artemis-jms を依存関係に含めます。 ルート用のクラスは、DI対象に含めます。 ActiveMQ Altemis用の設定を、application.propertiesに記します。 前回 ActiveMQとQuarkus、ApacheCamelで、画像アップロード処理をしたい。 その1 Producer 編 Apache CamelとQuarkusの第一歩 Camel Extensions for Quarkus と Camel K の入門 - 赤帽エンジニアブログ はい、この通りに、Maven/Gradeleでプロジェクトを作って、実行してみましょう。1 Quarkus - Start coding with code.quarkus.redhat.com Routeの修正 上記のサンプルだと、少々使いづらい。 Routesクラスを以下のように修正します。
継承する親クラスを EndpointRouteBuilder にします。2 タイプセーフで、「流れるようなインターフェース」でルートが書けるようになります。 クラスに @ApplicationScoped アノテーションを付けます。 RoutesクラスがDI対象に含まれます。 ActiveMQからのメッセージ受信 camel-quarkus-sjms2を依存関係に加えます。 諸々必要なコンポーネントが自動で入ります。 ActiveMQ/JMSを通じて、メッセージを受信するためのコンポーネントには、camel-activemq / camel-jmsがあります。 このコンポーネントには、Spring Frameworkのライブラリが依存で入ってしまうのです。 ネット上のサンプルプログラムは、Spring-BootベースのConsumerが多いからでしょうね。 quarkus-artemis-jmsを依存関係に加えます camel-quarkus-sjms2には、ActiveMQとの通信をする、ConnectionFactoryの実装クラスが入ってないのです。 Artemis JMSの記述のようにapplication.propertiesに設定を記述すると、ConnectionFactoryもDI対象になります。 Quarkus Artemis BOMは、Quarkusと違うので、別途依存関係に追加します。 @ApplicationScoped public class Routes extends EndpointRouteBuilder { private final ConnectionFactory connectionFactory; @Override public void configure() throws Exception { from(sjms2("topic:upload.