2010-12-27 57 views
3

Javaライブラリのインターフェイスを実装するクラスを作成しようとしています。特定のインタフェースが質問に関連してはいけませんが、ResultSetは具体的である必要があります。 (私はいくつかの追加機能を提供する通常のResultSetの上にレイヤーを置く必要がありますが、私は "通常の"関数を通過させたいと思います。そして、私は通常のResultSetまたは私の "強化された" ResultSet)。複数のバージョン間でインターフェイスを実装しています

私の問題は:クラスがJava 5とJava 6の両方で正常にコンパイルされるようにこれを行う方法はありますか?

Java 6のResultSetインターフェイスには、Java 5で定義されていないオブジェクトを返す関数が多数あります。これらの関数をインクルードすると、未定義の型を参照しているため、Java 5ではクラスがコンパイルされません。しかし、もし私がこれらの関数を含んでいなければ、インタフェースを完全に実装していないので、Java 6で私のクラスはコンパイルされません。私はキャッチ22の何かにこだわっているようだ。私は実際にこれらの関数のどれも必要としません - 実際に私の実装は単にそれらのすべてのための "実装されていない"例外をスローします。

プログラマーの中にはJava 5を実行しているものもあれば、Java 6を実行しているものもあります。私たちの生産環境はJava 5です。私たちはより完全な世界ではすべて同じバージョンを実行していると思います。しかし、この場合問題を解決するために私の環境を変更することができたとしても、確かにこの問題はオープンソースプロジェクトで発生します。 Java 5で動作するように自分のコードを変更した場合、遅かれ早かれJava 6にアップグレードするとクラスが壊れてしまい、かなり迷惑に見えます。

更新

まあ、与えられた回答をいただきありがとうございます。むしろ、この注釈を追加するか、ここに「W」という文字を入力すれば、それはすべて魔法のように機能します。そのような運はないと思います。

すべての回答は(このアップデートの時点で)とにかく良い点を示していますので、私はそれらのすべてをアップしてしまいました。私は自分のフラストレーションを最もよく表しているものに「ベストアンサー」の賞を与えました。 :-)

私の本当の解決策は、ResultSetを実装するアイデアを放棄し、代わりにResultSetの関数を含む新しいインターフェイスを作成して、動作させる必要があると思います。私はこれを感情的には満足していないが、代わりのものよりも良いと思われる。

答えて

2

私はプロキシの提案が最良の答えだと思いますが、私は2つの配慮追加してみましょう:インターフェースにメソッドを追加することで、パブリックAPIを変更するには、

まず、中に存在しなかったクラスに依存する方法以前のバージョンは、一般的には忌み嫌われています(自分自身のように、そのインターフェースを実装する開発者は必然的にトラブルにつながる)。この忌み嫌いはまれであり、2番目の考慮事項によって弱められます。

JDBC APIはもちろん公開APIです。しかし、あまり知られていない。私は通常、そのインターフェイスはJDBCドライバプロバイダによってのみ実装されることを意味します。この場合、異なるJDBCバージョン(see for eg)の実装が異なることは許容されます。私が目指しているのは、非常に特殊な(低レベルの)状況を除いて、ResultSetを実装/ラップするクラスを実装することを妨げることです。一般に、結果セットをbussinessレイヤーに渡すのは悪い習慣です。典型的な場合、JDBCドライバはResultSetをインスタンス化し、DAOメソッドはそれを使用しますが、それを返すことはありません。

2

あなたは、Proxyクラスを使用してJDKプロキシとしてサービスを実装する必要があると思います。

これは1.3以降であり、すべてのバージョンで動作します。

構文は次のとおりです。

ResultSet rs = Proxy.newProxyInstance(
        ResultSet.class.getClassloader(), 
        new Class[]{ResultSet.class}, 
        new ResultSetInvocationHandler() 
); 

そしてResultSetInvocationHandlerは、カスタム・ロジックを持ついくつかのメソッドをインターセプトし、他人を通過InvocationHandlerの実装になります。

古代はtutorial about the proxy mechanismです。

+0

これは静的な型の安全性を破壊し、大量の定型文を書くことを伴います。エラーが発生しやすく、効率が悪くなります。しかし、それは間違いなく動作します! –

+0

@Tom Anderson *これは静的型の安全性を破壊します*私は知っています。しかし、コンパイル時の安全性を確保するためには、CGLIBなどを使用する必要があります。 –

2

ああ、偉大なJDBCの後方互換性の崩壊。あなたは、これのためにサンの指示で2つのパイントを断言する権利があります。

まったく同じ実装クラスを5と6に使用する方法はないと思います。あなたは、しかし、のような何かができる:

abstract class JaysBaseSuperResultSet /* does not implement ResultSet */ { 
    // all needed methods for java 5 
} 

class JaysSuperResultSetForJava6 extends JaysBaseSuperResultSet implements ResultSet { 
    // all additional java 6 methods 
} 

class JaysSuperResultSetForJava5 extends JaysBaseSuperResultSetForJava5 implements ResultSet { 
    // class body can be empty; compile this only with java 5 
} 

あなたは少し奇妙なビルドプロセスを持っている必要があります:私は、最も簡単なものは6コンパイラでJaysSuperResultSetForJava5が、すべてをコンパイルすることであると思うが、-target 5で、その後、コンパイルしますそのクラスだけで5つのコンパイラ、または6つのコンパイラではなく、5つのライブラリに配線されています(これは実行可能であり、より簡単かもしれません)。

次に、現在のバージョンを検出し、適切な具象クラスのインスタンスを作成するファクトリクラスが必要になります。

これで、すべてを1つのJARにパッケージ化できます。

これはうまくいくようですか?

EDIT:これは4つではなく3つのクラスで実現できます。

1

ResultSetを実装するクラスを作成するのではなく、ResultSetを新しいクラスにラップします。

1つの警告:

public class MyWrapper<T extends ResultSet> { 
    T myResultSet; 

    public MyWrapper(T myResultSet) { 
     this.myResultSet = myResultSet; 
    } 

    public T getResultSet() { 
     return myResultSet; 
    } 

    public void setResultSet(T myResultSet) { 
     this.myResultSet = myResultSet; 
    } 

} 

(私はこれをテストしていませんが、注意してください):それはResultSetの正しいサブインターフェイスを返すようにするためにジェネリック医薬品の使用を検討してください。

注:すでに順番に、独自のサブインターフェイスを持っている独自のサブインターフェイスRowSetを有するResultSetによるはすぐResultSetは、表面上は良いアイデアのように聞こえるかもしれ実装していますが、という新しいクラスを作成する
は狂気に退化JdbcRowSetこれには独自のサブインターフェースがあります。このツリーの最後には、データベース用のJDBCドライバーの一部である実際のオブジェクトがあります。

+0

ここでキャッチするのは、ResultSetをパラメータとして受け取る関数を含むライブラリAがあることです。私はライブラリAを使用するプロジェクトBに取り組んでいます。私は原則としてライブラリBの関数をオーバーロードして、プロジェクトBの新しいクラスのインスタンスを取得することができました。しかし、その後私はBをAに依存関係を構築しますが、これは悪い考えです。それ以外の場合は、ライブラリAのインタフェースを定義します。このインタフェースは、実際に使用する関数だけのResultSetの小さなサブセットです。しかし、私は別の型を取っている別の関数でResultSetを取るバージョンのすべてのコードを複製する必要があります。 – Jay

+0

私は実際に結果セットの "下"に気にしません。私は独自のJDBCインタフェースを作成していません。私は必要ないくつかの追加機能、エラー処理などを提供するクラスを作成していますが、呼び出し側には基本的なnextメソッドとgetterメソッドへのアクセスを依頼しています。だから私は下のレイヤーを追加していない、私は上記のレイヤーを追加しています。その下にあるものは、私が知っているか気にするべきではありません。 – Jay

+0

@jay Spring JDBCを使用する必要があります。私はあなたが車輪を再発明していると思います。 –

関連する問題