- 投稿日:2019-04-11T22:25:27+09:00
Gsonはデフォルトではnullなフィールドをシリアライズしない
調べたのでメモ。
題名の通り、GsonはオブジェクトをJSONに変換する際、デフォルトではnullのフィールドをシリアライズしない。
nullのフィールドをシリアライズしたい場合、GsonBuilder#serializeNulls()を使用する。サンプルコード
MainActivity.ktclass MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val data = Data("nonnull", "nullable", null) val gson1 = Gson() val json1 = gson1.toJson(data) Log.d(TAG, json1) // => {"nonNullProp":"nonnull","nullableProp1":"nullable"} val gson2 = GsonBuilder().serializeNulls().create() val json2 = gson2.toJson(data) Log.d(TAG, json2) // => {"nonNullProp":"nonnull","nullableProp1":"nullable","nullableProp2":null} } data class Data( val nonNullProp: String, val nullableProp1: String?, val nullableProp2: String? ) companion object { private const val TAG = "MainActivity" } }参考URL
- 投稿日:2019-04-11T21:06:12+09:00
Java(OkHttp)でHTTP通信するときのメモ
目的
・Javaで実装された処理から、外部APIとHTTPでやり取りしたい
・bodyにXMLを詰めたい
・実装がなるべく簡単なものがいいJavaのHTTPクライアントって・・・
デファクトスタンダード的なものはないのでしょうか・・・?
ネット上の記事を参考に、
OkHttp(https://square.github.io/okhttp/)
というライブラリを使ってみました。<!-- http client --> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>3.7.0</version> </dependency>実装
例ではXMLをbodyに詰めてAPIをコール、
APIから返却されるXMLのStringを受け取ってreturnするイメージです。
basic認証もしています。public String callApi(String xml) throws IOException { return new OkHttpClient().newCall( new Request.Builder() .url("【APIのURL】") // basic authentication .header("Authorization", Credentials.basic( "【basic認証のuser】", "【basic認証のpassword】")) .post(RequestBody.create(MediaType.parse("text/xml"), xml)) .build() ).execute() .body() .string(); }参考
JavaのHTTPクライアントはどれがいいのか?
https://qiita.com/alt_yamamoto/items/0d72276c80589493ceb4
- 投稿日:2019-04-11T20:55:14+09:00
【初心者向け】javaのコンストラクタについてまとめ
コンストラクタとは
コンストラクタとは、newで生み出されたインスタンスに自動で情報(フィールド)を渡してくれるものです。
public class Hero { String name; int hp; }このHeroクラスをインスタンス化すると、値の入っていないHero(nameがnullでhpが0)が生成されてしまいますが
public class Hero { String name; int hp; //コンストラクタ Hero(){ this.name = "名前"; this.hp = 100; } }こうすることによって値をフィールドに代入できます。
でもこれだと同じ名前と同じHPのHeroしか作ることができません。
魔法使いHP50とか、妖精HP70とかが作れないのです。
なので、自由にキャラクターを作れるようにするためにこのようにします。public class Hero { String name; int hp; //コンストラクタ Hero(String name , int hp){ this.name = name; this.hp = hp; } }これは何をしているかというと、Hero(String name , int hp)でnameとhpを受け取って、フィールドに代入しているのです。
どこから受け取っているのかというと、mainメソッドから受け取っています。public static void main(String[] args) { Hero h = new Hero("勇者" , 100); }Heroクラスで引数を2つ受け取るコンストラクタを設定したので、呼び出すときも引数を2つ設定して呼び出します。
これが引数1つだとエラーになります。結果はこうなります。
ちゃんと値が渡されているか確認しましょう。public static void main(String[] args) { Hero h = new Hero("勇者" , 100); System.out.println("名前は" + h.name + "です。"); System.out.println("HPは" + h.hp + "です。"); }結果は
名前は勇者です。 HPは100です。ちゃんと渡すことができました。
でもこれだと、名前だけを渡したい場合エラーになってしまいます。
public class Main { public static void main(String[] args) { Hero h = new Hero("勇者");//エラーになる } }こんな時はHeroメソッドにコンストラクタを追加します。
public class Hero { String name; int hp; //コンストラクタ Hero(String name , int hp){ //ひとつ目のコンストラクタ this.name = name; this.hp = hp; } Hero(String name){ //ふたつ目のコンストラクタ this.name = name; this.hp = 50; } }コンストラクタは、名前が同じでも、引数の数が違えば複数設定できるのです。
これをオーバーロードと言います。
もしmainメソッドでnewして呼び出すとき、引数にnameとhpがあったらひとつ目のコンストラクタが呼び出されます。
引数にnameだけがあったらふたつ目のコンストラクタが呼び出されます。
このままでもエラーにはなりませんが、渡されるフィールドが増えてきたりすると、修正や可読性が悪くなってしまいます。
なのでthis()を使います。
これを使うと、同じメソッドにあるコンストラクタを呼び出すことができます。public class Hero { String name; int hp; //コンストラクタ Hero(String name , int hp){ //ひとつ目のコンストラクタ this.name = name; this.hp = hp; } Hero(String name){ //ふたつ目のコンストラクタ this(name , 50); } }こうなります。
ふたつ目のコンストラクタの中でひとつ目のコンストラクタを呼び出しているのです。
ひとつ目のコンストラクタは引数が2つあるのでthis()の()の中の引数は2つです。
nameはmainメソッドから渡されたものが入り、hpは渡されないので任意のhpを入れます。ここでは50としています。
これで実行するとpublic class Main { public static void main(String[] args) { Hero h = new Hero("勇者"); System.out.println("名前は" + h.name + "です。"); System.out.println("HPは" + h.hp + "です。"); } }結果
名前は勇者です。 HPは50です。ちゃんと50が渡されてますね。
this()は結構ややこしいですね。ひとつずつ書いたほうが分かりやすいよ!と思ってる方もいると思いますが、そうすると後からフィールドを変更しなければならなくなった時大変になります。public class Hero { String name; int hp; //コンストラクタ Hero(String name , int hp){ //ひとつ目のコンストラクタ this.name = name; this.hp = hp; } Hero(String name){ //ふたつ目のコンストラクタ this.name = name; this.hp = 50; } }こんなふうに書いていて、あとからフィールドを変更しなければならなくなると
public class Hero { String name1; //ここをname1に変更しなければならない。 int hp; //コンストラクタ Hero(String name , int hp){ //ひとつ目のコンストラクタ this.name = name; //エラーになる。 this.hp = hp; } Hero(String name){ //ふたつ目のコンストラクタ this.name = name; //エラーになる。 this.hp = 50; } }この場合2か所直さないといけなくなります。
コンストラクタが2つならまだいいですが、これが増えてくると作業が大変になります。
なん十か所も直していたら一か所くらいミスが出てもおかしくありません。自分がつまずいた部分だったのでまとめてみました。
間違いがありましたら指摘をお願いします。nkojimaさんご指摘ありがとうございます。
記事の一部を削除しました。
確かに読み返してみたら可読性とは違いましたね。
送っていただいた記事も参考にさせていただきます。
- 投稿日:2019-04-11T19:28:05+09:00
クラスタリング環境で発生した検証値エラー
クラスタリング環境で検証エラーが発生する
開発環境
- JavaSE8
- JavaEE7
- Payara5
- JSF2.2
- Eclipse Oxygen4.7.2
事象
パラメータによって選択肢が変化するラジオボタンがある。
任意の項目を選択しポストすると「j_idt39: 検証エラー: 値が有効ではありません 」が発生。
ローカルやシングルインスタンス環境だと発生しない。原因
プロジェクトの要件でスティッキーセッションを使用せず、通信の都度ランダムにサーバに割り振られていた。
そのためセッション内にBeanが複製されまくり、その中には初期値のない(null)のラジオボタンの選択肢リストが存在した。
ポストしたときに運悪くリストがnullのBeanに当たった時に検証エラーが発生していた。問題のソース
XHTML
<form jsf:id="form" jsf:prependId="false"> <h:selectOneRadio name="choiceName" value="#{choiceBean.choiceName}" styleClass="radio_list"> <f:selectItems value="#{choiceBean.choiceList}" var="prize" itemLabel="#{item.labelName}" itemValue="#{item}" /> </h:selectOneRadio> <button jsf:action="#{pageControlBean.toConfirm()}" class="btn_orange"> 次へ </button> <span jsfc="h:messages" class="form_error_text" /> </form>Bean
@Named @SessionScoped public class ChoiceBean implements Serializable { private static final long serialVersionUID = 1L; @NotNull @Getter @Setter private ChoiceType choiceName; @Getter @Setter private List<ChoiceType> choiceList; }Enum
public enum ChoiceType { TYPE1("タイプ1", 0), TYPE2("タイプ2", 1), TYPE3("タイプ3", 2); @Getter private final String labelName; @Getter private final int index; private ChoiceType(String labelName, int index) { this.labelName = labelName; this.index = index; } }解決
コンストラクタで初期値を設定してやる。
Bean
@Named @SessionScoped public class ChoiceBean implements Serializable { private static final long serialVersionUID = 1L; @NotNull @Getter @Setter private PrizeType choiceName; @Getter @Setter private List<ChoiceType> choiceList; /** * Constructor * NotNull変数の初期値設定 */ public ChoiceBean() { choiceList = new ArrayList<>(); choiceList.add(ChoiceType.TYPE1); choiceList.add(ChoiceType.TYPE2); choiceList.add(ChoiceType.TYPE3); } }調査のコツ
最終的にセッションの中身が見えるIDE(有料版Intellijとか)で調査してbeanの複製が分かった。
JavaEEだとNetBeansでも見れるそうですね。
- 投稿日:2019-04-11T18:11:17+09:00
【MySQL+Java】採番プロシージャ
はじめに
MySQL + Java な環境で採番の仕組みを用意する必要があったので、
下記の記事を参考に作ってみました。MySQL で採番テーブル
MySQL で シーケンス 機能実現
LAST_INSERT_IDを使って採番テーブルを扱うOracleのシーケンスがMySQLにもあればなー。
環境
MySQL 5.7
Java 8やったこと
- 採番用のテーブルを用意する。×2
- 採番プロシージャを用意する。×2
- Javaで検証する。
採番用テーブル
テーブル1CREATE TABLE `seq1` ( `prefix` varchar(8) NOT NULL, `id` int(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8テーブル2CREATE TABLE `seq2` ( `prefix` varchar(8) NOT NULL, `id` int(11) NOT NULL DEFAULT '0' ) ENGINE=InnoDB DEFAULT CHARSET=utf8それぞれ1レコードずつ登録しておく。
採番プロシージャ
プロシージャ1CREATE DEFINER=`trial`@`localhost` PROCEDURE `nextval_seq1`(out seqnum varchar(12)) BEGIN START TRANSACTION; update seq1 set id = LAST_INSERT_ID(id + 1); select CONCAT(prefix, LPAD(LAST_INSERT_ID(id), 10, '0')) into seqnum from seq1; COMMIT; ENDプロシージャ2CREATE DEFINER=`trial`@`localhost` PROCEDURE `nextval_seq2`(out seqnum varchar(12)) BEGIN START TRANSACTION; update seq2 set id = LAST_INSERT_ID(id + 1); select CONCAT(prefix, LPAD(LAST_INSERT_ID(id), 10, '0')) into seqnum from seq2; COMMIT; END検証Javaコード
以下の観点で検証コードを実装しました。
- マルチスレッドでも問題ない事
- プロシージャを利用してもコネクションが死なない事
- 複数の採番用テーブル、採番プロシージャでちゃんと?採番される事
private void execute(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(100); try { List<Callable<Boolean>> taskList = new ArrayList<>(); for (int i = 0; i < 50; i++) { taskList.add(() -> callProcedureAndUpdatePrefix1()); taskList.add(() -> callProcedureAndUpdatePrefix2()); } pool.invokeAll(taskList); } catch (InterruptedException e) { e.printStackTrace(); } finally { pool.shutdown(); } } private boolean callProcedureAndUpdatePrefix1() { try (Connection conn = ConnectionManager.getConnection()) { conn.setAutoCommit(false); callProcedure1(conn); updateSeq1(conn); conn.commit(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } private boolean callProcedureAndUpdatePrefix2() { try (Connection conn = ConnectionManager.getConnection()) { conn.setAutoCommit(false); callProcedure2(conn); updateSeq2(conn); conn.commit(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } private void callProcedure1(Connection con) throws SQLException { try (CallableStatement cs = con.prepareCall("call nextval_seq1(?)")) { cs.executeQuery(); System.out.println(cs.getString(1)); } } private void callProcedure2(Connection con) throws SQLException { try (CallableStatement cs = con.prepareCall("call nextval_seq2(?)")) { cs.executeQuery(); System.out.println(cs.getString(1)); } } private void updateSeq1(Connection con) throws SQLException { boolean b = (new Random()).nextInt(99) % 2 == 0 ? true : false; String sql = "update seq1 set prefix = " + (b ? "'XA'" : "'XB'"); try (Statement st = con.createStatement()) { st.execute(sql); } } private void updateSeq2(Connection con) throws SQLException { boolean b = (new Random()).nextInt(99) % 2 == 0 ? true : false; String sql = "update seq2 set prefix = " + (b ? "'YA'" : "'YB'"); try (Statement st = con.createStatement()) { st.execute(sql); } }検証結果
XA0000000001 YA0000000006 YA0000000004 XA0000000006 XA0000000005 XA0000000002 XA0000000004 XA0000000007 YA0000000003 YA0000000005 XA0000000019 XA0000000018 YA0000000012 XA0000000013 YA0000000008 YA0000000011 YA0000000007 YA0000000015 YA0000000013 XA0000000003 XA0000000012 XA0000000016 XA0000000015 YA0000000014 XA0000000014 XA0000000017 YA0000000009 YA0000000010 YB0000000022 XB0000000023 XB0000000022 YB0000000021 YB0000000019 YA0000000018 YB0000000020 YA0000000016 YB0000000023 XA0000000020 YA0000000017 XA0000000021 XA0000000025 XB0000000026 XA0000000024 XA0000000011 XA0000000008 YA0000000001 XA0000000010 XA0000000009 YB0000000029 YB0000000026 YB0000000028 YB0000000030 YA0000000002 YB0000000024 YB0000000025 YB0000000027 YA0000000034 YA0000000037 YA0000000031 YA0000000032 YA0000000033 YA0000000035 YA0000000038 YA0000000039 YA0000000036 YA0000000043 XA0000000027 XA0000000029 XA0000000035 YA0000000041 XA0000000034 YA0000000042 YA0000000040 XA0000000030 XA0000000028 XA0000000036 XA0000000033 XA0000000032 XA0000000031 XB0000000045 XB0000000046 XB0000000041 XB0000000047 XB0000000048 XB0000000038 YB0000000050 XB0000000037 XB0000000050 YA0000000045 YB0000000047 YA0000000044 XB0000000042 XB0000000043 XB0000000044 XB0000000049 XB0000000039 XB0000000040 YB0000000048 YB0000000046 YB0000000049以上
- 投稿日:2019-04-11T14:27:41+09:00
android PreferenceFragmentCompatのEditTextPreferenceを改行させないようにする方法
なかなか調べても出てこなかったので、
EditTextPreferenceで改行ができてしまい、すこし操作性が悪かったので
改行をできなくするようにする方法です。というよりはDialogで呼ばれるEditTextのレイアウトを指定する方法です。
preferences.xml
<EditTextPreference android:dialogLayout="@xml/prefernce_custom_edittext" android:key="userName" android:title="ユーザー名" />android:dialogLayoutを設定します。
prefernce_custom_edittext.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@android:id/edit" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingLeft="18dp" android:paddingRight="18dp" android:inputType="text|textNoSuggestions" /> </LinearLayout>これで普段扱っているように自由にカスタマイズできます。
改行できない!よかったよかった!
- 投稿日:2019-04-11T13:23:36+09:00
はじめました(•ө•)
講義用です
はじめろって言われたんではじめましたよろしくおねがいします
Qiitaタグ必須なのめんどいですね
- 投稿日:2019-04-11T12:19:30+09:00
JMeterのインストール方法 for Mac
MacでJMeterのインストールとアップデート - ブロックチェーンエンジニアとして生きる
記事の通り、Homebrewでインストールするのが簡単で良い。
# インストール $ brew install jmeter # 実行 $ jmeterJDKをまだインストールしていない場合
Java8じゃないと動かないという記事(MacにJMeterを入れる - Qiita)があるがJava12で動いたので最新Javaで問題なさそう(2019/04/11現在)。
homebrew-cask経由でインストール
複数バージョンのJavaを設定ファイルの書き換えで切り替えできるのでおすすめ。
MacのBrewで複数バージョンのJavaを利用する - Qiita
homebrew-caskって何??? - Qiitaインストーラーでインストール
- 投稿日:2019-04-11T11:38:34+09:00
switch文のフォールスルー (fall through)を活用してenumのマッピングをシンプルに書く
ある処理結果(5択)のenumをバッチ結果のenum(2択)にマッピングしたいとき
switch (result) { case WAITING_RETRY: return BatchResult.SUCCESS; case SUCCESS: return BatchResult.SUCCESS; case SUCCESS_WITH_ZERO: return BatchResult.SUCCESS; case REQUESTING: return BatchResult.FAILURE; case PROCESSING: return BatchResult.FAILURE; case FAILURE: return BatchResult.FAILURE; default: return BatchResult.FAILURE; }switch文を利用して上のように書ける。
しかしなんだか冗長。enum定義が増えたとき、見通しが悪くなる。switch (result) { case WAITING_RETRY: case SUCCESS: case SUCCESS_WITH_ZERO: return BatchResult.SUCCESS; default: return BatchResult.FAILURE; }上記のように「2択の分岐である」ことを明示すれば、
resultのenum定義が増えて分岐漏れしても比較的安全。
さらに、増えた定義がFAILUREにあたるものだった場合、ここのコードは変更しなくて済む。フォールスルーで危険なのは、見通しの悪さから分岐漏れが生じて予期せぬ挙動になること。
「書きやすいし見やすいなら使う」。(もちろん、現場のコーディング規約は守る)
