ryhmrt’s blog

意識低い系プログラマの雑記

MacBook Pro Retina 13" の最大解像度

MacBook ProRetina 13" モデルは OSX 標準の設定画面からだと最大 1680x1050 までしか解像度を上げられませんが、実はもっと大きな解像度をサポートしています。

AppStore にいくつか有料のアプリがありますが、フリーのコマンドラインソフトがあるのでオススメ。
https://github.com/jhford/screenresolution
Xcodeコマンドラインツールが入っていれば、 make を叩くだけで実行ファイルが出来るはず。

フォークしたこのブランチには、最大解像度に一発で変更する max オプションが追加されています。
https://github.com/ryhmrt/screenresolution/tree/max_option

尚、この魔改造を施す間に Retina 13" の最大解像が 2560x1600 であることを知りました。 対応解像度一覧にバグがあって、 2560x1600 が表示されていなかったのです。
このバグ修正は本家に Pull Request を投げておいたので、マージされると嬉しいな。

Atom の Add Selection Above/Below のキーボードショートカット

Atom の Add Selection Above/Below のキーボードショートカットはデフォルトで Shift  +Control + Up/Down なんだけど、OSXYosemite になってから Control + Up/Down をデフォルトでミッションコントロールに割り当てているため、どちらかを設定変更しなければうまくいかない。

自分は OSX の Preference を開いて、ミッションコントロールのキーバインドを削除しました。 

Googleカレンダーで書込権限のあるカレンダーをその他のカレンダーに追加する

自分は会社でも個人でもメールとカレンダーはGoogleにべったりです。

会社でGoogleカレンダーを使い始めてから一つずっと気になっていたのが、他人のカレンダーがマイカレンダーに追加されて、Macのカレンダーアプリで予定承認の通知が表示されてうざいということでした。

Googleカレンダーの仕様として、書込権限のあるカレンダーを追加するとマイカレンダーのところに追加されます。

そして、マイカレンダーにあるカレンダーはMacのカレンダーアプリでは問答無用で表示されます。

今回、Googleカレンダーにて以下の儀式を行うことで、書込権限のあるカレンダーをその他のカレンダーに追加できることを発見しました。
  1. Googleカレンダーで対象のカレンダーを追加する(マイカレンダーに追加される)
  2. MacのカレンダーアプリのDelegateで対象のカレンダーを選択する
  3. Googleカレンダーで対象のカレンダーを削除する
  4. Macのカレンダーアプリでカレンダーを更新する
すると、Googleカレンダーで対象のカレンダーがその他のカレンダーに追加されます。あら不思議。

以上の手順は2015/1/29時点のGoogleカレンダーMacにて動作が確認されております。
 

Spring Roo の database コマンドでスキーマが見つからないと言われる

database.propertiesに

database.url = jdbc:postgresql://localhost:5432/hoge

と設定されているとき

roo> database reverse engineer --schema hoge --package ~.entity

とか

roo> database introspect --schema hoge

とかコマンドを打っても

Schema(s) 'hoge' do not exist or does not have any tables. Note that the schema names of some databases are case-sensitive

などと言われてしまう。

--schema オプションには public と指定するらしい。これは分かりづらい...

Spring MVC で独自バリデーション

組込のバリデーション

Spring MVC では JSR-303 のバリデーションが使える。

@NotNull
@Size(min=1, max=50)
@Pattern(regexp = "[a-zA-Z-_.]+@[a-zA-Z-\\.]+")

とかのバリデーションをBeanのフィールドに宣言して、アクションのメソッド

public String save(Model model, @Valid @ModelAttribute("form") HogeForm form, BindingResult bindingResult) {
    if (bindingResult.hasErrors()) {
        model.addAttribute("form", form);
        return "hoge/edit";
    }

こんな感じにエラー分岐すれば、form:errorsタグでエラーが表示できる。

<form:errors path="email" cssClass="text-error" />

独自のバリデーション

標準のバリデーションで足りない分をどうすすか。

最初は org.springframework.validation.Validator を実装して、アクションの頭で

ValidationUtils.invokeValidator(hogeValidator, form, bindingResult);

とかやってみたけど、これはきれいじゃない。

調べたら、独自のアノテーションを定義できるらしい。

以下のように ConstraintValidator と、ペアになるアノテーションをセットで定義してやればOK

/**
 * JSR-303 Validation Annotation for List empty check
 */
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=ListNotEmpty.ListNotEmptyValidator.class)
public @interface ListNotEmpty {
    public String message() default "{ListNotEmpty}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    /**
     * Validator
     */
    public static class ListNotEmptyValidator implements ConstraintValidator<ListNotEmpty, List<?>>  {

        @Override
        public void initialize(ListNotEmpty annotation) {
        }

        @Override
        public boolean isValid(List<?> target, ConstraintValidatorContext context) {
            if (target == null || target.size() == 0) {
                return false;
            }
            return true;
        }

    }
}

複数フィールドをチェックする必要がある場合はクラスをバリデーションの対象にすればOK

/**
 * JSR-303 Validation Annotation for Password confirmation.
 * Target bean should implement PasswordConfirmation.PasswordConfirmable.
 * (No need to put PasswordConfirmation annotation)
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=PasswordConfirmation.PasswordConfirmationValidator.class)
public @interface PasswordConfirmation {
    public String message() default "{PasswordConfirmation}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

    /**
     * Interface for password confirmation
     */
    @PasswordConfirmation
    public interface PasswordConfirmable {
        public String getPassword();
        public String getPasswordConfirmation();
    }

    /**
     * Validator
     */
    public class PasswordConfirmationValidator implements ConstraintValidator<PasswordConfirmation, PasswordConfirmable> {

        @Override
        public void initialize(PasswordConfirmation annotation) {
        }

        @Override
        public boolean isValid(PasswordConfirmable bean, ConstraintValidatorContext context) {
            if (bean.getPassword() != null && !bean.getPassword().equals(bean.getPasswordConfirmation())) {
                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                    .addNode("passwordConfirmation")
                    .addConstraintViolation();
                return false;
            }
            return true;
        }

    }
}

AJDT configurator for m2e

Aspect J のプロジェクトをEclipseで扱ったら、Plugin execution not covered by lifecycle configurationとか表示されてコンパイルが止まってしまう問題に遭遇。

stackoverflowとかを徘徊して、SPRINGSOURCE BLOGにあるUPGRADING MAVEN INTEGRATION FOR SPRINGSOURCE TOOL SUITE 2.8.0という記事のUh oh…my projects no longer buildという項目がそれっぽいかなぁと思ったのだが、記事の手順通りにconnectorを探してみたものの、それらしきものが全く見当たらない。

その後質問をいろいろ変えてGoogle先生に問い合わせたところ、aspectj-users mailing list の過去ログからAJDT configurator for m2eというスレッドを見つけ、Eclipse の Install New Software に http://dist.springsource.org/release/AJDT/configurator/ を追加して、AJDT configurator for m2e を入れたところ、ようやく解決した。