2016-04-18 68 views
1

Mailgun serviceを使用してメールを送信するのはlittle libraryです。Java genericsを使用してコンバータSPIを設計する適切な方法

ライブラリは、現在、ある種のHTML DSLを使用してリッチメールの本文コンテンツを生成する非常に簡単なメカニズムを備えています。私はあなたが望むようにフォーマットされたオブジェクトを渡すことができるように、コンバータのSPIを提供したいところの次のバージョンで作業しています。数字、日付、通貨価値などについて考えています。

ジェネリックス、ワイルドカードの種類、境界などに苦しんでいます。私の問題はジェネリックスの使用法の詳細よりも一般的な設計だと思います。だから私の質問は、どのように私は私のSPIを設計する必要がありますJavaジェネリックの制限を与えます。私は、コンバータインタフェースを定義開始している

は:

public interface ContentConverter<T> { 
    String toString(T value); 
} 

ライブラリ全体で使用される構成オブジェクトがあります。そこで、ユーザは、この登録メソッドを使用して、そのインタフェースのインスタンスを登録することになっています。

public <T> Configuration registerConverter(ContentConverter<? super T> converter, 
              Class<T> classToConvert) 
{ 
    converters.add(new Converter<>(classToConvert, converter)); 
    return this; 
} 

Converterクラスは、コンバータとそれのクラスをencapsuleするための内部クラスです。

private final static class Converter<T> { 
    private Class<T> classOfConverter; 
    private ContentConverter<? super T> contentConverter; 

    Converter(Class<T> classOfConverter, 
       ContentConverter<? super T> contentConverter) 
    { 
     this.classOfConverter = classOfConverter; 
     this.contentConverter = contentConverter; 
    } 
} 

Configurationはコンバータのリストを保持します。

private List<Converter<?>> converters = ... 

最後に、この設定ではオンデマンド変換が提供されます。

@SuppressWarnings("unchecked") 
public <T> ContentConverter<T> converter(Class<T> classToConvert) { 
    for (Converter<?> converter : converters) 
     if (classToConvert.isAssignableFrom(converter.classOfConverter)) 
      return (ContentConverter<T>) converter.contentConverter; 
    return (ContentConverter<T>) defaultConverter; 
} 

デフォルトコンバータは、単にObject.toString()を呼び出しています。

private final static ContentConverter<Object> defaultConverter = 
    new ContentConverter<Object>() { 
     @Override 
     public String toString(Object value) { 
      return value.toString(); 
     } 
    }; 

ユーザーが本文メッセージを作成しているとき、これらの2つの方法のいずれかを呼び出して、構成済みコンバータを使用してオブジェクトを追加できます。

public Builder text(Object value) { 
    ContentConverter<?> converter = configuration.converter(value.getClass()); 
    return text(value, converter); 
} 

public <T> Builder text(T value, ContentConverter<T> converter) { 
    return text(converter.toString(value)); 
} 

public Builder text(String s) { 
    [...] // this is where the content is really appendend 
    return this; 
} 

しかし、これは機能しません。最初のメソッドはコンパイルされません。私はさまざまな組み合わせを試しましたが、問題はより深く、タイプの消去については何かと思います。

答えて

0

最初のtextメソッドの値パラメータを一般的にします。 (あなたはまだ、クラスオブジェクトのキャストを必要とする):

public <T> Builder text(T value) { 
    ContentConverter<T> converter = configuration.converter((Class<T>)value.getClass()); 
    return text(value, converter); 
} 
+0

値のキャストも必要であるためコンパイルされません – Jorge

+0

@Jorge値がT – wero

+0

です。パラメータタイプも変更されていません。 – Jorge

0

あなたも価値のために、正しい鋳物をやっていることを確認してください:「あなたの最初の

public <T> Builder text(Object value) { 
    Configuration configuration = new Configuration(); 
    ContentConverter<T> converter = configuration.converter((Class<T>)value.getClass()); 
    return text((T)value, converter); 
} 

と同様Tを定義しますテキストメソッド

とにかく、両方のtextメソッドがお互いを呼び出しているため出力が得られないため、コードの結果はjava.lang.StackOverflowErrorになることに注意してください。

+0

この例では私が質問に編集しなかったtext(String)オーバーロードメソッドがあります。それは、SOを防止する。 – sargue

関連する問題