JacksonでXMLをJavaオブジェクトに変換する

はじめに

エキサイト株式会社 21卒 バックエンドエンジニアの山縣です。 既存サービスのリビルドするにあたり、外部APIを呼び出してXMLを取得してJavaオブジェトに変換する処理を書きました。 Jacksonを使用したXMLJavaオブジェクト変換についての記事は少なかったため本記事にて紹介します。

導入

本記事で使用するサンプルのXMLとそれに対応するJavaクラスです。

サンプルで使用したXML

<Response>
    <ItemList>
        <Item id="a123" name="orange"/>
        <Item id="b234" name="lemon"/>
        <Item id="c345" name="apple"/>
    </ItemList>
    
    <ResultList>
        <Result num="1">オレンジ</Result>
        <Result num="2">レモン</Result>
        <Result num="3">リンゴ</Result>
    </ResultList>
</Response>

XMLに対応するJavaのクラス

package com.example.demo.model;

import java.util.List;

import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText;
import lombok.Data;

@Data
@JacksonXmlRootElement(localName = "Response")
public class Basket {
    @JacksonXmlProperty(localName = "ItemList")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Item> items;

    @JacksonXmlProperty(localName = "ResultList")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List<Result> results;

    @Data
    public static class Item {
        @JacksonXmlProperty(isAttribute = true)
        private String id;
        @JacksonXmlProperty(isAttribute = true)
        private String name;
    }

    @Data
    public static class Result {
        @JacksonXmlProperty(isAttribute = true)
        private Integer num;
        @JacksonXmlText
        private String text;
    }
}

XMLのルートの下からマッピングする

XMLのルートの下からマッピングするには、@JacksonXmlRootElementを付与する必要があります。

@JacksonXmlRootElement(localName = "Response")
public class Basket { ... }

XMLのリストをマッピングする

XMLのリストをマッピングするには、下記2つのアノテーションが必要です。

@JacksonXmlProperty(localName = "ResultList")
@JacksonXmlElementWrapper(useWrapping = false)
private List<Result> results;

@JacksonXmlElementWrapperは、useWrappingの他にlocalNameも設定できます。 このとき、@JacksonXmlPropertyを消して、@JacksonXmlElementWrapper(useWrapping = false, localName = "ResultList") と書くと動作するように見えますが、UnrecognizedPropertyExceptionとなってしまいマッピングすることができませんでした。 そのため、上記のように2つのアノテーションを記述しなくてはなりません。

RestTemplateでXMLJavaオブジェクトの変換をする

最後に、下記のように記述することで、外部APIから取得したXMLJavaオブジェクトの変換を実現することができます。

final ResponseEntity<Basket> response = restTemplate
    .exchange(
        "http://example.com",
        HttpMethod.GET,
        httpEntity,
        Basket.class
);

おわりに

Jacksonを使用したXMLJavaオブジェクト変換についてまとめました。 JSONJavaオブジェクトの記事は数多くありますが、XMLJavaオブジェクトの記事はあまり見当たらなかったので、 XMLの変換で困っている人の助けになれば幸いです!

エキサイトは「DroidKaigi2021」に協賛しました!

エキサイトは「DroidKaigi2021」にSUPPORTERSとして協賛しました。今回は惜しくも弊社から登壇者はいませんでしたが、グループ会社であるRadiotalkから牧山さんが登壇しました。 来年は弊社から登壇者が出るように技術力を切磋琢磨し、向上させていきたいです。

登壇内容

登壇者:牧山

タイトル:Androidエンジニアが1人という不安と向き合う

内容:Androidエンジニア不足が叫ばれる昨今、1つのAndroidアプリに対して1人のエンジニアという状況が増えてきているように感じています。このような状況下では、スキル面・キャリア面での不安を持つ方も多いのではないでしょうか。私もそうでした。私のAndroidエンジニアキャリアもほとんどがAndroidエンジニアが1人での開発を経験しています。  本セッションでは、私の経験を踏まえ、どのようにAndroidエンジニアとしての技術を学び、どのように不安と向き合っているのかを紹介します。

  • Androidエンジニアとしての技術の学び方

 ・キャッチアップの方法

 ・ 優れたソースコードを読む

  • 不安と向き合うために

 ・スコープを広げてソフトウェア開発を学ぶ

 ・サービスへの理解を深めソフトウェア開発に還元する

 ・サービスの未来を見据えた設計/開発

 ・エンジニアリングでサービスを前にすすめる

アーカイブURL:https://www.youtube.com/watch?v=5M0xJLdAcAE

DroidKaigi2021

公式サイト:https://droidkaigi.jp/2021/

公式チャンネル:https://www.youtube.com/c/DroidKaigi

Javaでリトライをする方法

こんにちは。 エキサイト株式会社の三浦です。

アプリケーションコードを書く上で、特定の処理をリトライさせたい場合があります。 今回は、Java / Spring Bootでリトライする方法について説明していきます。

リトライ

アプリケーションコードを書く上で、どうしても失敗する可能性が消しきれない処理というものが存在します。 代表的なものとして「インターネットを介したAPIリクエスト」があり、以下のようにリクエスト元である我々ではどうしようもないエラーが発生し得ます。

  • リクエスト先APIに何かしら不具合が発生した
  • 通信をするためのネットワーク周りで何かしら障害が発生した

特にインターネットはベストエフォートなので、そもそも「100%常にリクエストが成功する」ことは保証していません。 そのため、上記のような場合でも我々が管理するアプリケーションは正しく動作することを考える必要があります。

これを解決する方法の一つが「リトライ」です。 すなわち、1回失敗しても「失敗した」判定はせず、規定回数に達するか成功するまで何度も処理を実行する、というものです。

Java / Spring Bootでのリトライ方法

このリトライ処理は、Java / Spring Boot環境では spring-retry というライブラリを使うことで簡単に実装できます。

build.gradle

必要なライブラリを設定します。 spring-retry だけでなく、 spring-boot-starter-aop も必要なので注意してください。

// バージョンは適宜変更してください
implementation 'org.springframework.retry:spring-retry:1.3.1'

// 設定にはこちらも必要になります
implementation 'org.springframework.boot:spring-boot-starter-aop'

設定ファイル

spring-retry の設定ファイルです。 ここで spring-retry を使えるようにします。

@Configuration
@EnableRetry
public class RetryConfig {}

リトライしたいメソッド

準備が整ったら、後はリトライしたいメソッドに @Retryable というアノテーションをつければリトライするようになります。 この時、 value に投げられたらリトライする例外クラスを、 backoff にリトライする際の挙動を書きます。

今回のサンプルコードでは、

  • SampleExceptionが投げられたらリトライする
  • リトライする際は、500ms空けて実行する
  • それ以外はデフォルトの動作

となっていますが、設定次第で挙動をカスタムできます。

@Retryable(value = {SampleException.class}, backoff = @Backoff(delay = 500))
public String sample() {
    return "Sample";
}

最後に

リトライは、アプリケーションが大きくなっていくと必要になる場面が増えてきます。 もちろん何でもかんでもリトライすればいいわけではないですが、適切に使用することでアプリケーションの信頼性は向上するはずです。

ぜひ使ってみてください。

KUROTEN.の技術スタック

エキサイト株式会社でKUROTEN.の開発している森脇です。

今回はKUROTEN.の技術スタックについてご紹介いたします。

KUROTEN.とは

KUROTEN.(クロテン)は経営管理業務のDXを行い、スピード経営を実現するプラットフォームです。必要なデータを一元管理、経営判断が可能な管理会計のあるべき姿を構築し、経営の意思決定をサポートするSaaSのサービスです。

lp.kuroten.jp

KUROTEN.開発の歴史

KUROTEN.は 2020年3月くらいから開発を開始し2021年6月にβ版のリリースをいたしました、その間いろいろ仕様も変わりシステム構成も変わり、なかなかチャレンジングな開発を行ってきました。

ようやくリリースし構成も決まってきたので、ご紹介したいと思います。

サーバーサイドの技術スタック

項目 ソリューション
言語 Go
フレームワーク Iris
ORマッパー gorp
テストフレームワーク testing
データベース Aurora
ドキュメント生成 swaggo
アーキテクチャ クリーンアーキテクチャ

Go

エキサイトではあまり使っていませんでしたが、サービスの特性上、静的型付け言語がよかったので選定しています、 エンジニア的にも業務で使ってみたかったところも大きいです。

Iris

サーバーサイドは紆余曲折あって、最終的にIrisを選定して使っています。

最初はLambdaで動かしていました。エンドポイントは100を超え、メンテナンス性が悪くパフォーマンスもよくなかったので、ECSで動かすことにしました。
ECSで動かすならフレームワークが必要ということで、選んだのがIrisでした、echoやginも候補でしたが、最速ということもありIrisを選んでいます。

ORマッパー

複雑なSQLを書いているため、ORマッパーの恩恵はあまり受けていません。 select文を書いた時に名前でバインドしたかったので、gorpを選んでいます、今はgormでもできるので、そっちが一般的ですね

swaggo

ドキュメントの生成と、postmanに食わせるswagger.jsonを吐き出してくれるとても便利なやつです。
導入前はpostman用のjsonを手動で書き、apiの追加・変更があるたびに修正しないと行けなかったのですごく大変でした

クリーンアーキテクチャ

当初はLambdaで作っていたこともあり、あまりアーキテクチャを意識した作りになっていませんでした。
Irisに移行した時にmvcにしましたが、機能が増えていくことで複雑化し、メンテナンス性や循環参照の問題も出てきたため、クリーンアーキテクチャの導入を行いました、コードもみやすく役割がはっきりと分かれているので、レビューもしやすくなりました、現在はまだ移行中です

フロントエンドの技術スタック

項目 ソリューション
言語 javascript
フレームワーク nuxtjs
デザインフレームワーク vuetify
テストフレームワーク jest

javascript

typescriptにすればよかったんですが、javascriptで書いてます。vue3に上げるタイミングでtypescriptに移行しようと思っています。

jest

当初はavaで行っていましたが、今はjestに変更しています、カバレッジも100を目指して日々テストコードを書いています。

バッチの技術スタック

項目 ソリューション
言語 python
ORマッパー sqlalchemy
テスト pytest

python

特にフレームワークも使わずに好きに書いています、Lambdaで動かすので、関数を呼ぶシンプルなコードになっています

インフラ

主にAWSを使っています、使っているサービスは一般的なものを中心です。

AWS 説明
ECS frontとapiが動いています
RDS Aurora MySQL
S3 一時的なデータ保存場所で使用しています
AppSync 非同期通信を行うために使用しています
Lambda 主にバッチを動かしています
StepFunction LambdaをStep毎に実行するために使用しています
QuickSight サービス分析で使用しています
WAF セキュリティ関連
Codepipline 検証環境や本番へのデプロイで使用しています。
CodeBuild
CodeDeploy
CloudWatch 監視
terraform インフラコードは全てterraformで書いています
cloudformation Lambda関連はsamを使っているので、cloudformationも使っているます

その他

項目 ソリューション
認証 Auth0
spreadjs

最後に

KUROTEN.はいろんな技術を使って構築されています。
今後も新しい技術をどんどん使い、良いサービス提供したいと思います。

SpringBootで画像を受け取りそのまま表示する方法

エキサイト株式会社エンジニアの佐々木です。小ネタですが、画像を受け取ってそのまま表示する方法のメモです。

はじめに

SpringBootで画像を受け取って表示する簡単なサンプルです。フォームでファイルをアップロードし、それをそのまま表示するだけのデモアプリになります。

HTML

テンプレートエンジンでThymeleafを使用します。普通のHTMLとして記述できます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
  <form>
      <input type="file" name="file"/>
      <button type="submit" formenctype="multipart/form-data" formmethod="post" formaction="/upload">MultipartFile送信</button>
  </form>
</body>
</html>

サーバ

サーバの方は、コントローラに実装を書いていきます。今回は、Thymeleafを使用するので、 @Controller を使います。

@Controller
@RequestMapping
@RequiredArgsConstructor
public class RootController {

    @GetMapping
    public String index(){
        return "index";
    }

   @ResponseBody   // テンプレートは使用せずに、メソッドで返却したものBodyとして扱う指定
   @PostMapping(value = "upload" , consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Object upload(@RequestPart("file") MultipartFile filePart) throws IOException {   // ファイルの場合は、 `@RequestPart` を使うことを注意
        File file = File.createTempFile(UUID.randomUUID().toString(), filePart.getOriginalFilename());   // ファイル名を取得し、Fileインスタンスを生成
        filePart.transferTo(file.toPath());
        byte[] bytes = Files.readAllBytes(file.toPath()); //ファイルの読み込み

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.parseMediaType(Files.probeContentType(file.toPath())));  // ファイル名からMimeTypeを取得する
        httpHeaders.setContentLength(bytes.length);

        return new HttpEntity<>(bytes, httpHeaders); //レスポンス
    }

}

ファイルアップロードのパラメータに関しては、 @RequestPart を使用します。フォームで送信されたファイルをFiles.readAllBytes()で読み込みます。あとは、レスポンスに入れるだけなので、HttpEntityにデータを入れれば画像の表示ができます。

まとめ

Javaはファイルの扱いが結構面倒な言語なんで、スクリプト言語に比べると面倒に感じるかもしれません。(byte配列への変換とか)。最近ではFilesクラスPathsクラスが便利になってきているので、それほど辛くはないと思います。(以前はxxxxReaderBufferとか色々あって辛かった)

最後に

エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。

カジュアル面談はこちらになります! meety.net

募集職種一覧はこちらになります!(カジュアルからもOK) www.wantedly.com

JavaのRestTemplateでgzipを受け取る方法

こんにちは。 エキサイト株式会社の三浦です。

APIなどからのレスポンスは、サイズが小さいに越したことはありません。

レスポンスサイズを小さくする方法の1つに、レスポンスをgzipで圧縮するという方法があります。 API側でレスポンスをgzip圧縮して送信し、受け取り側で解凍して使用するというやり方です。

ですが、実はJavaのRestTemplateは、デフォルトではgzip圧縮したレスポンスを使うことができません。

ここでは、RestTemplateを使ってgzip圧縮されたレスポンスを使用できるようにする方法を説明します。

レスポンスのサイズ

APIなどから受け取るレスポンスのサイズは、小さいに越したことはありません。 小さいと、

  • レスポンス全体の転送完了までの速度が上がる
  • 転送量が減るので、転送量ごとに料金がかかる場合、料金を削減することができる

などの利点があります。

転送量を減らすための方法はいくつかありますが、その一つに「データを圧縮してレスポンスを送信する」という方法があります。 例えば、Nginxでも設定によってレスポンスデータをgzip圧縮することができます。

ただし、RestTemplateを使っている場合、問題があります。 実は、デフォルトのRestTemplateではgzip圧縮されたレスポンスをそのまま使用することができないのです。 では、どうすれば良いのでしょうか。

RestTemplateでgzip圧縮されたレスポンスを使用する方法

gzip圧縮されたレスポンスを使用するには、RestTemplateの定義時に ClientHttpRequestFactory というものを設定する必要があります。

通常RestTemplateを定義する際は

var restTemplate = new RestTemplate();

とすると思いますが、これを

// バージョンは適宜変更してください
implementation 'org.apache.httpcomponents:httpclient:4.5.13'
var clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
var restTemplate = new RestTemplate(clientHttpRequestFactory);

のように、 ClientHttpRequestFactory を設定します。 後は、リクエスト時にヘッダーに Accept-Encodinggzipを設定すれば、(API側がgzip圧縮に対応していれば)gzip圧縮されたレスポンスを受け取り、自動で解凍して使ってくれるようになります。

最後に

デフォルトでgzip解凍をしてくれないというのは少し罠みたいなところもあり、詰まってしまった方もいるのではないでしょうか。 この記事が参考になれば幸いです。

口下手デザイナーがLT発表までにした準備

f:id:KAJIJI_Design:20211027121307p:plain

初めまして!
SaaS事業部でデザイナーをしている、21卒のかじもとです!

社内・社外で発表する機会はあるけど「発表なんてやったことない!無理無理!」と遠慮される方が多いと思います。

私もかなりの口下手ですが、学生時代はデザイン系がゆえプレゼンが多く、膝を震わせながら大勢の前で発表してきました。

何度か積み重ねて口下手流のプレゼンを乗り切る対策をつかんできたので、発表の準備やスライド制作のコツをシェアします!
「これまで発表なんてしたことない…」「人前で話すのはプレッシャーだよ!」と悩む人の手助けになれたら嬉しいです。

発表前に準備するもの

私がプレゼン当日までに必ずやっていることがあります。それは、

  • 発表資料を必ず準備する
  • プレゼンの読み上げ原稿を準備する
  • 発表前に自分のプレゼンを聞き直す

この3つです。一つずつ解説していきます。

発表資料を必ず準備する

その場で実物画面を見せたり、過去の資料を再利用する方もいるかもしれませんが、私は毎回テーマに合わせて資料を準備します。

伝えたいことを整理して不要な情報を削ぎ、見合ったグラフィックに置き換えて発表する内容専門のスライドを用意しています。

そうすることで、発表の完成度を高めることにもつながりますし、作っていくうちに言葉が洗練されていくので、自分のためにも・聞き手のためにも分かりやすいスライドになります🙆‍♀️

「そんなこと言われてもうまくまとめられないよ!」という人向けに、近々スライド制作のコツも書くので、ぜひ参考にしてみてください〜!

プレゼンの読み上げ原稿を準備する

スライドを準備をすれば、原稿もほぼほぼできたようなものです。スライドに合わせて言葉で解説する文章を作るので、イメージとしては紙芝居に近いかもしれませんね。一言一句読み上げられるものや、大まかにメモしたものなど、この作り方は個人の好みでいいと思います。

大切なのは伝えたい内容をきちんと伝えることですので、あまり悩みすぎず自分らしい言葉でまとめられれば大丈夫です👌

また、原稿を作ったら文字量を確認してみてください。下に発表時間とおすすめの文字量を記しました。

スライド制作の文字量

  • 3分プレゼン:900文字
  • 5分プレゼン:1500文字
  • 10分プレゼン:3000文字

発表時間が長くなるほど多少のズレは生じますが、適切なトークスピードで話せる文字量は1分あたり300文字です。この制約を設けることで喋りすぎ・喋らなすぎを防げますよ🙌

発表前に自分のプレゼンを聞き直す

これがいちばんハードル高く感じるかもしれません…自分の声なんて聞きたくない、発表まで時間がない…なんて方が多いはず。

ですが、これをやる・やらないで大きく変わります。準備してきた資料や原稿を客観的に見ることで、制作中気づけなかったミスや、わかりにくい表現が見えてきます。

さらに発表時間が決まっている場合は、内容のボリュームや話す速さを確かめるためにもぜひ聞き直してみてください⏰

私もこれまで、「当日大勢の前で失敗するよりも前もって練習して自信をつける方がマシ…」という思いで、夜な夜な録音して聞き返す作業をしてきました…

可能であれば、自分の声+スライドの遷移を同時に見られるように画面収録をしておくとより分かりやすくなります。

 

出来上がったスライドがこちら

slideshareに上がっているスライドに原稿も書いてあるので、気になった方はぜひダウンロードしてご覧ください〜!

終わりに

オンラインで画面越しに人と繋がる機会が多くなり、人前で話すプレッシャーもだいぶ軽減できるとてもいい時期だと思います。

近々、スライド作りのコツについても記事を書くので、ぜひ皆さんもプレゼンにチャレンジしてみてください〜!