Javaでのジェネリック型とEnumの関連付け

Associating a generic type with Enum in Java


質問 written by Ben March @2013-10-14 22:42:32Z

: 6 : 3 : 3

ユーザー設定用のストアを作成していますが、ユーザーが値を設定できる設定の数は決まっています。 設定(設定)の名前はEnumとして保存されます:

public enum UserSettingName {

    FOO,
    BAR,
    ETC

}

私ができるようにしたいのは、サービスがユーザーの値を正しいJava型で保存できるように、値型を名前で保存することです。 たとえば、FOOはLongで、BARはStringです。 これまでは、すべての値をStringとして保存してから、値を適切なJava型に手動でキャストしていました。 これは、サービス内にtry / catchを1つだけ持つ方が理にかなっている場合に、どこでもtry / catchブロックにつながります。 私は列挙型がジェネリック型を持つことができないことを理解しているので、私は遊んでいます:

public enum UserSettingName {

    FOO(Long.class),
    BAR(String.class),
    ETC(Baz.class)

    private Class type;

    private UserSettingName(Class type) {
        this.type = type;
    }

    public Class getType() {
        return this.type;
    }
}

正しい型の値を返し設定するpublic T getSettingValue() public void setSettingValue(T value)メソッドとpublic void setSettingValue(T value)メソッドを持つ一般的なUserSettingオブジェクトがあります。 私の問題は、次のようなことができないため、設定を作成または取得するときにそのジェネリック型Tを指定しようとすることから生じます。

new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)

これが正確に明確でない場合は申し訳ありませんが、理解されていない場合は明確にすることができます。

ありがとう!

更新

設定の名前と値の両方は、Spring MVC REST呼び出しから取得されます。

public ResponseEntity<String> save(@PathVariable Long userId, @PathVariable UserSettingName settingName, @RequestBody String settingValue)

そこで、Springが着信データを自動的にキャストするため、Enumを使用しました。

コメント 1

enumを使用することはどれほど重要ですか?代わりにstatic finalフィールドを使用できる場合、かなり簡単な答えがあります。

written by StriplingWarrior @2013-10-14 22:07:14Z

コメント 2

@StriplingWarriorはそれほど重要ではありませんが、Spring MVCが自動的にEnumにキャストするため、コードが削減されます。私の質問にコードを追加します

written by ベン @2013-10-14 22:41:11Z

回答 1 written by davnicwil @2013-10-14 22:12:46Z
3

まず、一歩下がって達成しようとしていることを考え、標準パターンまたは言語構造を使用して達成する必要があります。

ここで何をしようとしているのかは完全には明らかではありませんが、あなたのアプローチからは、Javaではるかに簡単な方法で行うことができる何かを再発明しているように見えます。 たとえば、オブジェクトのランタイムクラスを本当に知り、操作する必要がある場合は、リフレクションAPIの使用を検討してください。

より実用的なレベルでは、ここでやろうとしていることはジェネリックでは不可能です。 ジェネリックはコンパイル時の言語機能です。これらは、Objectからすべてを明示的にキャストすることを避け、コンパイル時に型チェックを行うのに役立ちます。 この方法でジェネリックを単純に使用することはできません。つまり、実行時にのみ知られる値UserSettingName.Foo.getType()としてTを設定します。

コメント 1

私はこれに完全に同意し、さらに、列挙型は通常OPで使用されている方法で使用されるべきではないことを付け加えます。基本的に、列挙型はユーザー定義の抽象(コーディングの意味ではありません)型のグループであり、異なるシナリオを区別するために使用する必要があります。たとえば、自分の人生をプログラムする場合、平日MONDAYからSUNDAYを含む列挙型を使用できます。これを使用して、希望するだけ眠れるかどうかを判断できます。さらに良い例は、enumを使用して、単純な自家製(UDP)メッセージパーサーのメッセージタイプを指定することです。

written by イズマキ @2013-10-14 22:22:35Z

回答 2 written by Anton Bessonov @2013-10-14 22:32:00Z
2

nettyでどのように行われたか見てみましょう:

http://netty.io/wiki/new-and-noteworthy.html#type-safe-channeloption

彼らは型付き定数を使用してそれを行いました:

http://grepcode.com/file/repo1.maven.org/maven2/io.netty/netty-all/4.0.0.Beta1/io/netty/channel/ChannelOption.java#ChannelOption

編集:

public interface ChannelConfig {
   ...
   <T> boolean setOption(ChannelOption<T> option, T value);
   ...
}

public class ChannelOption<T> ...
    public static final ChannelOption<Integer> SO_TIMEOUT =
        new ChannelOption<Integer>("SO_TIMEOUT");
    ...
}

EDIT2:次のように変換できます:

EDIT2: you can transform it like:

コメント 1

リンクが質問にどのように答えているかわかりません。説明してもらえますか?

written by トム @2013-10-14 22:05:20Z

コメント 2

@tom:列挙型の代わりに静的な最終フィールドを使用できる場合、各値には、彼が提供したリンクのChannelOptionクラスで表示されるパターンに従って、一般に宣言された型を関連付けることができます。

written by StriplingWarrior @2013-10-14 22:09:39Z

コメント 3

この回答に関連するコードサンプルを追加できますか?、ほんの数個のリンクです

written by 現状では @2013-10-14 22:12:23Z

コメント 4

これはうまくいくと思うので、試してみましょう。

written by ベン @2013-10-14 22:27:25Z

コメント 5

私の唯一の問題は、実行時までタイプがわからないことです。2回目の編集では、文字列に基づいて型を解釈し、UserSettingNameを検索する必要があります。データはREST呼び出しから取得されます: public ResponseEntity<String> save(@PathVariable Long userId, @PathVariable UserSettingName settingName, @RequestBody String settingValue)これはSpringで機能します。これには生の文字列を使用する必要があります。

written by ベン @2013-10-14 22:38:03Z

回答 3 written by aglassman @2013-10-14 22:29:16Z
0

ここでは列挙型は答えではありません。 どこでもコードを繰り返すことに気付いた場合は、ユーティリティクラスを作成して、そこにすべてのtry / catchロジックをカプセル化することができます。 これにより、現在のコードに大きな影響を与えることなく、コードの冗長性が削減されます。

public class Util
{
    public static MyObject getObjectFromString(String s)
    {
        try
        {
            return (MyObject)s;
        }
        catch(Exception e)
        {
            return null;
        }
    }
}

次に、次のように使用します。

Then use as follows: