【Java】AdoptOpenJDK 11がLTSをサポート
Javaのサポートについて
OracleのJavaへのサポート体制の変更が波紋を呼んでいます。
Oracle JDK 11の有償化
事の発端は、OracleがJava 11の提供を有償化する声明を出したことでした。
Oracleは今まで、Javaのバージョンを約3年ごとにリリースし、約5年ごとのサポート期間を設けていました(Long Term Support、LTS)。
例えば、
となっています。
しかし、Oracleは2017年9月にリリースされたJava9以降6ヶ月ごとにリリースを行うスタイルに変更します。 同時に、次回verがリリースされるのと同時に、前回verのサポートを打ち切る方針に転換しました(Feature Release Model)。
- Java9 ・・・2017年9月21日にリリース(2018年3月にサポート終了)
- Java10・・・2018年3月20日にリリース(2018年9月にサポート終了)
すなわち、Oracle Javaを今後使っていく人は早いサイクルでアップデートをし続けなくてはならない、という流れになりつつありました。
本来であれば、セキュリティや新機能実装の観点からこまめなアップデートは推奨されるべきなのですが・・・。
中~大規模なシステムだとアップデート作業やテスト、デグレ解消に結構な工数がかかるので、長期間安定して使えるJDKが欲しいというのが実情だと思います。
ところが2018年9月、OracleはJava 11がリリースを決定したのですが、Java 11 の商用利用を有償化し、同時にLTSとすると発表したのです。
システム運用等の業務でJavaを使っている人からすれば長期サポートは嬉しいのですが、いきなりの有償化宣告に対応する余裕はありません。
なんとかして無償でJavaを使い続けられる環境を維持したいものです。
ちなみにJava8はサポート期限が2019年1月とJava9よりもあとまでのサポートとなっています。
期間的にはだいぶ長めですが、来年頭にはサポートが切れるので同様の対応が必要になります。
(Oracle 公式より引用)
Java8~10の刻々と迫るサポート期間、Java11 LTS の有償化にJava界隈がざわついていました。
OpenJDK
OpenJDKはその名の通り、Javaプラットフォームをオープンソース化したものです。
OpenJDKの実装にはOracleも参画しており、商用にも耐えうる実装であると考えられます。実際、OracleはOpenJDKの2018年の最新バイナリをOracle JDKに統合した上で、今後のOracle JDKを運用していく旨を発表しています。またオラクルの声明では以降無償Javaを利用するにはOpenJDKを使ってねとも言っています。
こちらのJDKであれば無償で使うことができますね!
・・・と思いきや、OpenJDKはLTSをサポートしていません。
つまり、OpenJDKを利用する場合、6ヶ月ごとにJDKのバーションをアップデートしなければならなくなります。
ここで再びFeature Release Modelの問題が発生します。
無料で、かつLTSなJDKが欲しい・・・!
AdoptOpenJDK 11
そんな中、AdoptOpenJDKが興味深いサポートライフサイクルを提示していました。
AdoptOpenJDKはIBMやRedHat、SAP、オラクル等に所属するメンバーが参画するOpenJDKコミュニティーです。 OpenJDKのビルドを提供します。 彼らの提供するJava 11のJDKは、無償かつLTSとのことでした。
12以降はどうなるかわかりませんが、少なくともJava 11を3年間サポートを受けながら使えるようですね。素晴らしいです!
ただ、公式のgithubのissueでビルドできないとの報告も上がっており、少々不安も感じさせます。
OpenJDK でも Java 11 をLTS化?
orangeitemsさんの記事に最新情報があがっていました。
また、Redhatの姿勢が明らかになっています。2018/6/4に、RedHat社は、OpenJDK8のサポート終了後は、OpenJDK11をリリースしこれをLTS(長期サポート)すると明言しました。
Red Hat OpenJDK 11 Advice - Red Hat Customer Portal
RHELでOpenJDK8を動かしているのであれば、11への移植をお勧めします。
https://www.orangeitems.com/entry/2018/02/08/152022 より引用
どうやら、RedHatが公式にOpenJDK 11をLTS化することを発表したようです。
リンク先の記事を参照したかったのですが、subscription専用なので読み進められない・・・
これが本当であれば、今後の無償JavaはOracleの声明どおりOpenJDK一択となりそうです。
参考
【OAuth】Twitter OAuthでのWhite ListにCallback URLを登録する
Twitter 認証APIの仕様変更
6/12-13(?)ごろ、Twitter 認証用APIの仕様が変更され、パラメータとして指定されたcallback_urlがApplication Manager上で登録されていない場合、HTTP 403 エラーを返す仕様となりました。
これを受け、Tiwtter連携を扱うサービスのログインなどで一部不具合が見られました。
企業が提供するアプリはもちろんのこと、個人で開発しているアプリでも同様の現象が発生しうるので、今回はそれらの対応方法について書きます。
Application Managerの設定を変更する
Twitter Application Managerページに移動します。アプリを管理するアカウントにログインする必要があるので、ログインしていない方は予めログインしてください。
次に、設定するアプリ名をクリック。
「Service」タブをクリックします。
「Callback URLs」という欄があるので、入力フォームにCallbackURLを入力し、「add a Callback」をクリックしてください。CallbackURLは最低2つ入力する必要があります。
あとは画面一番下の「Update Setting」を押して完了です!
余談
Twitter連携で認証・認可後、利用したいユーザデータにemailを含めたい場合は「Permissions」タブ->「Additional Permissions」欄のチェックマークにチェックを入れることで可能となります。
参考
【Watson】Watson Studio でMNIST手書き文字認識を行う①【Watson Studioセットアップ】
Watsonとは
IBM Watsonは、IBMが提供するAIサービスです。
主に自然言語処理系の機械学習を行うAIを提供しており、文章のカテゴライズや文章と音声間の変換などをサポートします。
また自然言語処理だけでなく、画像認識の機能の提供も行っています。
Watson Studioとは
Watson Studioは、機械学習を用いたデータの統合開発・分析環境です。
従来のWatsonが提供するAIサービスにとらわれず、機械学習のためのモデル作成や学習を柔軟に行うことができます。
今までpythonを使ってTensorflowやChainerなどをゴリゴリ書いていた人も、Watson Studioを使えば簡単にモデルを構築でき、パラメータ調整やモデルアーキテクチャの構成に集中できそうです!
今回はWatson Studioを使って、手書き文字データセットであるMNISTをクラス分類する実験を行いたいと思います!
Usage
それでは、Watson Studioを使ってみましょう!
使用にはIBM Cloud アカウントが必要なので、アカウントがない人は先に取得を行いましょう。
↓の記事に従うと、ライト・アカウントを取得することができます。
IBM Cloud Watson Studioを導入する
IBM Cloudライト・アカウントを手に入れたら、ダッシュボード画面に入ります。
ダッシュボード画面に入ったら、画面右上の「リソースの作成」ボタンをクリック。
するとサービス一覧が掲載されたカタログが展開されるので、スクロールして"Watson"の欄を探し、右下の「Watson Studio」をクリックします。
Watson Studioサービスの詳細画面に遷移します。 内容を確認したら「作成」をクリックします。
Watson Studioサービスが作成されました!
「Get Started」を押し、サービスを開始しましょう!
ちなみにこちらの WML(Watson Machine Learning)サービスインスタンスも作成してください!
続き
参考
【IBM Cloud】IBM Cloud ライト・アカウントを取得する
IBM Cloudとは
IBM Cloudとは、IBMが提供するビジネス用クラウドソーシングサービスです。
IaasからSaaSに渡るビジネス向けのサービスを多く取り揃えているのが特徴です。そのためAWSやAzuleのような個人デベロッパーやスタートアップによく使われるクラウドとは対象的に、企業におけるビジネス活用が目立つクラウドです。
AIサービスで有名なWatsonも、IBM Cloudのサービスとして組み込まれています。
今回はWatsonのようなサービスを個人でも利用できるようにするため、IBM Cloudライト・アカウント登録のフローを紹介します。
Usage
IBM アカウントの作成
IBM Cloud用のアカウントを作成するためにはIBM アカウントが必要なので、先にこちらから取得を行います。
IBM Cloudのページにアクセスし、画面右上の人物アイコンをクリックしてプルダウンを表示、その後「サインイン」ボタンを押します。
するとサインイン画面に遷移しますが、アカウントがないので「IBMidを作成します」をクリック。
すると名前等を入力する欄があるので、それぞれに記入し「次へ」をクリック。
アカウントプライバシーについて同意を求められるので、確認しつつ「Proceed」をクリック。
これでIBM アカウント自体の登録は完了です(メールも届いたと思います)。
また登録後、人物アイコンのプルダウンがログイン状態になっていることも確認できます。
IBM Cloud ライト・アカウントの作成
次にIBM Cloudのライト・アカウント(無料)の作成を行います。
最初に、画面右上の「マーケットプレイス」をクリック。
IBM Cloudの商品ページに遷移するので「無料評価版を始める」をクリックします。
遷移先のページでライト・アカウントの案内があるので、「ライト・アカウントを今すぐ登録」をクリック。
ライト・アカウント登録フォームが表示されるので、先程IBMアカウントに登録したメールアドレスをクリック。
すると登録メールアドレスに確認用メールが届くので、メール内の確認ボタンを押します。
確認後遷移した画面にログインボタンがあるので押し、ログインが成功すれば登録完了です。
参考
【React Native】Native Base でiOS/AndroidのUIを構築する
Native Base
NativeBaseはReact Nativeで使うことのできるプラットフォームUIコンポーネントです。 iOS/Androidそれぞれに適切なUIを提供します。
例えば、iOS用のヘッダーには下図のような平坦なデザインが多いのですが、Androidではマテリアルデザインを踏襲したヘッダーが主流です。
Native Baseではこのような差異を吸収した共通のUIコンポーネントを提供してくれます。
それでは、早速使ってみましょう!
Usage
何はともあれ、インストールします。
最初は、create-react-native-app
を使ってReact Nativeのプロジェクトを作成しましょう。
$ create-react-native-app native-base-app
create-react-native-app
をまだインストールしていない方は下記記事を参考にしてください。
次に、作成したプロジェクトにnative-base
を入れていきます。
$ npm install --save native-base
これで準備完了です!
Source
iOSとAndroid、それぞれの端末でUI/UXが異なるのを確認すべく、
- ヘッダー
- フッダー
- ボタン
- DatePicker
- 入力フォーム
を試しに配置してみました。
import React, { Component } from 'react'; import { StyleSheet } from 'react-native'; import { Container, Header, Left, Body, Right, Button, Icon, Title, Text, Footer, Content, Card, CardItem, DatePicker, Form, Item ,Label, Input} from 'native-base'; export default class GeneralExample extends Component { render() { return ( <Container style={styles.container}> <Header style={styles.header}> <Left> <Button transparent> <Icon name='arrow-back' /> <Text>Back</Text> </Button> </Left> <Title>Header</Title> <Right> <Button transparent> <Icon name='menu' /> </Button> </Right> </Header> <Content style={styles.content}> <Button > <Text> Button </Text> </Button> <Card> <CardItem> <Body> <Text> Card </Text> </Body> </CardItem> </Card> <DatePicker defaultDate={new Date(2018, 4, 4)} minimumDate={new Date(2018, 1, 1)} maximumDate={new Date(2018, 12, 31)} locale={"en"} timeZoneOffsetInMinutes={undefined} modalTransparent={false} animationType={"fade"} androidMode={"default"} placeHolderText="Select date" /> <Form> <Item fixedLabel> <Label>Input..</Label> <Input /> </Item> </Form> </Content> <Footer style={styles.footer}> <Text>Footer</Text> </Footer> </Container> ); } } const styles = StyleSheet.create({ container: { width: "100%", height: "100%", }, content: { padding: 30, }, header: { alignItems: "center", justifyContent: "center" }, footer: { alignItems: "center", justifyContent: "center" } });
Demo
iPhone
Android
iOSはデフォルトUIのデザイン、Androidはマテリアルデザインで表示されているのがわかりますね!
今まではReact Nativeで「iOSとAndroid、どちらでも"動く"」アプリは作れましたが、
Native Baseをつかうことで一つのアプリで別々のUIを提供できるようになりました!
(Native Base の提供する範囲内に限っての話ですが。。。)
これでクロスプラットフォームアプリ制作がはかどります!
参考
【Yarn】Yarnをインストールする
Yarnとは
YarnはFacebookが開発したパッケージマネージャです。Yarnは、Nodel.js上で用いられるパッケージマネージャであるnpmを代替します。
前回の記事でも触れましたが、npmは昨今のWeb開発では頻繁に用いられています。一方で、npmはパッケージインストール時のエラーに悩まさえることが少なくありません。
またFacebook曰く、npm自体、現行の企業のアプリ開発業務の規模に耐えられなくなりつつあるようです。
そこでFacebookは新しいパッケージマネージャとしてのYarnを開発しました。Yarnはnpmにない新しい機能・規模感・安定性を提供するパッケージマネージャとして、少しずつ広まりつつあるようです。
今回はYarnを実際にインストールし、その機能を見ていきます。
Yarnの特徴
オフラインインストール
パッケージがダウンロード済みの場合、何度でもインストールできます。ローカルにパッケージがキャッシュされます。
npmと環境を共存できる
npmと同じnode_modules内でパッケージを管理でき、package.jsonで依存関係の管理も行うので、npmからの移行が簡単です。
高速
前述のオフラインインストールに加え、Yarnはインストール時のリクエストを効率的にキューイングすることでネットワークパフォーマンスの向上も達成しているようです。
Usage
Yarnのインストール
環境はMac OS X High Sierra 10.13.4 です。
ドキュメントにもある通り、brew
またはMacProts
でインストールできます。
# brew
$ brew install yarn
# MacPorts
$ sudo port install yarn
YarnをNodeなしでインストールできます。YarnはデフォルトでNodeとともにインストールされます。
$ brew install yarn --without-node
これでOKです!
Yarnを使ってプロジェクトを作成
結論を言ってしまうと、npm
と使い方はほぼ全て同じです!
プロジェクト初期化はyarn
コマンドで実行できます。yarn init
でも可能です。
$ yarn yarn install v1.7.0 info No lockfile found. [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [3/4] 🔗 Linking dependencies... [4/4] 📃 Building fresh packages... success Saved lockfile. ✨ Done in 0.08s.
yarn add
で依存関係を追加できます。
$ yarn add [package] --dev $ yarn add [package] --peer $ yarn add [package] --optional
追加した依存関係をインストールしましょう!
$ yarn install
yarn install [package]
で依存関係の追加を行わずにパッケージのインストールができます!
$ yarn install [package]
依存関係を削除するには、yarn remove [package]
を使います。
$ yarn remove [package]
インストールしたパケージのまたアンインストールは下記で可能です。
$ yarn uninstall [package]
npmと全く一緒で乗り換え楽勝でした。
参考
【Java】JAX-WSでJSON Body Parameterをサーバ側でMapとして受け取る
JAX-WSとは
JAX-WSはJavaのサーバサイドフレームワークであり、JavaクラスとAPIの構造をマッピングする機能を持ちます。
クラスやメソッドに対してアノテーションを付加することで、簡単にマッピングすることができます。
例えば、APIサーバがapi/hoge/get
GETメソッドを提供したい場合、下記のように記述することができます。
import java.util.List; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import hoge.fuga.Request; import hoge.fuga.Response; @Path("hoge") @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public class APIResource { @POST @Path("post") public Response post(Request request) { ... return result; } }
クラス、及びメソッドがAPIの階層構造にマッピングされ、整然と記述することができます。
ボディパラメータ(application/json)を受け取る
以前より、application/json
形式のリクエストボディをサーバが受け取れるようにするため、リクエストパラメータ受け取り用クラスをAPIごとに定義していました。
例えば、上記コードのpost
メソッドの引数となっているRequest
型変数には、JSON形式のリクエストボディをJavaオブジェクトに変換した結果が格納されています。この変数の型となっているRequestクラスは、上記post
メソッドのリクエストボディを受け取るためだけに作られた専用のクラスになります。
Request.java
public class Request { private int id; private int label; private int page; }
このやり方で進めてしまうと、JSONボディパラメータを受け取るAPIメソッド一つ作るたびに、専用のパラメータ受け取り用クラスを作成しなければなりません。
APIごとに類似したレスポンスを返すのであれば共通化・一般化したクラスを定義して使い回せばよいのですが、新たに受け取らなければ行けないパラメータが増えた場合、新たにクラスを定義する必要が出てきます。
対応策
Mapオブジェクトで受け取れました。。。
どうやらJAX-WSでは、ユーザ定義クラスに対するマッピングだけでなく、Mapクラスに対するオブジェクトマッピングも行ってくれるみたいです。
import java.util.List; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import hoge.fuga.Response; @Path("hoge") @Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8") public class APIResource { @POST @Path("post") public Response post(Map<String, Object> request) { // Map内のパラメータを解体 String name = (String)request.get("name"); String label = (String)request.get("label"); int page = (Integer)request.get("name"); .... return result; } }
ただし、MapのValue型が殆どの場合Objectになってしまうので、型変換が暗黙的になってしまうというデメリットはありますが。。。 ココらへんは、仕様書にきちんと記述するなり、コメントで記述するなりしっかりしておく必要があると思います。
JAX-WSの仕様を把握しきれていなかったというオチでした。。。