2016年10月1日土曜日

[Jackson]Enumの値を読み書きする

Jacksonを使って、json内の値をEnumとして読み書きする方法。

Jacksoのバージョン

compile 'com.fasterxml.jackson.core:jackson-databind:2.8.3'

jsonにマッピングするオブジェクトの定義

json→Enumの変換は@JsonCreatorアノテーションを設定したstaticメソッドで行う。
Enum→jsonの変換は@JsonValueアノテーションを設定したメソッドで行う。
public class SampleBean {

    private Enum value;

    public Enum getValue() {
        return value;
    }

    public void setValue(final Enum value) {
        this.value = value;
    }
}

enum Enum {
    A(1),
    B(2),
    C(3),;

    private int value;

    Enum(final int value) {
        this.value = value;
    }

    @JsonValue
    public int toValue() {
        return value;
    }

    @JsonCreator
    public static Enum fromValue(int value) {
        return Arrays.stream(values())
              .filter(v -> v.value == value)
              .findFirst()
              .orElseThrow(() -> new IllegalArgumentException(String.valueOf(value)));
    }
}

jsonの内容

{"value": 2}

json→Beanに実装

final ObjectMapper objectMapper = new ObjectMapper();

final SampleBean bean = objectMapper.readValue("{\"value\": 2}", SampleBean.class);
System.out.println("bean.getValue() = " + bean.getValue());

final String json = objectMapper.writeValueAsString(bean);
System.out.println("json = " + json);

結果

bean.getValue() = B
json = {"value":2}

2016年8月25日木曜日

[Jackson]デシリアライズ時に発生するUnrecognizedPropertyExceptionを抑止する

Jacksonを使って、jsonをBeanにデシリアライズするときに、jsonには存在しているけどBeanに存在しない属性があるとUnrecognizedPropertyExceptionが発生する。
これを、Jacksonに対する設定で、一括で無効にする方法。

Jacksonのバージョン
compile 'com.fasterxml.jackson.core:jackson-databind:2.8.1'

入力のjson
{"name": "あいうえお"}

beanの定義
class Sample {

    private String name;

    private int age;

    @Override
    public String toString() {
        return "Sample{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Jacksonを使ったデシリアライズ処理
jsonにだけ存在する属性があった場合に例外を発生させる設定を無効化する設定を行う。
無効化する設定はDeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES。
final ObjectMapper mapper = new ObjectMapper();

// beanに存在しない属性があっても無視する(例外を発生させない)
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);

final String content = "{\"name\": \"あいうえお\"}";
final Sample sample = mapper.readValue(content, Sample.class);

System.out.println("sample = " + sample);


結果
sample = Sample{name='null', age=0}

2016年7月20日水曜日

[JMockit]バージョン1.23からはNonStrictExpectationsではなくExpectationsを使う

バージョン1.23で非推奨になって、1.25で完全に削除されたようです。

JMockitの新しいバージョンを使う場合は、NonStrictExpectationsを使うのではなく、Expectationsを使います。


例

モックが返す値を設定する際にminTimesを使って、最小の呼び出し回数に0を設定する。
これで、NonStrictExpectationsと同じような動きを実現できるようになる。
        new Expectations() {{
            mockList.add("hoge");
            minTimes = 0;

            mockList.get(0);
            result = "1"; minTimes = 0;
        }};

2016年7月19日火曜日

[JMockit]VerificationsでMatcherを使って、モックに渡された値をアサートする

JMockitでモックオブジェクトのメソッドに渡されたオブジェクトをアサートしたい場合は、withArgThatを使う。

使い方

検証したいメソッドの呼び出しに対して、withArgThatを使用して、検証用のwithArgThatを指定する。

この例の場合は、単純にmockList.add("hoge")で置き換えできるが・・・
引数をキャプチャするwithCaptureを使ってたけど、こっちのほうが便利。

    @Mocked
    private List mockList;

    @Test
    public void sample() throws Exception {
        mockList.add("hoge");

        new Verifications() {{
            mockList.add(withArgThat(is("hoge")));
        }};
    }

2016年5月28日土曜日

[Oracle]アプリケーションコンテキストの作成

アプリケーションコンテキストにアプリ固有の情報を格納する方法


ネームスペースの作成

create contextを使用して、ネームスペースを作成する。
ネームスペース作成時には、名前と値を管理するためのPL/SQL(プロシージャやパッケージ)をセットで指定する。

※CREATE ANY CONTEXTシステム権限が必要

sample_ctxネームスペースを作成して、名前と値を管理するためのPL/SQLにはsample_ctx_managerを指定。
この時点では、PL/SQLが存在していなくてもOK
create context sample_ctx using sample_ctx_manager;

名前と値のペアを管理するためのPL/SQLの作成

PL/SQLの名前は、create contextを作成した時の名前にする。
dbms_session.set_contextを使ってアプリケーションコンテキストに名前と値のペアを登録できる。
本来は、ログインしたユーザの情報から、DB検索して値の設定をしたりするらしい。
CREATE OR REPLACE PROCEDURE sample_ctx_mgr
IS
BEGIN
  dbms_session.set_context(
      namespace => 'sample_ctx',
      attribute => 'sample_key',
      value     => 'sample_value'
  );
END;

PL/SQLの実行

うえで作成したPL/SQL実行することでアプリケーションコンテキストに値を設定できる。

セキュリティを高めるためには、安易にexecute権限を付与するとかじゃなくってログイントリガーとかで実現するのがよいらしい。

設定された値の確認

session_contextを参照することで値を確認できる。
07:23:44 SQL> r
  1* select * from session_context

NAMESPACE         ATTRIBUTE        VALUE
------------------------------ ------------------------------ ------------------------------
SAMPLE_CTX         SAMPLE_KEY        sample_value

sys_contextを使うと値を抜き出すことができる。
select sys_context('sample_ctx', 'sample_key') from dual;


アプリケーションコンテキストをうまく使うとセキュリティを高めることができるらしい。
(まだ詳しくわかってない。)

2016年5月27日金曜日

[Oracle]DBMS_SPACE.SPACE_USAGEを使ってブロックの使用量を調べる

このPL/SQLを実行すると結果が出力される。

PL/SQL

set serveroutput on
declare
  segment_owner varchar2(30) := '&owner';
  segment_name  varchar2(30) := '&table';
  segment_type  varchar2(30) := 'TABLE';
  unformatted_blocks   number;
  unformatted_bytes    number;
  fs1_blocks           number;
  fs1_bytes            number;
  fs2_blocks           number;
  fs2_bytes            number;
  fs3_blocks           number;
  fs3_bytes            number;
  fs4_blocks           number;
  fs4_bytes            number;
  full_blocks          number;
  full_bytes           number;
begin                  
  DBMS_SPACE.SPACE_USAGE(
    segment_owner,
    segment_name,
    segment_type,
    unformatted_blocks,
    unformatted_bytes,
    fs1_blocks,
    fs1_bytes,
    fs2_blocks,
    fs2_bytes,
    fs3_blocks,
    fs3_bytes,
    fs4_blocks,
    fs4_bytes,
    full_blocks,
    full_bytes
  );

  dbms_output.put_line('空き領域が0-25%   Blocks = ' || rpad(fs1_blocks, 15)  || ' Bytes = ' || fs1_bytes);
  dbms_output.put_line('空き領域が25-50%  Blocks = ' || rpad(fs2_blocks, 15)  || ' Bytes = ' || fs2_bytes);
  dbms_output.put_line('空き領域が50-75%  Blocks = ' || rpad(fs3_blocks, 15)  || ' Bytes = ' || fs3_bytes);
  dbms_output.put_line('空き領域が75-100% Blocks = ' || rpad(fs4_blocks, 15)  || ' Bytes = ' || fs4_bytes);
  dbms_output.put_line('一杯になったもの  Blocks = ' || rpad(full_blocks, 15)  || ' Bytes = ' || full_bytes);

end;

出力例

空き領域が0-25%   Blocks = 0               Bytes = 0
空き領域が25-50%  Blocks = 0               Bytes = 0
空き領域が50-75%  Blocks = 0               Bytes = 0
空き領域が75-100% Blocks = 22              Bytes = 180224
一杯になったもの  Blocks = 286             Bytes = 2342912

deleteでデータを削除した後の出力例

一杯になったBlockが空きが75から100のところに移動している。
deleteなので使用済みのblockはそのままのこっている
空き領域が0-25%   Blocks = 0               Bytes = 0
空き領域が25-50%  Blocks = 0               Bytes = 0
空き領域が50-75%  Blocks = 0               Bytes = 0
空き領域が75-100% Blocks = 308             Bytes = 2523136
一杯になったもの  Blocks = 0               Bytes = 0

truncate後の出力例

HWMがリセットされている。
空き領域が0-25%   Blocks = 0               Bytes = 0
空き領域が25-50%  Blocks = 0               Bytes = 0
空き領域が50-75%  Blocks = 0               Bytes = 0
空き領域が75-100% Blocks = 0               Bytes = 0
一杯になったもの  Blocks = 0               Bytes = 0

2016年5月21日土曜日

[Oracle]セキュアアプリケーションロール

セキュアアプリケーションロールを使うと、ロール作成時に指定したPL/SQLからのみそのロールを有効化することができるようになる。
また、ロールを有効化する直前に、PL/SQLのコード内でセキュリティ要件を満たしているかのチェックができるメリットがある。

セキュアアプリケーションロールの作成

セキュアアプリケーションロールは、ロール作成時にidentified using を付加することで作成できる。
なお、このタイミングでidentified usingに指定したpl/sqlが存在していなくても問題ない。

SQL> create role sample_role identified using hoge.activation_sample_role;

Role created.

ロールを有効化するためのpl/sqlを作成する

このpl/sqlでは、要件を満たす場合にのみdbms_sessionパッケージを使って、先ほど作ったロールを有効化します。
サンプルとして、接続プログラムを表す値が「SQL*Plus」の場合にロールを有効化します。
create or REPLACE PROCEDURE activation_sample_role
authid CURRENT_USER
AS
BEGIN
  if (SYS_CONTEXT('USERENV','MODULE') = 'SQL*Plus') THEN
    DBMS_SESSION.set_role('sample_role');
  END IF;
END;

ロールの付与

hrスキーマのjobsテーブルへの参照権限をロールに付与し、ロールをhogeユーザに付与する。
SQL> grant select on hr.jobs to sample_role;

Grant succeeded.

SQL> grant sample_role to hoge;

Grant succeeded.

ログインしてロールの確認をする


SQL> sho user
USER is "HOGE"

-- ログイン直後のロールの確認
-- sample_roleは付与されていない
SQL> select * from session_roles;

ROLE
--------------------------------------------------------------------------------
RESOURCE

-- ロールに与えているオブジェクト権限で参照できるテーブルへアクセスしてみるがエラーとなる。
SQL> select* from hr.jobs;
select* from hr.jobs
                *
ERROR at line 1:
ORA-00942: table or view does not exist

-- ロール有効化のPL/SQLを実行
SQL> execute activation_sample_role;

PL/SQL procedure successfully completed.

-- ロールの確認
-- 有効になっていることがわかる
SQL> select * from session_roles;

ROLE
--------------------------------------------------------------------------------
SAMPLE_ROLE

-- ロールに値ている権限で参照できるテーブルも見れるようになる。
SQL> select* from hr.jobs;

JOB_ID    JOB_TITLE          MIN_SALARY MAX_SALARY
---------- ----------------------------------- ---------- ----------
AD_PRES    President        20080      40000