Hectorを使ってみる (3) - Object Mapperの続き -

2012-09-23T00:00:00+00:00 Cassandra Java

さらにちょっと進めてみた。やってみる項目として、継承・AnonymousPropertyHandling(ドキュメントではAnonymousPropertyAddHandler)・Listなデータを突っ込んでみる

BaseTable.java

package sample;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.DiscriminatorColumn;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.Table;

import me.prettyprint.cassandra.serializers.StringSerializer;
import me.prettyprint.hom.annotations.AnonymousPropertyHandling;
import me.prettyprint.hom.annotations.Id;

@Entity
@Table(name = "Sample")
@Inheritance
@DiscriminatorColumn(name = "class")
@AnonymousPropertyHandling(
    type = String.class,
    serializer = StringSerializer.class,
    adder = "addAnonymousProperty",
    getter = "getAnonymousProperties"
)
public abstract class BaseTable {

    @Id
    private String key;

    private Map<String, String> anonymousProperties = new HashMap<String, String>();

    public void setKey(String key) {
        this.key = key;
    }

    public String getKey() {
        return key;
    }

    public void addAnonymousProperty(String name, String value) {
        anonymousProperties.put(name,  value);
    }

    public Collection<Map.Entry<String, String>> getAnonymousProperties() {
        return anonymousProperties.entrySet();
    }
}

例えば、毎回テーブルマッピングを行う度にIdアノテーションなの定義するのめんどくさい。なのでこれを外部クラスで提供して継承することで実装をしない方向で

Inheritanceアノテーションとabstract classに関しては省略。でDiscriminatorColumnアノテーションによって、クラスを識別するにあたって必要な情報を格納するカラムを指定する模様。で値になるのはDiscriminatorValueアノテーションになる

んでAnonymousPropertyHandlingアノテーションによって、Columnアノテーションで指定してない等のプロパティもCassandraに突っ込みたい場合にadderに対応するメソッドを介してデータをつっこみ、getterに対応するメソッドが返すCollectionによって返されたデータがCassandraに突っ込まれる模様

Sample.java

package sample;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

import me.prettyprint.hom.annotations.Column;

@Entity
@DiscriminatorValue("sample")
public class Sample extends BaseTable {

    @Column(name = "name")
    private String name;

    @Column(name = "colors", converter = Color.ColorConverter.class)
    private List<Color> colors = new ArrayList<Color>();

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setColors(List<Color> colors) {
        this.colors = colors;
    }

    public List<Color> getColors() {
        return colors;
    }

    public void addColor(Color color) {
        colors.add(color);
    }
}

前回の記事で違うのは、BaseTableを継承する・(set/get)Colorでは無く、(get/set)ColorsでList<Color>を使う点。もちろん前回で書いたColor.javaももろもろ修正する

Color.java

package sample;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import me.prettyprint.hom.PropertyMappingDefinition;
import me.prettyprint.hom.converters.Converter;

public class Color {

    private String color;

    public Color(String color) {
        this.color = color;
    }

    public String value() {
        return color;
    }

    @Override
    public String toString() {
        return this.value();
    }

    public static class ColorConverter implements Converter<List<Color>> {
        @Override
        public List<Color> convertCassTypeToObjType(PropertyMappingDefinition def, byte[] value) {
            String[] colorNames = StringUtils.split(new String(value), ",");
            List<Color> colors = new ArrayList<Color>(colorNames.length);

            for (String colorName : colorNames) {
                colors.add(new Color(colorName));
            }

            return colors;
        }

        @Override
        public byte[] convertObjTypeToCassType(List<Color> colors) {
            return StringUtils.join(colors, ",").getBytes();
        }
    }
}

HectorClient.java

import sample.Color;
import sample.Sample;
import me.prettyprint.hector.api.Cluster;
import me.prettyprint.hector.api.Keyspace;
import me.prettyprint.hector.api.factory.HFactory;
import me.prettyprint.hom.EntityManagerImpl;

public class HectorClient {

    private static long time;

    public static void main(String[] args) {
        Cluster cluster = HFactory.getOrCreateCluster("Test Cluster", "127.0.0.1");
        Keyspace keyspace = HFactory.createKeyspace("sample", cluster);

        EntityManagerImpl em = new EntityManagerImpl(keyspace, "sample");

        putSample(em);

        Sample sample = em.find(Sample.class, String.valueOf(time));

        System.out.println(sample.getName()); // "hoge"が出力

        for (Color color : sample.getColors()) {
            System.out.println(color); // "red" "blue" が一行づつ表示
        }

        System.out.println(sample.getAnonymousProperties()); //
"[test=hoge fuga foobar]" と表示される

        cluster.getConnectionManager().shutdown();
    }

    public static void putSample(EntityManagerImpl em) {
        time = System.currentTimeMillis();

        Sample sample = new Sample();
        sample.setKey(String.valueOf(time));
        sample.setName("hoge");
        sample.addColor(new Color("red"));
        sample.addColor(new Color("blue"));
        sample.addAnonymousProperty("test", "hoge fuga foobar");

        em.persist(sample);
    }
}

これは前回とほとんど変わらない。ただputする際にsetColorからaddColorに変わったのと、addAnonymousPropertyでカラム指定無しなデータを突っ込むところだけは異なる。で実行後にCassandra側のデータを確認すると

RowKey: 1348330541878
=> (column=class, value=sample, timestamp=1348330541907000)
=> (column=colors, value=red,blue, timestamp=1348330541900000)
=> (column=name, value=hoge, timestamp=1348330541906000)
=> (column=test, value=hoge fuga foobar, timestamp=1348330541907001)

Hectorを使ってみる (4) - 単体テスト - Hectorを使ってみる (2) - Object Mapper -