克服J2SE 1.3-1.4 的不兼容性

發表于:2007-06-22來源:作者:點擊數: 標簽:
概要 實現Java 眾多API中的一個是一件困難的工作。你必須經常實現許多相互依賴的接口。對新特征的 需求 促進了最新Java API的創建,投資商們必須不斷的更新他們的實現以跟上時代的需要。 當復雜性和持續修改可以理解甚至被看好時, API 版本的不 兼容性 迫使

   
  概要
  
  實現Java 眾多API中的一個是一件困難的工作。你必須經常實現許多相互依賴的接口。對新特征的需求促進了最新Java API的創建,投資商們必須不斷的更新他們的實現以跟上時代的需要。

當復雜性和持續修改可以理解甚至被看好時, API 版本的不兼容性迫使你為更新的版本保留獨立的代碼庫,從而N次方增加你的受挫等級。本文演示了如何克服接口版本的不兼容性,制作可為多個API版本編譯的代碼庫的進程。
  
  Java 已經添加了無數個API,像Java 數據庫連接(JDBC),到它的標準庫系列上。這可以幫助更廣泛的用戶使用API,因為可選軟件包不必捆綁到配置上。對于編寫這些流行的API的工作組來說,使用的越多他們的付出就越有價值。但是,當更新的Java版本運載最新的API,而最新的API依賴的類和方法是以前的Java版本所不能實現的時候,這些工作組希望他們的API仍然是可選的(與包括在Java的標準庫系列內相反)。這樣你忽然必須要保留實現的兩個版本——一個編譯老的API,另一個編譯新的API。這就是發生在Java2平臺標準版(J2SE)1.4中的JDBC API身上的事情。因為修改了JDBC API, java.sql.Connection 的一個實現不能在J2SE 1.3 和 1.4版本下編譯。
  
  你可能發現你自己也處于與我一樣的困境中:我需要實現JDBC 接口如 java.sql.Connection,但是我的代碼需要在J2SE 1.3 和1.4下編譯。我不想為J2SE 1.3 和1.4保留不同的源文件,所以我尋找更好的解決方法。
  
  不幸的是,當你需要Java編譯器來完成編譯時著名的WORA (一次編寫,各處運行)不包括WOCA (一次編寫,各處編譯)。幸運的是,使用Reflection API對代碼做一些修改并且使用Ant 對編譯做一些修改可以幫你走出困境。我能有一組.java 源文件和Ant來幫助我在J2SE 1.3 和 1.4兩者之上編譯代碼。Ant允許我運行時修改.java文件,                               正確修改以便與編譯時使用的Java版本兼容。但是在我闡述整個解決方案之前,我必須得說明整個問題。
  
  窮人的連接池
  
  兩年前,我的公司需要一個JDBC連接池但是又買不起。那個時候,我們找不到好的免費的備選的東西,所以我們編寫了一個內部的連接池。為了更好的追溯連接在整個我們的應用程序上是如何使用的,我們創建了com.icentris.sql.ConnectionWrapper,它實現java.sql.Connection和一些其他的可實現其他java.sql接口的包裝者類。 包裝者類只追蹤我們應用程序內的數據庫的使用并且傳遞方法調用到真正的JDBC資源處。
  
  當 J2SE 1.4 出來的時候,我們自然想要將一些我們的客戶端程序移到它上面,這樣他們就能從J2SE 1.4的許多改進中獲益。但是,當然,我們仍然需要支持J2SE 1.3,因為那些客戶端看不出有什么理由需要升級。我們氣憤的是, ConnectionWrapper和我們其他的JDBC包裝者類不修改就不能在J2SE 1.4上編譯。為了保持文章的簡潔,我使用ConnectionWrapper來演示我應用到所有不能同時在J2SE 1.3和 1.4下編譯的類的技巧。 為了遵循最新的JDBC API,我不得不添加幾個方法到ConnectionWrapper上,這造成了兩個大問題:
  
  1.因為我的包裝者類需要通過方法調用,我不得不調用J2SE 1.3 sql 類中沒有的方法。
  
  2.因為一些新方法依賴于新的類,我不得不依賴于J2SE 1.3 中沒有的類。
  
  Reflection 來拯救
  
  一些代碼樣品最適合解釋第一個問題。因為我的ConnectionWrapper包裹了java.sql.Connection,所有我的樣品依賴于構造器中的realConnection實際變量 (粗體) 組:
  
  private java.sql.Connection realConnection = null;
   
   public ConnectionWrapper(java.sql.Connection connection) {
    realConnection = connection;
   }
  
  為了看清楚我在沒有不兼容問題的情況下做過什么,我們看看setHoldability(int) (到J2SE 1.4中的java.sql.Connection 的新方法):
  
  public void setHoldability(int holdability) throws SQLException {
    realConnection.setHoldability( holdability );
   }
  
  不幸的是,該代碼在J2SE 1.3下不能編譯因為 java.sql.Connection 沒有我在J2SE 1.3才能調用的setHoldability()方法。但是要在J2SE 1.4下編譯,我必須有一個setHoldability()方法可正確的實現該API. 要解決這個catch-22,我假設我的setHoldability() 方法只能在J2SE 1.4下編譯,所以我可以使用Reflection API來調用該方法:
  
  public void setHoldability(int holdability) throws SQLException {
    Class[] argTypes = new Class[] { Integer.TYPE };
    Object[] args = new Object[] {new Integer(holdability)};
    callJava14Method("setHoldability", realConnection, argTypes, args);
   }
  
   public static Object callJava14Method(String methodName, Object instance,
   Class[] argTypes, Object[] args)
    throws SQLException
   {
    try {
     Method method = instance.getClass().getMethod(methodName, argTypes);
     return method.invoke(instance, args );
    } catch (NoSuchMethodException e) {
     e.printStackTrace();
     throw new SQLException("Error Invoking method (" + methodName + "): "
     + e);
    } catch (IllegalAclearcase/" target="_blank" >ccessException e) {
     e.printStackTrace();
     throw new SQLException("Error Invoking method (" + methodName + "): "
     + e);
    } catch (InvocationTargetException e) {
     e.printStackTrace();
     throw new SQLException("Error Invoking method (" + methodName + "): "
     + e);
    }
   }
  
  現在我有了setHoldability()方法,所以我可以在 J2SE 1.4下編譯。我不直接調用我的java.sql.Connection 上以前不存在的方法,所以我能在J2SE 1.3下編譯。我的 callJava14Method()方法使用 Reflection API調用該方法,然后包裹任何錯誤在SQLException里面,因為SQLException就是我給出的異常的全部。我將該策略用于所有新的J2SE 1.4方法,調用包裹了的方法,然后在 1.3下編譯?,F在我只需要解決第二個問題并且找出一條方法來依賴J2SE 1.3中不存在的類。
  
  Ant就是答案
  
  在J2SE 1.4中,java.sql.Connection依賴于新類java.sql.Savepoint。因為這個新類設置在 java.sql軟件包內,你不可能將它添加到J2SE 1.3上。Java不允許添加任何第三組織的東西到java.* 或者 javax.*軟件包中的核心類系列上。所以這也是對我的挑戰:使用新的java.sql.Savepoint類來編寫我的代碼這樣它就可以在J2SE 1.4下運行, 然后確保代碼可在J2SE 1.3下編譯,實際上,這個類在J2SE 1.3中不存在。簡單,對吧?說“YES”的人都品行良好。好,至少,它簡單得現在我已經找到答案了。
  
  首先,我將下列條件輸入包括進來:
  
  // Comment_next_line_to_compile_with_Java_1.3
   import java.sql.Savepoint;
  
  然后為 Ant找到一條方法:當在J2SE 1.3下編譯時可注釋該輸入。 簡化之后, Ant 腳本核心部分為:
  
  <replace>
    <replacetoken>Comment_next_line_for_Java_1.3
  </replacetoken>
    <replacevalue>Comment_next_line_for_Java_1.3
  //</replacevalue>
   </replace>
  
  該 Ant 標記有幾個選項——在下面的我的完整范例中你會看到更多——但是最重要的部分就是我搜索 然后用取代它?!?
  
  ” 是用于"newline"的XML 實體。當在J2SE 1.4下編譯時,Ant對源文件不做任何修改;并且在 J2SE 1.3下,重要語句被注釋:
  
  // Comment_next_line_to_compile_with_Java_1.3
   //import java.sql.Savepoint;
  
  但是在必須依賴Savepoint 的類的體中仍有代碼:
  
  public Savepoint setSavepoint(String name) throws SQLException { . . .
  
  再次,我只能期望可在J2SE 1.4下使用這些新方法,這樣他們不必在J2SE 1.3下運行; 他們只需要編譯。我發現:如果我的軟件包中有一個Savepoint 類,我的代碼不需要輸入語句就可以編譯。但是當輸入語句沒有注釋的話(在J2SE 1.4編輯下),我的Savepoint 類會被忽略因為存在更特殊的輸入。所以我創建了我自己的啞元類com.icentris.sql.Savepoint,它(java文章排斥它)可能是最短的有效類 :
  
  package com.icentris.sql;
  
   /** Dummy class to allow ConnectionWrapper to implement java.sql.Connection
    * and still compile under J2SE 1.3 and J2SE 1.4. When compiled
    * under J2SE 1.3, this class compiles as a placeholder instead of the
    * missing java.sql.Savepoint (not in J2SE 1.3). When compiled
    * under J2SE 1.4, this class is ignored and ConnectionWrapper uses the
    * java.sql.Savepoint that is new in J2SE 1.4.
    */
   public class Savepoint {}
  
  在J2SE 1.4下,我現在可以正確的輸入java.sql.Savepoint。在J2SE 1.3下, Ant 注釋輸入行,這樣我的代碼中引用的 Savepoint正好在同一個軟件包處于

原文轉自:http://www.anti-gravitydesign.com

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97