20211127のJavaに関する記事は4件です。

GitHub Actions で Error: Gradle Wrapper Validation Failed!

GradleでのJavaのビルドとテスト を元にGitHub Actionsを設定をしたら、以下のようなエラーが出たので解消メモ。 Run gradle/wrapper-validation-action@v1 with: min-wrapper-count: 1 allow-snapshots: false env: JAVA_HOME: /opt/hostedtoolcache/Java_Adopt_jdk/11.0.11-9/x64 Error: Gradle Wrapper Validation Failed! See https://github.com/gradle/wrapper-validation-action#reporting-failures ✗ Other validation errors: Expected to find at least 1 Gradle Wrapper JARs but got only 0 実際に引っかかってるコードは以下。 gradle-wrapper.jarをバージョン管理してなかったので、.gitignoreを修正して解消。 gradle/wrapper/gradle-wrapper.jar
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kotlinについて徹底的に客観的に分析してみた

先日開催されたJJUG CCC 2021 Fallにて『Kotlinを研究する』というタイトルで発表しました。 その中でいくつか面白さを感じていただけそうな部分をピックアップして紹介していきたいと思います。 元発表 スライド https://speakerdeck.com/doyaaaaaken/kotlinwoyan-jiu-suru 動画 https://youtu.be/T6cS67VEGO4 内容概要 現状のKotlinについて徹底的に客観的に分析した内容になります(そういった背景から”研究する”というタイトルにしました)。 基本的には発表は個人的な見解として行うものですが(例:『Kotlinの拡張関数という機能はイケてる!』)、世の中の公開データを元に2021年末現在のKotlinについてなるべく主観を排除して分析してみたら有用な知見になりそうだと感じこのテーマにしました。 ピックアップポイント 1. Kotlinは2016年にv1リリースされた若い言語 他のモダンな言語であるRustやGoよりも後発。 Goは2012年、Rustは2015年にv1をリリース。 2. 若い言語なのにも関わらず言語仕様として新しい発明はほぼない Kotlinが新しく発明した機能・概念はごくわずか。 モダンな他の言語の良い点を取り入れ言語仕様が作られ、”Pragmatic”な言語を目指している(※後述)。 3. "Pragmatic(実用的)"という言語思想 Pragmatic(実用的)な言語を目指して作られており、他のモダンな言語の良いところを取り入れ、簡潔で安全に書けるようにしている。 エレガントさより、有用さを重視している。 ”実用的”というのはコーディング中だけでなく開発者体験全体を指しており、例えば以下のような点にも気を使って開発されている。 Javaとの相互互換性(=Javaプロジェクトに混ぜられるため少しずつ置き換えができる) Javaの既存エコシステム(例:Javaライブラリ, Maven, Gradle)を利用可能 IDEを使った開発者体験(補完・警告等)を重要視 学習コンテンツなどを用意・拡充している 4. 2017年のGoogle I/Oが転機で普及した 2017年のGoogle I/OでAndroidの開発言語としてサポートすることが発表され、それを機に一気に普及した。 (なおちょうどその2年後に、GoogleがAndroidの開発言語としてKotlinを第一言語として推奨する発表をした) 5.Android開発では現在支配的な地位を確立 Android公式ドキュメントによると、上位1,000件のAndroidアプリの80%以上にKotlinコードが含まれているそうです。 6. Android開発以外にもサーバサイド開発でも広く使われている 元々Jetbrains(KotlinやIntelliJを作ったチェコの会社)が社内のJavaアプリケーション(IntelliJなど)コードを置き換えていく用にKotlinを発明しただけあって、グローバルではAndroidに次いでサーバサイド開発でも広く利用されている模様。 ちなみに日本だとNewspicksさんがサーバサイドの主要言語をJavaからKotlinに置き換えたりした事例が2021年にありました。 他のサーバサイドKotlinの国内事例はこちらの記事にもまとまっているようです。 7. 現在はコンパイラの書き直しや、Multiplatform対応を進めている 言語仕様としてはもう成熟しているので、現在はコンパイラの書き直しによるパフォーマンス向上や、Multiplatform対応(JVM以外のプラットフォームでも動かせるようにする対応)に注力している。 まとめ 以上、発表内の重要な点をまとめてみましたが、ぜひご興味わいた方は元スライドのほうもご覧いただけますと嬉しいです! それでは皆さん、よいクリスマスを!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Java】package privateなメンバーはその気になれば外部プロジェクトからアクセスできる

はじめに Javaにおけるアクセス制御修飾子には以下の4種類があります。 public どこからでもアクセス可能 protected 同じパッケージ内か、もしくはサブクラスのインスタンスからアクセス可能 アクセス修飾子なし(package private) 同じパッケージ内からのみアクセス可能 private 同じクラス内からのみアクセス可能 これらは見ての通り、下に行けば行くほどアクセス可能範囲が狭いです。publicとprotectedが公開API、package privateとprivateが非公開APIとされます。 今回話題にしたいのは、下から2番目のpackage privateです。package privateというのが正式な呼び方かわかりませんが、その呼ばれ方の通り限りなくprivateに近いものなのだろうと思っていたのですが、案外そうでもなかったぜというのがこの記事の趣旨です。 結論 package privateが「同じパッケージ内からのみアクセス可能」という理解は正しいが、外部のプロジェクトにおいても同じ名前のパッケージを作成することで、そのパッケージ内からはアクセス可能になる。 サンプルコード 話としては上に書いた通りで、大したコードは出てこないですが一応書きます。 呼ばれる側のコード package foo.bar.internal; public class PackagePrivateSample { public void publicMethod() { System.out.println("PackagePrivateSample.publicMethod"); } void packagePrivateMethod() { System.out.println("PackagePrivateSample.packagePrivateMethod"); } protected void protectedMethod() { System.out.println("PackagePrivateSample.protectedMethod"); } private void privateMethod() { System.out.println("PackagePrivateSample.privateMethod"); } } 上記をビルドしてjarファイルを作成します。 呼ぶ側のコード こちらは上記と同じプロジェクト内ではなく、上記でビルドしたjarを参照して別プロジェクトとして作成します。 仮にGradleプロジェクトとしたら、以下のような感じでローカルのjarを参照します。 test_package_private-1.0-SNAPSHOT.jarが該当のjarファイルで、libフォルダに置いたものとします。 (それ以外の記述は自動生成そのままにしているだけなのでなくてもいいかもです) plugins { id 'java' } group 'org.example' version '1.0-SNAPSHOT' repositories { mavenCentral() } dependencies { implementation files('lib/test_package_private-1.0-SNAPSHOT.jar') testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0' } test { useJUnitPlatform() } まずは、参照できないパターンです。 package foo.bar;  // <- パッケージが違う import foo.bar.internal.PackagePrivateSample; public class UseSample { public static void main(String[] args) { var sample = new PackagePrivateSample(); sample.publicMethod(); // 以下は呼べない(コンパイルエラー) // sample.privateMethod(); <- 'privateMethod()' has private access in 'foo.bar.internal.PackagePrivateSample' // sample.packagePrivateMethod(); <- 'packagePrivateMethod()' is not public in 'foo.bar.internal.PackagePrivateSample'. Cannot be accessed from outside package // sample.protectedMethod(); <- 'protectedMethod()' has protected access in 'foo.bar.internal.PackagePrivateSample' } } 実行結果 PackagePrivateSample.publicMethod 続いて、参照できるパターンです。 package foo.bar.internal; // <- パッケージが同じ! public class UseSample { public static void main(String[] args) { var sample = new PackagePrivateSample(); sample.publicMethod(); // 呼べる! sample.packagePrivateMethod(); // ついでにこれも呼べる sample.protectedMethod(); // これはさすがに呼べない // sample.privateMethod(); <- 'privateMethod()' has private access in 'foo.bar.internal.PackagePrivateSample' } } 実行結果 PackagePrivateSample.publicMethod PackagePrivateSample.packagePrivateMethod PackagePrivateSample.protectedMethod 余談 同じパッケージ内に同じ名前のクラスを作って、その中からprivateメンバーを呼べちゃうかどうかも調べましたが、それはさすがに無理みたいです。 (クラスは作れるが、参照がそちらに上書きされて元のほうが参照できなくなる) 終わりに まあこんなことやるか?と言われたら普通やらないとは思うのですが、ちょっとびっくりしました。 Effective Javaには、テストを容易にするためにprivateなメンバをpackage privateにすることは許容されるという趣旨のことが書かれていますし、あんまり気にしなくてもいいと思いますが、知識としては持っておいてもいいかもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

僕とMavenの3650日

Mavenって何 MavenはJavaのビルド・パッケージングツールです。誤解を恐れずにいうならばJavaプログラムの 「ビルドサイクルマネージャ」ともいえます。今回はこのMavenについてまとめていきます。 いつものことですが、この文書には「本当ではないこと」が含まれています。理解しやすさを優先して経緯の時系列や仕様など丸めながら再考しています。読んでくれた方の興味関心に少しでも応えられたらうれしい限りです。 Mavenと僕 僕の今の会社での最初の仕事は、Javaのプロジェクトをコンパイルすることだった。大規模な金融バックシステムをコンパイル、パッケージングするためのビルドツールとして僕はAntをを選んだ。Antはきちんと仕事をして、予定通り動作しリリースすることがきた。Subversionと連動したこの自動ビルド・リリースの仕掛けは、当時としてはちょっとした物だったけど、私のオリジナルだったことからなかなかに手離れが悪いものとなった。以後数年このビルドシステムの子守を僕がすることになってしまった。 「Ant書けるなんてすごいじゃん。ところでMavenって知ってる?」 今でも尊敬しているある先輩から、言われたときでも 出始めで、資料が少ない。Antに比べて実績がない 難しそう Antで十分 こんな理由から採用を見送った。もう少し勉強して、採用すればよかった。せっかくキーワードはもらっていたのに僕はその努力を怠った。 僕とMavenの出会いは、ちょっとほろ苦いものだった。 さぁビルドを始めよう ビルドって何? さて、ソフトウェアのビルドとはなんだろう。一言でいうと「ソースコードをかき集めて動作可能なモジュールとしてまとめてしまうこと」だと思う。 大規模開発だとこれが意外に大変。I/F勝手に変えるアホとか、I/F追加のタイミングが合わなくて、他のプログラムが先に実装したりとか。。主にI/F面ですごーく苦労する。 ビルドの作業内容は大同小異あっても大体こんな感じじゃないだろうか。 No. 作業項目 作業内容 検討事項など 1. SRC収集 SCMもしくは(狂ってるけど)ファイルサーバから対象のソースをかき集める。 どうやってソースコードを集める? 2. ライブラリ収集 プログラムが使うライブラリをコンパイルのために集めておく ライブラリの管理方法を考える。コンパイル時にだけ必要なライブラリ実行時環境にも持ち込む必要があるライブラリテスト時だけ必要なライブラリ 3. コンパイル ソースコードを実行可能コードに変換する。(ちょっと違うけど) コンパイルする方法を考える。 4. 単体テスト 最低限の品質確保のために、ホワイトボックステストをする。 JUnitなどを実行。単体テストの実装方法などなど 5. パッケージ作成 出来上がったプログラムを配布可能な状態にする。 Jarにまとめる。Jarファイルの単位 「こんなのEclipseがあれば余裕っち」 と考える人も多い。個人で使う分にはそうすればいい。(僕なら個人でもやらないが) 複数人での作業を前提とする場合、どれもそれなりに整理が必要。特に2はきちんと考えておかないとまずい。俗人的になりやすいので。。 Javaのビルドツール Javaは素晴らしい。開発に必要なツールはあらかた、JDKに入っている。よーし今日から俺もJavaプログラマ!!コンパイルはどうすればいいのかな。。。。 な、ない!!! 統合開発環境がどこにもない!!! ん??? jar: 複数のファイルを1つのJARファイルに結合します。 java: Javaアプリケーションを起動します。 javac: Javaクラスとインタフェースの定義を読み取り、バイト・コードのクラス・ファイルにコンパイルします。 あ、コンパイラとパッケージャは同梱しているんですね。。。じゃぁ、見てみましょう。大丈夫。僕は空気が読める男なので、ファイルをいきなりダブルクリックしたりはしません。コマンドプロンプトで。。。 > javac --help 使用方法: javac <options> <source files> … --class-path <path>, -classpath <path>, -cp <path> ユーザー・クラス・ファイルおよび注釈プロセッサを検索する位置を指定する … えっと。source filesってことはファイルを一覧化して渡さないといけないんですね。依存ライブラリも一つ残らず、全部class-pathを列挙しなくちゃなんですね。 千オーダーで存在するファイルを一つも抜けもれなくリストするってどういう罰ゲームですか? というわけで、javacコマンドを直接使うのは却下ですね。。。 ちなみにご参考まで。私、Windowsバッチで必至にJavacをループ回してるプロジェクト知っています。。控えめに言ってアタマオカシイです。 ほかには、--class-pathを環境変数%CLASSPATH%で解決して、Jarのファイル名一覧が環境変数の上限を超えたとか。。。 もうなんだろうね。。ちゃんとやり方調べりゃいいのに。 第一世代 Makefile 最初期、Javaは言語専用のmakeが用意されていなかった。そこで、先人たちはmakeを流用した。makeの使い方は久しく忘れてしまったので、ここでの詳細や例示は避ける。ただ、個人的には 卒論用のシミュレータ(C) 卒論本体(Latex) あたりはmakeで書いてたし。Javaも初期はmakeでビルドしていたような気がする。でもまぁやっぱり不便だった。それは主に Javaではソースコードがたくさん増えていく。しかもディレクトリも分かれていく Javaのライブラリ解決方がめっちゃ面倒くさい。(=CLASSPATHに全部入れる。) に起因していて、結局「大量のファイルを一括して扱うための仕掛け」ってのが 必要というのが当時の感想。 そんな時、僕は出会ってしまうのだ。。運命の蟻に。。。。 第二世代 Apache Ant Apache Ant is a Java library and command-line tool whose mission is to drive processes described in build files as targets and extension points dependent upon each other. The main known usage of Ant is the build of Java applications. もう大好きant!! 登場時期は2000年代の頭だった気がする。それ以来ずっと使っている。なんと2014年の仕事で、antベースのAnsibleもどき作っちゃうぐらいには好き1 何がいいって。 filesetとmapperが超強力 ソースもライブラリも「集合」としてまるめて考えられる。 Windows(\)もLinux(/)にも対応しちゃう。疑似PATHがやっぱり強力 ライブラリへのクラスパス設定がすごく楽 わりと何でも書けるぐらい条件分岐がかけたりもする。 豊富なモジュール 主に、Java開発では肥大しがちな「ファイル」を手軽に、抽象化して扱い、ビルドの再現性を高めるためのツール。makeの時に感じた課題感にピッタリはまる。。 ハイ。採用。 ことファイルを集合として扱う作業でant以上の強力なツールを僕はしらない。そのため、僕の使うPCには必ずantが入っている。2 Antの課題 antは超便利なツールで、革命的だったけど。結局どうやって依存ライブラリを集めるのかとか、ソースコードをどう配置すべきなのかとか、出来上がったライブラリをどうやってバージョニングしながら共有するのか等といった課題には一切答えていない。というかツールのスコープ外 この「スコープ」をきっちり守ってそれ以上に広げようとしないのはすごく良いことだと思う。中途半端なもの作るぐらいなら…というね。3 実はこれ、あまり知られていませんが。この記事。ここからが本編なんですよ。 第三世代 Apache Maven ねぇビルドって作る対象によってそんなに変わるもの? 実は、何も変わらない。だったら。。。「型にハメて考えること減らそうぜ!!」というのが普通の発想。この「標準化」っていくつか利点があって。 考えることが減る(もう。考えるのはやめだ!!疲れるから。。。) 準備が楽になる。(画一化する) 画一化しているので、自動化可能 つまり、標準化のゴールは自動化とも言える。逆に標準化なくして自動化なし。Mavenが提供するの大きく以下の定義。 No. 名前 1. 標準ビルドライフサイクルの定義 2. 標準ディレクトリ構成の定義 3. 標準ライブラリ依存解決方法の定義 Mavenが提供するのはビルドに関する「定義」。定義することで、人は考えるのをやめる。ヒューマンリソースを生産的な方向にむけることができる。 標準ビルドライフサイクル(= Phase)の定義 Mavenの「jar」「ejb3」「war」に対するビルドのライフサイクルは以下の通りです。 NO. phase 役割 1 process-resource パッケージングに備えて、リソースをtargetディレクトリにcopyする 2 compile src/main/java配下のソースをコンパイルしてJavaバイトコードに変換します。 3 process-test-resource テストに備えて、リソースを所定のディレクトリにコピーする。 4 test-compile testコードをコンパイルしてJavaバイトコードを生成する。 5 test テストを実行する 6 package テスト済みのコードを「jar/war/ear」にパッケージングする 7 install ローカルリポジトリに、生成したパッケージファイルを登録する。 8 deploy リモートリポジトリに、生成したパッケージファイルを登録する。 これを図で表すと、 ご覧の通り最初の図に綺麗にMapします。それもそのはずで、Mavenのライフサイクルに慣れてしまった後、私は基本的にこのサイクルで考えるようになったからです。標準化されて使いやすいし、概念としていれておけば他のあらゆる言語に応用が効きます 標準ディレクトリ構成の定義 Mavenでは1つのJarファイル=1プロジェクトとして整理する。 ディレクトリ 役割 ├─pom.xml プロジェクト定義ファイル。依存ライブラリの定義や生成するライブラリ名などを定義するファイル │ └─src プロジェクトリソース格納ディレクトリ   ├─main 稼動系リソース格納用。最終的に生成されるライブラリに入るのはここに格納されたリソースのみ   │ ├─java java ソースファイル   │ │   │ └─resources javaソース意外のファイル   └─test テストリソース格納用。テストフェーズで優先的に利用される。        ├─java javaのテストソース        │        └─resources java意外のリソース このように定義することで、「ソースを集める先を決める」とか「テスト実行時のクラスパスの順序」への考慮とか面倒くさいだけで本質的ではない検討をすべてぶっとばせる。eclipseの.projectとか.settingsとかいらないものを管理する必要もない。 また、「標準」であることから、手順をいちいち記載する必要がない。10人いても100人いてもMaven標準ディレクトリなんでよろと言えばいい。俺の仕事にはこいつが特に重要でね   「Maven 標準なんで手順は書きません」   「分からない人はどうするんですか?」   「その程度の人を雇っても別のところで苦労するだけです。いりません。」 こんなやり取りをするわけです。標準を知らないってのはそういうことです。 標準ライブラリ依存解決方法の定義 Mavenはライブラリ依存解決の方法を定義した。これが画期的。Maven以前とMaven以降ではライブラリ管理方法に雲泥の差がある。 Maven以前のビルド風景 全てのライブラリは、公開サイトもしくは製品パッケージから作業者が取得し、クラスパスに通す。超俗人的。つまり「秘伝のたれ」。ガッコ親父が30年煮詰めて作った汗と涙と埃の結晶。。本当にこれ食べれるの??ってやつになる。またこの時ファイル名の変更などをしてしまうと、実際に使っているバージョンが容易にはわからず、環境再現するのが困難となる。ビルドの仕掛けを変えたくなくてファイル名変えるあれな人もいるので混乱する。「あれ?Version 2ってなってるんだけど、3以後で削除されてるあのメソッドもう削除されてるよ。。。おい。誰だよファイル名変えやがったのはさぁ!!!!」とか痛い痛い。いや、何度も使うネタで恐縮ですが。「これ、普通にあるんですよ?」 Maven以後のビルド風景 Maven以後は、全てのライブラリは、Mavenリポジトリから取得される。Mavenリポジトリは各ライブラリの過去のバージョンも保持しているため、必要に応じて過去のバージョンも利用可能。利用するライブラリはPOM(Project Object Model)に宣言的に保持される。Mevenはこの POMをもとに、ライブラリを取得し利用する。このためPOMはいわばMaven Project 設計図もと言える。 作業者は「利用するライブラリ」「利用したいバージョン」を決定しPOMに記載する。Mavenはこの情報をもとに勝手にビルド時に解決してくれる。これは「宣言的」な運用が可能となることを意味する。宣言したものが宣言したとおりに出来上がる。あたり前のように見えるがソフトウェア開発の管理の面ではすごくありがたい。 助けて。15年前のプログラムをビルドすることができないの。。 こんな問題もさくっと解決。だって、全てはPOMファイルに書かれているから。ソースコードと一緒に格納して管理するのだから、コードがあれば依存関係が分かる。こんなアホな(そして困ったことに時折ある)状況は消滅する。 なお、このMavenリポジトリは、Javaプロジェクトのビルドのデファクトスタンダートとなっている。GradleなどJavaベースの言語用のビルドツールの他、ScaleのためのSBT等、Javaベースの派生言語におけるビルドツールのライブラリリポジトリとしても利用されている。 第四世代 Gradle 前述のようにMavenはPomに記載された内容を、Mavenのライフサイクルで実行する。つまり基本的に作業可能なのは mvn clena package deploy だけとなる。たとえば、あるファイルが存在するか否か、現在の曜日などをもとに処理を分けたい場合とかかゆいところに手は届かない。そこでMavenのもつ強力な依存解決を利用しつつ、条件分岐等の記載の自由を獲得するために開発されたのがgradleである。つまり登場コンセプトは 親の敷いたレールになんて乗るのは嫌だ!俺は、自由に生きるんだ なんですけど、自由って言ってもあれですよね。。やることビルドですよ??同じですやん。 まぁ、親の敷いたレールから逃れるため、GradleはDSLとしてgroovy(今はkotlin)を採用し、Javaおよびその派生ライブラリを使ってなんでもできるいい子ではある。 プログラムの様に細かくいろいろとかける代わりに、事前の設計項目が多く、スピーディにPJを立ち上げたい場合等には向かない。大規模PJでは使いにくい。でもまぁ慣れれば何でもありだけどさ。 じゃぁ、Gradle使っておけば正解? 時と場合による。Gradelのもつ強力なキャッシュ機能とか、より洗練された推移的依存解決やその他もろもろが欲しいのなら、Gradleかな。一方で、やること既に決まっていて、ビルド自体あまり考えたくないなら、脳死でいけるmavenがいいかと思う。僕は 自由がないこと、制限、制約があることの素晴らしさ を享受するために、mavenを好んで使う。 あのさ、なんでも自由ならいいってもんじゃないのよ?300人参加する開発でさ。4全員が自由にやってごらんなさいよ。すごいことなるから。あとさ、お前ら「自由が欲しい、やりたいことができない」って言うくせに、自由にどうぞっていうと「手順がない、やり方を教えろ」っていうじゃん。束縛大好きじゃん。結局自由を活用できないなら、束縛大好きッ子として、制限制約のある気楽さを選ぶのがいいんだよ。。ほんと。。 あ、なんか愚痴になっちゃった。。。 IDEとビルドツール 序盤でもそっとふれたけど、「IDEあればビルドツールいらないじゃん。俺、InteliJだしって。」って思うでしょ? でもね、IDEだってコンパイルはする。コンパイルつまりビルドのためには、ビルドを実行する仕掛けが必要。わざわざ専用のツールを作るのは無駄なので、IDEツールではmaven/gradleを内部的に呼び出していたりもする。依存解決も楽だしね。つまり、知らないうちに使っているのです。ほぼ誰でも。 以下は一例である No. IDE デフォルトのビルドツール 他に利用できるツール 1 Eclipse 独自(すまんうろ覚え) Maven/Ant 2 NetBeans Maven ANT 3 InteliJ Gradle - 4 AndroidStudio Gradle InteliJ派生だしね。 参考まで、Gradleとか書きたかったら、InteliJが最高!でも僕は、Maven大好きっこなので、NetBeansが大好きです まとめ Antは便利だけど、いちいち全部をかかなくちゃいけないから不便だよ。 Mavenはディレクトリ構成、ライフサイクルを標準化することで、作業効率と再現性を向上させているよ *Maven以後のJavaビルドツールはMavenリポジトリを利用可能だよ 当時Ansibleを知らなかった。後から知って、「しまった!!」と思ったのは言うまでもない。 ↩ この点については別の記事を起こして語ろうと思う ↩ 依存性解決についてはApache Ivyで解決済み。連携プロジェクトとして独立しているのがよい。 ↩ リアル「世紀末救世主伝説」を再現したいなら、止めはしない。 ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む