情報系学部生日記

備忘録や勉強したことのまとめ

ControllerAdviceとResponseEntityExceptionHandlerを用いた例外ハンドラ

やること

Springで例外ハンドラを用意する方法は複数あるが、今回はResponseEntityExceptionHandlerを用いてアプリケーション内で共通の例外ハンドラを定義する。

ResponseEntityExceptionHandler (Spring Framework 5.0.0.RELEASE API)

環境

  • Spring Boot 1.5.7.RELEASE

方法

投げる例外の基底クラスを作る

Transactionalでロールバックさせるため、RuntimeExceptionを継承した例外クラスを作る。

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;

abstract public class HttpStatusException extends RuntimeException {
    private String message;
    private HttpStatus httpStatus;

    HttpStatusException(HttpStatus httpStatus, String message) {
        this.httpStatus = httpStatus;
        this.message = message;
    }

    public HttpStatus getHttpStatus() {
        return this.httpStatus;
    }

    public String toResponseJson() throws JsonProcessingException {
        return new ObjectMapper().addMixIn(HttpStatusException.class, HttpStatusExceptionMixin.class).writeValueAsString(this);
    }

    @JsonAutoDetect(
        getterVisibility = JsonAutoDetect.Visibility.NONE,
        isGetterVisibility = JsonAutoDetect.Visibility.NONE,
        fieldVisibility = JsonAutoDetect.Visibility.NONE
    )
    abstract class HttpStatusExceptionMixin {
        @JsonProperty String message;
    }
}

例外エラーのフィールドには返すメッセージとHTTPステータスを用意し、返却するJSONを生成するメソッドを実装する。 JSONで返す値はmessageだけで良いので、Mixin用の抽象クラスをインナークラスとして定義しておく。

派生例外クラスを作る

とりあえずBadRequest用のクラスを作る。

import org.springframework.http.HttpStatus;

public class BadRequestException extends HttpStatusException{
    public BadRequestException(String message) {
        super(HttpStatus.BAD_REQUEST, message);
    }
}

ControllerAdviceを用いた例外ハンドラを作る

import com.fasterxml.jackson.core.JsonProcessingException;
import com.example.exceptions.HttpStatusException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

@ControllerAdvice
public class ApiAdviceController extends ResponseEntityExceptionHandler {
    @ExceptionHandler(HttpStatusException.class)
    public ResponseEntity handleHttpStatusException(HttpStatusException exception, WebRequest request) throws JsonProcessingException {
        return handleExceptionInternal(exception, exception.toResponseJson(), new HttpHeaders(), exception.getHttpStatus(), request);
    }
}

ResponseEntityExceptionHandlerを継承したクラスを作り、ControllerAdviceアノテーションを付ける。 ExceptionHandlerをメソッドに付け、HttpStatusExceptionを引っ掛けてやるようにする。 handleExceptionInternalの引数は以下のようになっている。

  1. 引っ掛けた例外オブジェクト
  2. レスポンスボディ
  3. レスポンスヘッダ
  4. レスポンスステータス
  5. カレントリクエス

まとめ

今回はBadRequestExceptionだけ作ったが、必要に応じて他のレスポンスステータスを持つ例外クラスを作ってthrowするだけで色々な例外に対応できる。 今回はコントローラ共通の例外ハンドラを作ったが、コントローラ特有のハンドラを作ればそちらが優先されるらしいので、 汎用的な例外ハンドラはControllerAdviceで実装し、特殊なレスポンスを返すなどの条件があればコントローラに個別定義すれば良い。

参考リンク

qiita.com

LaravelのHomesteadをvagrant upしようとしたらThe requested address is not valid in its context.吐いて止まった

最近、環境構築で手こずることが多いです…

環境

OS: Windows8.1
Vagrant: 1.9.3

現象

homesteadのboxを無事取り込み、vagrant upしたら以下のようなエラーを吐いて止まりました。

C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `initialize': The requested address is not valid in its context. - connect(2) for "0.0.0.0" port 8000 (Errno::EADDRNOTAVAIL)
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `new'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:21:in `block in is_port_open?'
        from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:88:in `block in timeout'
        from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `block in catch'
        from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `catch'
        from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:32:in `catch'
        from C:/HashiCorp/Vagrant/embedded/lib/ruby/2.2.0/timeout.rb:103:in `timeout'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/is_port_open.rb:19:in `is_port_open?'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:248:in `port_check'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:121:in `[]'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:121:in `block in handle'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:257:in `block in with_forwarded_ports'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:253:in `each'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:253:in `with_forwarded_ports'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:98:in `handle'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:42:in `block in call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/environment.rb:567:in `lock'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_forwarded_port_collisions.rb:41:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/prepare_forwarded_port_collision_params.rb:30:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/env_set.rb:19:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/provision.rb:80:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/clear_forwarded_ports.rb:15:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/set_name.rb:50:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/clean_machine_folder.rb:17:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_accessible.rb:18:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/box_check_outdated.rb:78:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/config_validate.rb:25:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_virtualbox.rb:17:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/match_mac_address.rb:19:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/discard_state.rb:15:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/import.rb:74:in `import'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/import.rb:13:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/prepare_clone_snapshot.rb:17:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/prepare_clone.rb:15:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/customize.rb:40:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_accessible.rb:18:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/config_validate.rb:25:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/handle_box.rb:56:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:95:in `block in finalize_action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builtin/call.rb:53:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/plugins/providers/virtualbox/action/check_virtualbox.rb:17:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/warden.rb:34:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/builder.rb:116:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `block in run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/util/busy.rb:19:in `busy'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/action/runner.rb:66:in `run'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:225:in `action_raw'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:200:in `block in action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/environment.rb:567:in `lock'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:186:in `call'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/machine.rb:186:in `action'
        from C:/HashiCorp/Vagrant/embedded/gems/gems/vagrant-1.9.3/lib/vagrant/batch_action.rb:82:in `block (2 levels) in run'

解決

ググるとStackOverflowにたどり着く。 stackoverflow.com vagrant 1.9.3で発生する問題らしいですね。
Homestead/scripts/homestead.rbをエディタで開き以下のように変更する。

        # 86行目くらい
        # Use Default Port Forwarding Unless Overridden
        unless settings.has_key?("default_ports") && settings["default_ports"] == false
            default_ports.each do |guest, host|
                unless settings["ports"].any? { |mapping| mapping["guest"] == guest }
            config.vm.network "forwarded_port", guest: guest, host: host, auto_correct: true, host_ip: "127.0.0.1"
                end
            end
        end

        # Add Custom Ports From Configuration
        if settings.has_key?("ports")
            settings["ports"].each do |port|
            config.vm.network "forwarded_port", guest: port["guest"], host: port["host"], protocol: port["protocol"], auto_correct: true, host_ip: "127.0.0.1"
            end
        end

VagrantでリモートのboxをaddしようとしたらSSL read: error:00000000:lib(0):func(0):reason(0)で止まる

環境

現象

boxのダウンロード中に以下のようなエラーが出て、ダウンロードが中断される。

An error occurred while downloading the remote file. The error
message, if any, is reproduced below. Please fix this error and try
again.

SSL read: error:00000000:lib(0):func(0):reason(0), errno 50

解決

errnoの部分は自分の環境では50か60だった気がする。 ググると以下のような記事が見つかった。 github.com slick.pl

とりあえずオプションを追加したら無事にダウンロードできました。

vagrant box add --insecure -c laravel/homestead

KotlinとThymeleafの組み合わせで、Thymeleaf側でisHogeフィールドが参照できない。

ThymeleafとKotlinの組み合わせで発生した問題です。 コントローラからビューにisHogeという値を渡した場合に、 ビュー側のThymeleaf内でその値を使用するときisHogeという変数名で参照できないというものです。 これはKotlinのフィールドの概念を理解していればそんなに難しい内容でないのですが、 Kotlinで書いたコードがビルド後にどうなるかを意識していない場合に結構引っかかるのではないかと思います。

KotlinでisHogeというフィールドを書きコンパイルするとHogeというメンバ変数に対し、各アクセサが自動的に生成されるので Thymeleaf側からだとisHogeという変数は存在せずHogeという変数が見えるということですね。

それにしてもキャメルケースで書いた変数がパスカルケースになってしまうのは気持ちが悪いですね。 文章だけでは分かりにくいのでサンプルコードを載せておきます。 モデルは割愛します。

package com.example

import org.springframework.stereotype.Controller
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.servlet.ModelAndView

@Controller
@RequestMapping("/books")
@Suppress("unused")
class BooksController(
    val service: BookService
){
    @GetMapping("/add")
    fun add() = ModelAndView("books/add")
}
package com.example

import org.springframework.stereotype.Service

@Service
class BookService{
    fun getBookList() = arrayListOf<Book>().apply {
        add(Book(1, "初めてのKotlin", 3000, false))
        add(Book(2, "初めてのJava", 2800, true))
        add(Book(3, "初めてのIntellij", 4500, false))
    }
}
package com.example

class Book(
    var id: Long,
    var title: String,
    var price: Long,
    var isRemoved: Boolean = false
)
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8"/>
    <title>Book List</title>
</head>
<body>
    <table>
        <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Price</th>
            <th>IsRemoved</th>
        </tr>
        <tr data-th-each="book : ${bookList}">
            <td data-th-text="${book.id}"></td>
            <td data-th-text="${book.title}"></td>
            <td data-th-text="${book.price}"></td>
            <td data-th-text="${book.Removed}"></td>
            <!--<td data-th-text="${book.isRemoved}"></td>  isRemovedが参照できずエラーになる-->
        </tr>
    </table>
</body>
</html>

Kotlinのリフレクションを使ってプロパティ情報を取得する

やってることは簡単な内容なのですが、日本語の情報があまりなかったのでメモ程度に記録しようかと。
あるクラスのKClassを取得しプロパティ名と中身を取り出してみるというものです。

import kotlin.reflect.full.memberProperties

fun main(args: Array<String>) {
    val myBook = Book(
        name = "Hello Kotlin",
        page = 120,
        isbn = "978-4865940398"
    )

    myBook::class.memberProperties.forEach {
        println("${it.name}: ${it.call(myBook)}")
    }
}

class Book(
    val name: String,
    val page: Long,
    val isbn: String
)

実行結果は以下の通り。

isbn: 978-4865940398
name: Hello Kotlin
page: 120

htpasswdでパスワードの設定を行う際に8文字までしか認識してくれない

設定したパスワードよりも短い文字列で認証が通る

 SquidでプロキシのBasic認証のパスワード設定をする際に、設定したパスワードより短い文字列でも認証が通ってしまう現象に見舞われた。自分で構築した環境ではないので、仮想マシンで再現環境を構築して色々試してみた。すると9文字以降は認証時に入力の有無に関わらず、認証が通ってしまうことに気がついた。

htpasswd -cb ./.htpasswd hoge password12345

上記のようにパスワードを設定した場合には、「password」以降の「12345」は認証時に入力してもしなくても認証が通ってしまう。

ドキュメントを読む

 そこでHtpasswdのドキュメント(http://httpd.apache.org/docs/2.2/programs/htpasswd.html)を読んでみると、dオプションのところに以下のような文章が書いてあった。

This is not supported by the httpd server on Windows and Netware and TPF. This algorithm limits the password length to 8 characters.

そもそも最大8文字までしか対応していなかった。どうやらcrypt関数というものを使う際に、8文字までしか対応していないらしい。警告くらい出してくれると嬉しいな…

HAXMのインストールに失敗しx86のAndroidエミュが使えなくなった(解決済み)

環境

今回のお話の環境は富士通のSH90、Windows10でのお話。

突然の死

x86Androidエミュレータを起動しようとしたらエラーが表示され起動できなくなった。
StackOverflowで検索をかけるとIntel VTが無効になっているのではという回答があり、 BIOSを確認したところ有効になっていた。

HAXMの再インストール

更に調べるとSDKマネージャからではなくて、HAXMのインストーラをダウンロードし直接インストールしろという回答が…
SDKマネージャからHAXMをアンインストールし、Winodwsのコントロールパネルからもアンイストールの処理を行った。(記憶が正しければ、SDKマネージャから削除してもプログラム一覧には表示されてる。)
そしてIntelのサイトからHAXMのインストーラをダウンロードした。

software.intel.com

電子署名の沼

インストーラを起動しインストールを行っていたところエラーが表示された。
そして以下の様な表示が…
ググっても良い答えが見つからず、丸一日が潰れた。 f:id:inaba629:20160904170403p:plain

セキュアブートの無効化

何をしてもダメで、残すはBIOSの設定のみが残っていた。
Intel VTの設定とかオンオフしてみたりしたがダメ…
あとはセキュアブートの設定くらいしか残っていなかったので、無効化してみた。

生還

再びHAXMのインストーラを走らせたら、なんとエラーが表示されないではないか。 試しにIDEを起動し、x86エミュレータを作成し起動した…
動いた
IntelさんかMSさん、どうにかしてください。